Search Unity

Executing FixedUpdate logic during PhysicsScene.Simulate()

Discussion in 'Physics' started by Schazzwozzer, Aug 23, 2019.

  1. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    I am setting up a physics trajectory line, Angry Birds-style, but in 3D. In order to produce the trajectory line, I make an un-rendered copy of the scene (as described in this thread). Then I launch the copy of the player projectile and use PhysicsScene.Simulate to simulate out X seconds, making note of the projectile's positions, and finally using those positions to draw the prediction line.

    That all works great! However, my project uses FixedUpdate to alter physics behavior. For instance, one component conditionally adjusts the drag of its Rigidbody. Physics simulation does not invoke FixedUpdate, and so my simulation diverges from what will actually happen in the game.

    My question then: can physics simulation be made to call FixedUpdate? If not (I assume not), does anybody have experience with this issue? Hopefully an elegant solution? Any solutions I can imagine are pretty ugly.
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    I don't think it's possible PhysicsScene.Simulate to call FixedUpdate. As solution, you may put the code intended to be run in FixedUpdate in a separate method. Then you would invoke this method from FixedUpdate, and also after each call to PhysicsScene.Simulate in the un-rendered copy of the scene.
     
  3. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    Thanks for the response. Yeah, I figured this is basically what I'll need to do. Unfortunately, it gets messy quickly, for a couple reasons:
    • There's no built-in way to tell which components implement FixedUpdate (outside of using a bunch of reflection).
    • When Unity invokes FixedUpdate, it does so according to the Script Execution Order. How do I maintain that order?
    I think what I'll need to do is have all relevant components implement a C# Interface that lets FakeFixedUpdate be called. These components will have to register with some kind of PhysicsSimulationManager, and in order to maintain execution order, it'll need to be done in one of Unity's 'event functions', probably OnEnable. Then, between every simulation step, PhysicsSceneManager calls FakeFixedUpdate on its list of registered components.

    What happens if I need to add new items to my physics simulation scene? Uh... let's just hope I don't need to do that, I guess!

    Incidentally, does anyone know if Script Execution Order can be accessed during play? As far as I can tell, it's exclusive to the UnityEditor assembly. If I could access it, then PhysicsSceneManager's list could just be sorted accordingly.
     
  4. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    Is it really so complicated? I'm genuinely curious, as I haven't had experienced it myself. As for what I can tell, it could be like this:

    Create a new class "MyCustomBehaviour" that inherits from MonoBehaviour:
    • Implement a virtual method "CustomFixedUpdate" (empty by default).
    • Implement the FixedUpdate method which just calls to CustomFixedUpdate.
    All your scrips that need to be played in a separate physics scene would inherit from MyCustomBehaviour instead of MonoBehaviour, and override the CustomFixedUpdate method.

    When the scene is played normally you don't have to do anything special. Each script gets its fixed update logic called.

    When playing the copy of the scene:
    1. Get all the components MyCustomBehaviour in the copied scene and put it in a list.
    2. Call Physics.Simulate
    3. For each component in the MyCustomBehaviour list, call its CustomFixedUpdate method.
    4. Go to 2.
    Maybe there are other considerations I can't foresee, but that's the approach I would attempt.
     
  5. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    Your approach doesn't maintain script execution order, right? They're just called in whatever order they're added to the list, which is presumably according to scene hierarchy.

    To give an example of why that could be a problem: if I have a component that checks if the Rigidbody is touching the ground, and then a 2nd component that increases drag when the Rigidbody is grounded, that 2nd component MUST execute second, or else it'll diverge from gameplay.

    Does it need to be complicated? Well, that's why I posted in the first place. I was hoping someone else had already figured this stuff out, perhaps with an approach that hadn't occurred to me.

    I'll be sure to post my solution when I do decide to sit down and implement it. I'd think this might be a somewhat common problem, so perhaps it'll help people in the future. I'm kinda just dragging my feet about it right now.
     
  6. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    No, my approach doesn't maintain script execution order.

    However, note that your approach preserves the gameplay if those scripts are always executed in the same order, but the order itself is not important. In your example, if that second component executes first, then it will apply the drag just one physical frame after the contact with ground has been detected. The gameplay will be exactly the same as long as this specific execution order is preserved.

    Personally, I'd design the gameplay in a way that doesn't depend on the script execution order. Following your example, I'd just put everything that affects the rigidbody together in the same script.
     
  7. Schazzwozzer

    Schazzwozzer

    Joined:
    Jul 27, 2012
    Posts:
    18
    Following up, because I said I would. My solution pretty much looked like what Edy and I laid out in this thread. There were some changes worth mentioning though.

    First, I have a class I'll call PhysicsSceneManager. It's a singleton which creates the parallel physics scene, loading all of the necessary GameObjects into it. At the end of initialization, once the physics scene has been populated, I disable the entire scene hierarchy, and re-enable it.

    All components which need to be simulated inherit from a SimulatablePhysicsBehaviour base class. That class has a SimFixedUpdate() method, an IsSimulation boolean, and a RegisterWithPhysicsScene() method, which adds the component to a List within the PhysicsSceneManager. In OnEnable, if IsSimulation is true, it calls RegisterWithPhysicsScene(). This is why the PhysicsSceneManager switches everything off and back on. It causes every simulated object to call OnEnable, which executes according to Unity's script execution order. The result is that the PhysicsSceneManager is left with a List of all the SimulatablePhysicsBehaviours, ordered by script execution order.

    Finally, in order to run a physics simulation, PhysicsSceneManager calls PhysicsScene.Simulate(), and then runs through its List of Simulatables, calling SimFixedUpdate() for each one.

    If Simulatables must be added after initialization, I suppose perhaps the scene could be switched off-on again. Just have to take care with how references and state are maintained.

    Oh, and since this post is for posterity anyway, I recommend future forum-goers look into DOTS physics, if they're working on this stuff. It's currently in development and I haven't tinkered with it much, but unlike Unity's current PhysX implementation, it will be deterministic.
     
    Edy likes this.
  8. oturaz

    oturaz

    Joined:
    May 6, 2016
    Posts:
    13
    Ah, I have a few questions about your implementation. Maybe it's because I don't have much experience programming or because I'm dumb, but I couldn't understand everything. Could you help me understand, please?

    So my problem is similar in that I am manipulating my rigidbodies with external forces to simulate a car hovering above the ground. I need to be able to use Physics.Simulate because the game is networked in a lockstep system and I need to make rollbacks.

    So my questions are:
    • is the simulated scene always active and you just enable and disable the objects when you need the simulation to occur? Or you remake the scene every time you want a simulation?
    • the scripts in SimFixedUpdate depend on the state of the scene at the specific step of the simulation, so I presume you can't call Simulate with all the steps accumulated, but instead have to make a while with the fixed step in which you simulate physics a little, run all the SimFixedUpdate scripts then move another fixed step and so on until you reach the desired amount of time (in my case the rollback gets back to the present point in time). Is this correct? And if so, won't it cause a lag spike, considering the PC will have to make the calculations it had to make in multiple frames in a single frame?
    • I'm not sure I quite understand SimFixedUpdate (I know, I'm dumb...). Um... I presume that instead of writing (in my case) the car hover code in FixedUpdate, I would inherit SimulatablePhysicsBehaviour and write it in SimFixedUpdate instead? And if I get this right, how do I run the SimFixedUpdate between every Physics.Simulate call? Does the PhysicsSceneManager also inherit SimulatablePhysicsBehaviour? I don't understand how SimFixedUpdate is called to execute everything that is inside it.
    • How do you do the "calling SimFixedUpdate() for each one"? Doesn't calling SimFixedUpdate cause everything inside it to run? I guess this question is tied to my previous question...
    • Are SimFixedUpdate() and RegisterWithPhysicsScene() the only things inside SimulatablePhysicsBehaviour?
    • What is the point of RegisterWithPhysicsScene()? Doesn't disabling and enabling the scene hierarchy rearrange the GameObjects in the desired order for Unity's execution order? And if not, I fail to understand what exactly happens OnEnable and how you achieve rearranging them. Do you take the order from the main scene?
    Lastly, I actually initially started trying to use the DOTS physics, since having deterministic physics is a requirement for a lockstep system, but I can't get it to work for the life of me. And I mean I can't make it work at a basic level of creating a ball that falls on a plane. I followed all the steps from here, but once I press the play button, nothing happens. The ball isn't falling. Do you know if perhaps the current version is broken or something? Have you tried the DOTS physics yourself and made it work at a basic level?
     
  9. oturaz

    oturaz

    Joined:
    May 6, 2016
    Posts:
    13
    I just realized I have another question, but wouldn't calling SimFixedUpdate cause the objects in the main simulation to be affected? (I guess this one might be tied to the 3rd and 4th question though)
     
  10. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Omg... there are a lot of problems with this.

    No fixed update.

    When calling Physics.SomeMethod it calls the original physics scene even if you SetActiveScene to the new simulation scene before calling Simulate.

    PhysicsScene doesn't have methods like SphereCastAll(...), just SphereCast()... Why?

    It's very limited and not really useful for games at all seeing as good game physics usually needs to modify vanilla physics to be fun.


    Edit: oh I see, SphereCast is both SphereCast and SphereCastAll on the physics scene, just with different arguments.
     
    Last edited: Sep 29, 2020