Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Sync Physics Body with Animated GameObject by using Velocity

Discussion in 'Physics for ECS' started by Armitage1982, Apr 8, 2022.

  1. Armitage1982

    Armitage1982

    Joined:
    Jul 26, 2012
    Posts:
    38
    If you use Unity Physics / Havok, you may probably need to sync Physics Body to animated GameObject at some point.

    However, Translation & Rotation components, used in physics simulation, won't be updated when using techniques focusing only on the LocalToWorld component.

    That's the case of Unity.Transforms.Hybrid CopyTransformFromGameObjects.

    There are various solutions around this, but I needed one that takes Velocity in accounts for fluid Kinematic Physics Body movement and an Animator component for the animation (which could also work with anything else like a Dotween tweener).

    I had a little trouble finding it, so here is the recipe (for say, a monolithic moving platform):

    1. Bring your Model to the scene
    2. Add your Animator with the desired Animator Controller on that GameObject and switch Update Mode to "Animate Physics"
    3. Add a CopyTransformFromGameObjects component and put your GameObject in an empty parent (so that you will be able to easily change its origin by moving the empty parent)
    4. Add a Physics Body and set Motion Type to "Kinematic"
    5. Add a Physics Shape with the desired Shape Type and parameters
    6. Add a Convert To Entity components and set the Conversion Mode to "Convert And Inject Game Object"

    Now create a new Dots System (Assets > Create > ECS > System) with this code :
    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Mathematics;
    3. using Unity.Physics;
    4. using Unity.Transforms;
    5.  
    6. [UpdateInGroup(typeof(TransformSystemGroup))]
    7. [UpdateBefore(typeof(EndFrameTRSToLocalToWorldSystem))]
    8. public class SyncVelocityFromGameObjectTransform : SystemBase
    9. {
    10.     protected override void OnUpdate()
    11.     {
    12.         var tickSpeed = 1f / Time.DeltaTime;
    13.  
    14.         Entities.ForEach((ref PhysicsVelocity velocity, in CopyTransformFromGameObject copy, in LocalToWorld localToWorld,
    15.                     in Translation transform, in Rotation rotation, in PhysicsMass mass) => {
    16.  
    17.             var targetTransform = new RigidTransform(localToWorld.Rotation, localToWorld.Position);
    18.             velocity = PhysicsVelocity.CalculateVelocityToTarget(mass, transform, rotation, targetTransform, tickSpeed);
    19.  
    20.         }).Schedule();
    21.     }
    22. }
    Done!
    Your Physics Body should now sync with your Animated GameObject.

    This topic has few purposes:
    1. Helping you not to waste too much time on unnecessarily complex systems or legacy solutions.
    2. To confirm if it is a correct solution and check if there are not more suitable one (as I am not yet very comfortable with DOTS).
    3. Maybe improving this solution, such as taking scale into consideration (but that was not my goal here).
    This solution works with Entities 0.17.0-preview.42, Unity Physics 0.6.0-preview.3, Havok 0.6.0-preview.3, Hybrid Renderer 0.11.0-preview.44 since the Animator Package is on hold and as I'm stuck with Unity 2021.2 and can't use Entities 0.50.0 yet (I don't know if this is still a problem with this new version).


    I hope this helps someone
     
    bb8_1 and DevViktoria like this.