Duration-Based Part Awakening

As a Roblox developer, it is currently too hard to predict and control when parts will wake up from a sleeping state for physics interactions to occur.

Right now, developers have to reverse engineer the waking parts logic, using hacky, unreliable workarounds, or create their own physics engine (at lower framerate and higher latency than Roblox’s) - i.e. they have to reinvent the wheel.


Case Study - Ten Pin Bowling

Ten Pin Bowling game

In my bowling game, the pins like to fall asleep. This makes sense, is expected, and desired to some extent - they see no velocity for a while, nothing to collide with them, they sleep. But they should wake up fully in time for the bowling ball (arriving anywhere from 40 to 80 studs per second) to collide with them and cause the right stuff to happen.

However, occasionally the pins don’t wake up in time, and either act as if they are anchored, deflecting the ball despite the ball being far denser, or allowing the ball to pass right through them with the pin just shaking slightly.

Here is a clip of someone streaming the game which shows the issue well:
Twitch

In this particular clip, the client-side prediction begins to deflect the pins in the directions you’d expect, but when they catch up with what the server believe happened, the pins are shown to have barely moved at all. The sounds played are played from the server and indicate that multiple pins received touch events from the ball.

Our bowling happens server-side, and therefore shouldn’t be affected by client latency or any of that stuff. The actual collisions can appear slightly delayed, which is fine and acceptable so long as they are consistent and correct.

And one where the pins may as well be anchored:


Feature Request

A possible solution to the problem is to have the ability to wake up the pins for a given duration of time, either via an API through PhysicsService or another service, or a method directly on BaseParts themselves (or any other suitable solution).

This has more uses beyond just ten pin bowling. Any situation where a projectile is about to hit a group of objects of similar size that are currently stationary can result in this behaviour. Situations like shooting a stack of cans with a bullet like a carnival game, or crashing a high speed vehicle into a bunch of obstacles.

If we, as the developers, know exactly when something will happen, and know exactly what should be ready to simulate that, then we should be able to control the physics engine to ensure that event has priority and is simulated correctly.


Current Workaround

After many attempts doing many silly things to the ball, like adding a longer profile that follows behind in its wake, and trying to do mini explosions and all sorts, ultimately I settled for what seems to be the consensus workaround: soft pushing the body into the ground. (Thanks to @boatbomber for this one, including this lovely wrapper to neaten it up).

I don’t need this to be happening all the time, so I’m hooking to .Stepped when I want this to happen, and disconnecting afterwards - this is exactly where the feature request comes in, as I’d perform a method on the parts or call an API and tell it to wake the 10 pins for the next 3 seconds.


Summary

Ultimately, the cleanest, most useful and seemingly obvious solution is to provide a method of waking parts for a length of time, allowing greater control over the physics engine and avoiding the need for workarounds or custom physics systems.

Fast projectiles are an edge case, but I believe the edge case is large enough to warrant the feature of duration-based part awakening.

59 Likes

I remember having to deal with this in a car chassis project I put on halt. It even kept happening after the recent engine changes. Just one part sleeping for a frame would launch the entire rig higher than Elon Musk’s space Tesla.

Adding to the injury, physics run 4 times each frame and Lua scripts cannot run between those physics frames. Which means any band aid solution would only affect the car, while any part touching it would still end up at escape velocity.

5 Likes

Before we jump into your proposed feature, I’d really like to understand what’s going on with the bug you are experiencing in the bowling game, it’s certainly unexpected.

Have you found a way to reproduce this consistently? Or been able to reproduce it under the other examples you gave (carnival game, speeding car)?

Any file you can send, or more info on how you are handling client/server ownership, would be super helpful in understanding what’s going on.

3 Likes

We’ve not managed to reproduce it consistently, but it does happen occasionally. Network ownership is definitely on the server (we even check it every frame to be sure whilst we were debugging).

It’s quite a complex system at the moment so I’ll send over the whole bowling game minus some API keys to your DMs. Because we can’t reproduce it consistently, I don’t want to take out any of the functionality as I won’t be able to test if that has changed the frequency of it occurring.

4 Likes

We don’t have any client side prediction built into the engine, especially not that should be visible in any rendered frame. There is some limited on-contact local simulation, but that is always overriden by interpolation before any scripts can see the results of that simulation, well before the frame is rendered. There’s no built in system that would get the behavior seen in that Twitch clip.

Do you have custom client-side prediction in your game?

4 Likes

There’s no custom prediction in the game that I’ve programmed. We assumed there’s some client-side prediction on Roblox’s behalf as sometimes a pin will get hit, instantly jump back in time to where it was, then perform the collision again, as if catching up to where the server was.

Everything from the character animation through to the velocity and spin of the ball is 100% on the server, not a single bit of code on the client regarding physics.

If there’s no client-side prediction then I’m not sure why that would happen either, but it happens in a lot of games on Roblox, including car driving games and similar, where something will happen, unhappen, and re-happen in the space of a few frames.

Is it the server physics engine deciding the parts weren’t awake enough to it’s having a redo?

3 Likes

I guess a quick hitch back in time can be a telltale symptom of a network ownership transfer.

If bowling happens on the server, do you call SetNetworkOwner(nil) both on the ball and the pins to force network ownership to the server and prevent any automatic ownership re-assignment?

2 Likes

I do, and we check it every .Stepped, and if the owner isn’t nil, or if somehow ownership auto has become true, it sets it again.

When testing in Studio using Are Owners Shown, it confirms that after the ball leaves the player’s hand it becomes owned by the server and continues to be until it’s destroyed. Likewise the pins are set the moment they are unanchored and checked in the same .Stepped connection.

I’ll happily forward the same place file in DMs to you as I have done to kleptonaut if there’s any additional debug you have access to that could shed any further light.

It’s not been possible to repro in Studio at all so far, but when we get a few players on a few lanes in game it begins to occur.

3 Likes