Search Unity

Balls Not Rolling..Why? Physics Bug?

Discussion in 'Entity Component System' started by ippdev, Feb 16, 2020.

  1. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Edit..Been at this for a solid day. The balls do not roll, they slide. I have tried variants including the CreateBody script from the latest examples. In one tunnel they hit a wall and lose velocity and a bounce off the slightest curve on the next they reflect back to their emitted origin at near zero velocity. I tried in an arena and they act like they hit a wall or bounce and they do not go straight. They follow snake like curves though the arena is flat in this area. The code is below if someone wants to insert it into a script and test. If it works let me know what you did to send the values. In the tunnel it looked like it was hitting a broadphase box.



    Code (CSharp):
    1.  
    2.  public unsafe Entity CreateBody (RenderMesh displayMesh, float3 position, quaternion orientation, BlobAssetReference<Collider> collider,
    3.         float3 linearVelocity, float3 angularVelocity, float mass, bool isDynamic) {
    4.  
    5.         EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    6.         ComponentType[] componentTypes = new ComponentType[isDynamic ? 7 : 4];
    7.  
    8.         componentTypes[0] = typeof (RenderMesh);
    9.         componentTypes[1] = typeof (Translation);
    10.         componentTypes[2] = typeof (Rotation);
    11.         componentTypes[3] = typeof (PhysicsCollider);
    12.         if (isDynamic) {
    13.             componentTypes[4] = typeof (PhysicsVelocity);
    14.             componentTypes[5] = typeof (PhysicsMass);
    15.             componentTypes[6] = typeof (PhysicsDamping);
    16.         }
    17.         Entity entity = entityManager.CreateEntity (componentTypes);
    18.  
    19.         entityManager.SetSharedComponentData (entity, displayMesh);
    20.  
    21.  
    22.         // Check if the Entity has a Translation and Rotation components and execute the appropriate method
    23.         if (entityManager.HasComponent (entity, typeof (Translation))) {
    24.             entityManager.SetComponentData (entity, new Translation { Value = position });
    25.         } else {
    26.             entityManager.AddComponentData (entity, new Translation { Value = position });
    27.         }
    28.         if (entityManager.HasComponent (entity, typeof (Rotation))) {
    29.             entityManager.SetComponentData (entity, new Rotation { Value = orientation });
    30.         } else {
    31.             entityManager.AddComponentData (entity, new Rotation { Value = orientation });
    32.         }
    33.         Collider* colliderPtr = (Collider*)collider.GetUnsafePtr ();
    34.         entityManager.SetComponentData (entity, PhysicsMass.CreateDynamic (colliderPtr->MassProperties, mass));
    35.         // Calculate the angular velocity in local space from rotation and world angular velocity
    36.         float3 angularVelocityLocal = math.mul (math.inverse (colliderPtr->MassProperties.MassDistribution.Transform.rot), angularVelocity);
    37.         entityManager.SetComponentData (entity, new PhysicsVelocity () {
    38.             Linear = linearVelocity,
    39.             Angular = angularVelocityLocal
    40.         });
    41.         entityManager.SetComponentData (entity, new PhysicsDamping () {
    42.             Linear = 0.01f,
    43.             Angular = 0.05f
    44.         });
    45.         entityManager.SetComponentData (entity, new PhysicsCollider { Value = collider });
    46.      
    47.         return entity;
    48.     }
    49.  
     
    Last edited: Feb 17, 2020
  2. LastLabRat

    LastLabRat

    Joined:
    Jun 19, 2019
    Posts:
    3
    I imagine the biggest issue you're encountering is manipulating the physics components dynamically. Rather, I would recommend the following high-level approach if it fits your use-case.

    1) Create the ball 'types' and store them as prefabs, including the components convertToEntity/PhysicsBody/PhysicsShape

    2) Create a Spawner Entity that will be responsible for managing the entity types

    3) Create a Spawner System that will spawn the desired entity type- position it, orient it, etc., as you like

    Note: The code below is to quickly demonstrate the concept using a component system, and should work as is. However, it would be optimal using a job component system instead.

    Hope this helps.

    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Transforms;
    6.  
    7. // Attach Author To Spawner Entity
    8. [RequiresEntityConversion]
    9. public class SphereSpawnerAuthor : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
    10. {
    11.     public GameObject typeOne;
    12.     public GameObject typeTwo;
    13.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    14.     {
    15.         var data = new SphereSpawnerData {
    16.             BallTypeOne = conversionSystem.GetPrimaryEntity(typeOne),
    17.             BallTypeTwo = conversionSystem.GetPrimaryEntity(typeTwo)
    18.         };
    19.         dstManager.AddComponentData(entity, data);
    20.     }
    21.  
    22.     public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    23.     {
    24.         referencedPrefabs.Add(typeOne);
    25.         referencedPrefabs.Add(typeTwo);
    26.     }
    27. }
    28. // Stores the Entity Type Data
    29. public struct SphereSpawnerData : IComponentData
    30. {
    31.     public Entity BallTypeOne;
    32.     public Entity BallTypeTwo;
    33. }
    34.  
    35. // Entity Spawning Controls
    36. public class SphereSpawnerSystem : ComponentSystem
    37. {
    38.     EntityManager em;
    39.     protected override void OnCreate()
    40.     {
    41.         em = World.EntityManager;
    42.     }
    43.     protected override void OnUpdate()
    44.     {
    45.         Entities.ForEach((Entity entity, ref LocalToWorld localToWorld, ref SphereSpawnerData data) =>
    46.         {
    47.             // On LeftClick Event Spawn BallTypeOne
    48.             if (Input.GetMouseButtonDown(0))
    49.             {
    50.                 // Spawn the Entity
    51.                 var spawnedEntity = em.Instantiate(data.BallTypeOne);
    52.                 // Get Positioning and Rotation From Spawned Entity
    53.                 var spawnedEntityTranslation    = em.GetComponentData<Translation>(spawnedEntity);
    54.                 var spawnedEntityRotation       = em.GetComponentData<Rotation>(spawnedEntity);
    55.                 // Set Positioning and Orientation Relative To The Spawner Entity
    56.                 spawnedEntityTranslation.Value  = localToWorld.Position;
    57.                 spawnedEntityRotation.Value     = localToWorld.Rotation;
    58.                 em.SetComponentData(spawnedEntity, spawnedEntityTranslation);
    59.                 em.SetComponentData(spawnedEntity, spawnedEntityRotation);
    60.             }
    61.             // On RightClick Spawn BallTypeTwo
    62.             if (Input.GetMouseButtonDown(1))
    63.             {
    64.                 // Spawn the Entity
    65.                 var spawnedEntity = em.Instantiate(data.BallTypeTwo);
    66.                 // Get Positioning and Rotation From Spawned Entity
    67.                 var spawnedEntityTranslation    = em.GetComponentData<Translation>(spawnedEntity);
    68.                 var spawnedEntityRotation       = em.GetComponentData<Rotation>(spawnedEntity);
    69.                // Set Positioning and Orientation Relative To The Spawner Entity
    70.                 spawnedEntityTranslation.Value  = localToWorld.Position;
    71.                 spawnedEntityRotation.Value     = localToWorld.Rotation;
    72.                 em.SetComponentData(spawnedEntity, spawnedEntityTranslation);
    73.                 em.SetComponentData(spawnedEntity, spawnedEntityRotation);
    74.             }
    75.         });
    76.     }
    77. }
     
  3. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    I tried every possible way to spawn and instantiate and create from code. I could impart an initial torque but I could never see them roll properly, they simply slid. If I just placed the same prefabs with conversion component and let them fall on a slope they would roll..most of the time. I believe it may have something to do with the Inertia Tensor but there is not enough docs and plugging in Unity tech code didn't alleviate the issue.
     
  4. LastLabRat

    LastLabRat

    Joined:
    Jun 19, 2019
    Posts:
    3
    If I'm following correctly, it sounds like the way the force being applied is the issue. Maybe this is of some help, I'm using the ApplyLinearImpulse Component Extension here to apply force.

    Here's the results:


    Here's the code used:
    (Again, it's not optimized in any sense, but it should be easy to follow)

    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Transforms;
    6. using Unity.Physics;
    7. using Unity.Physics.Extensions;
    8.  
    9. [RequiresEntityConversion]
    10. public class SphereSpawnerAuthor : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
    11. {
    12.     public GameObject typeOne;
    13.     public GameObject typeTwo;
    14.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    15.     {
    16.         var data = new SphereSpawnerData {
    17.             BallTypeOne = conversionSystem.GetPrimaryEntity(typeOne),
    18.             BallTypeTwo = conversionSystem.GetPrimaryEntity(typeTwo)
    19.         };
    20.         dstManager.AddComponentData(entity, data);
    21.     }
    22.  
    23.     public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    24.     {
    25.         referencedPrefabs.Add(typeOne);
    26.         referencedPrefabs.Add(typeTwo);
    27.     }
    28. }
    29.  
    30. public struct SphereSpawnerData : IComponentData
    31. {
    32.     public Entity BallTypeOne;
    33.     public Entity BallTypeTwo;
    34. }
    35. public struct SA_ControlTag : IComponentData { }
    36.  
    37. public class SphereSpawnerSystem : ComponentSystem
    38. {
    39.     EntityManager em;
    40.     protected override void OnCreate()
    41.     {
    42.         em = World.EntityManager;
    43.     }
    44.     protected override void OnUpdate()
    45.     {
    46.         Entities.ForEach((Entity entity, ref LocalToWorld localToWorld, ref SphereSpawnerData data) =>
    47.         {
    48.             // On LeftClick Event Spawn BallTypeOne
    49.             if (Input.GetMouseButtonDown(0))
    50.             {
    51.                 // Spawn the Entity
    52.                 var spawnedEntity = em.Instantiate(data.BallTypeOne);
    53.              
    54.                 // Position the Entity
    55.                 var spawnedEntityTranslation = em.GetComponentData<Translation>(spawnedEntity);
    56.                 var spawnedEntityRotation = em.GetComponentData<Rotation>(spawnedEntity);
    57.                 spawnedEntityTranslation.Value = localToWorld.Position;
    58.                 spawnedEntityRotation.Value = localToWorld.Rotation;
    59.                 // Get Positioning and Rotation From Spawned Entity
    60.                 em.SetComponentData(spawnedEntity, spawnedEntityTranslation);
    61.                 em.SetComponentData(spawnedEntity, spawnedEntityRotation);
    62.                 // Activate Subsystem > Spawned Entity Controls
    63.                 em.AddComponent<SA_ControlTag>(spawnedEntity);
    64.             }
    65.  
    66.             // On LeftClick Event Spawn BallTypeTwo
    67.             if (Input.GetMouseButtonDown(1))
    68.             {
    69.                 // Spawn the Entity
    70.                 var spawnedEntity = em.Instantiate(data.BallTypeTwo);
    71.                 // Get Positioning and Rotation From Spawned Entity
    72.                 var spawnedEntityTranslation = em.GetComponentData<Translation>(spawnedEntity);
    73.                 var spawnedEntityRotation = em.GetComponentData<Rotation>(spawnedEntity);
    74.                 spawnedEntityTranslation.Value = localToWorld.Position;
    75.                 spawnedEntityRotation.Value = localToWorld.Rotation;
    76.                 // Set Positioning and Orientation Relative To The Spawner Entity
    77.                 em.SetComponentData(spawnedEntity, spawnedEntityTranslation);
    78.                 em.SetComponentData(spawnedEntity, spawnedEntityRotation);
    79.                 // Activate Subsystem > Spawned Entity Controls
    80.                 em.AddComponent<SA_ControlTag>(spawnedEntity);
    81.             }
    82.  
    83.         });
    84.  
    85.         // Subsystem Controls for Spawned Entity
    86.         Entities.ForEach((Entity entity, ref SA_ControlTag tag, ref PhysicsMass mass, ref PhysicsVelocity velocity) =>
    87.         {
    88.             // Sphere
    89.             var someSpeedFactor = 2f;
    90.             var impusleForward  = mass.InverseMass * Vector3.forward * someSpeedFactor;
    91.             var impusleRight    = mass.InverseMass * Vector3.right * someSpeedFactor;
    92.             var impulseLeft     = mass.InverseMass * Vector3.left * someSpeedFactor;
    93.             var impulseBack     = mass.InverseMass * Vector3.back * someSpeedFactor;
    94.          
    95.             // Sphere Control Inputs
    96.             if (Input.GetKeyDown(KeyCode.RightArrow))
    97.             {
    98.                 ComponentExtensions.ApplyLinearImpulse(ref velocity, mass, impusleRight);
    99.             }
    100.             if (Input.GetKeyDown(KeyCode.LeftArrow))
    101.             {
    102.                 ComponentExtensions.ApplyLinearImpulse(ref velocity, mass, impulseLeft);
    103.             }
    104.             if (Input.GetKeyDown(KeyCode.UpArrow))
    105.             {
    106.                 ComponentExtensions.ApplyLinearImpulse(ref velocity, mass, impusleForward);
    107.             }
    108.             if (Input.GetKeyDown(KeyCode.DownArrow))
    109.             {
    110.                 ComponentExtensions.ApplyLinearImpulse(ref velocity, mass, impulseBack);
    111.             }
    112.         });
    113.     }
    114. }
    115.  
     
  5. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Can you explain why you are adding the impulse to the horizontal orthogonals? Is it simply to push the rigidbodies about or are they involved in unlocking the "roll" of the rb?
     
  6. LastLabRat

    LastLabRat

    Joined:
    Jun 19, 2019
    Posts:
    3
    No problem. The former. Simply a location to push the entities around.

    Once the entity physics settings are applied and it exists in the physics simulation, it can be interacted with- I'm not doing anything to specifically lock or unlock anything further.

    Best of luck.
     
    BeerCanAI likes this.