Search Unity

Question Reaction forces non-deterministic?

Discussion in 'Physics' started by WARdd, Jan 17, 2021.

  1. WARdd

    WARdd

    Joined:
    Aug 10, 2015
    Posts:
    29
    TLDR
    Using some code in FixedUpdate based on Joint2D.ReactionForce causes the physics in my Unity project to behave in a non-deterministic way.


    I'm currently working on a puzzle game that involves letting the player blow up buildings, these buildings consist of rigid body nodes connected by joints represented by members connecting those nodes.

    I've gone trough a lot of effort to make sure the motion of the collapsing building is deterministic, that way a single player solution (i.e. arrangement of bombs) leads to the same outcome. This is important for the puzzle aspect, since otherwise a player might find themselves in a frustrating loop of trying out the same solution tens of times trying to get a lucky outcome.

    Anyway, this all worked fine until I added a mechanism where members can break by themselves when they experience enough force. This system is based on the Joint2D.ReactionForce of that joint, which for some reason is not always the same between different runs.

    The reaction force system is important since I want the members to break smoothly, with the ones under the most stress going first. Simply using the builtin breakforce function causes the joints to all pop at the same time.

    Some details about the system:
    • The timescale is kept on 0 between runs so no fixedupdates occur
    • the breaking mechanic is calculated in the fixedupdates
    • the breaking mechanic uses only deterministic floating point math
    • all rigidbody positions, angles, velocities and script states are fully reset and identical between runs

    ------------------------------------------------------ UPDATE ---------------------------------------------------

    Okay, I managed to make some progress on this issue; I've made it so that whenever a simulation starts, the members are all set to their broken state and immediately back to their whole state. In other words, the offending joints and rigid bodies are being disabled and re-enabled to flush out any lingering state they might have from a previous run.

    This almost fixed the issue, with me getting consistent runs between all levels and everything, EXCEPT the very first time after starting the game. Isn't that absurd? Though at this point I can get it fixed with a very awkward workaround.

    Note that even unloading and reloading the scene with the physics setup doesn't break the determinism, it's just the very first run after enabling the game, in any other scenario it is always consistent.
     
    Last edited: Jan 23, 2021
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    I have no experience with 2D physics, but I think it's worth noting that Unity uses the Box2D engine for 2D physics:


    There are a lot of resources and documentation on this engine. So you may look for similar situations and solutions in the Box2D community, and they might be applicable to your case in Unity as well.
     
    MelvMay likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    As above but to add that we simply pass your call to the following Box2D method: b2Joint::GetReactionForce. The property Joint2D.reactionForce implicitly uses the fixed delta-time whereas the method Joint2D.GetReactionForce allows you to explicitly state it but both call into the Box2D method above with no intervention by Unity therefore it's deterministic.

    All joints return an appropriately scaled impulse which was calculated during the last simulation step.
     
    Edy likes this.