Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Rotation not working

Discussion in 'Entity Component System' started by JamesWjRose, Aug 17, 2023.

  1. JamesWjRose

    JamesWjRose

    Joined:
    Apr 13, 2017
    Posts:
    663
    Hello gang,

    Now I feel especially stupid. This one SHOULD be easy and yet as you see from the various ways I have attempted to rotate an object, it's not rotating.

    The function is running from a System, and yes it runs (note the first line where I set the position and the object moves)

    So wtf am i doing wrong?

    Thanks


    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Mathematics;
    4. using Unity.Transforms;
    5.  
    6.  
    7. [WithAll(typeof(RotateYTag))]
    8. public readonly partial struct RotateYAspect : IAspect
    9. {
    10.     private readonly RefRW<LocalTransform> localTransform;
    11.     private readonly RefRO<RotationSpeed> rotationSpeed;
    12.  
    13.     public void Rotate(float deltaTime)
    14.     {
    15.         //localTransform.ValueRW.Position.y += 0.25f;  //this works, which means this function is running
    16.  
    17.  
    18.  
    19.         //localTransform.ValueRW.RotateY(deltaTime);
    20.  
    21.         //transform.Rotate(Vector3.up * (spinSpeed * Time.deltaTime));
    22.         //localTransform.ValueRW.Rotate(Vector3.up * (rotationSpeed.ValueRO.value * deltaTime));
    23.  
    24.  
    25.         localTransform.ValueRW.RotateY(rotationSpeed.ValueRO.value * deltaTime);
    26.         //localTransform.ValueRW = localTransform.ValueRO.RotateY(500 * deltaTime);
    27.         //localTransform.ValueRW.Rotation = localTransform.ValueRO.RotateY(500 * deltaTime);
    28.  
    29.  
    30.         //rotation.Value = rotation.Value * Quaternion.Euler(deltaTime, 0, 0);
    31.         //localTransform.ValueRW.Rotation.value = localTransform.ValueRO.RotateY(500 * deltaTime);
    32.  
    33.  
    34.         //transform.Rotate(Vector3.up * (spinSpeed * Time.deltaTime));
    35.  
    36.  
    37.         //localTransform.ValueRW.RotateY(deltaTime * 50);
    38.         //localTransform.ValueRO.Rotate(0, 3 * deltaTime, 0, Space.World);
    39.         //localTransform.ValueRO.Rotate(0, 3 * deltaTime, 0, 0);
    40.  
    41.         //quaternion yRotation = quaternion.RotateY(180f * Mathf.Rad2Deg * deltaTime);
    42.         //localTransform.ValueRW.Rotation = math.mul(localTransform.ValueRW.Rotation, yRotation);
    43.     }
    44. }
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Remark: I haven't used Aspects yet, so this might not be the case.
    But it sure looks like the same what would happen if you try write back via GetSingletonRW without refs.

    ValueRW returns a ref. RotateY returns a [new] struct. Which gets assigned nowhere. Because its copied, not referenced.

    Edit: First example I've posted is incorrect, sorry about that, tripped myself by the same case.
    Generating a new struct on the ref will... generate a new struct, but will not set it to the same memory location.

    Code (CSharp):
    1. // Try this instead
    2. LocalTransform localTrm = localTransform.ValueRO;
    3. localTrm.RotateY(...);
    4. localTransform.ValueRW = localTrm;
    Writing position in the example directly would work, because you're writing back to the same struct at the same pointer location. A good habit to take is to break down long lines into single ops. This helps to pindown this kind of issues more easily.
     
    Last edited: Aug 17, 2023
  3. JamesWjRose

    JamesWjRose

    Joined:
    Apr 13, 2017
    Posts:
    663
    I wish you were right. But the ref is not needed in aspects, I tried your answer in several ways, but still no luck. Thank you for the detailed answer, even though.

    Have a great day
     
    xVergilx likes this.
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Have you tried something like this (overriding whole struct)?

    (From examples):
    Code (CSharp):
    1. [BurstCompile]
    2.         public void OnUpdate(ref SystemState state)
    3.         {
    4.             float deltaTime = SystemAPI.Time.DeltaTime;
    5.  
    6.             foreach (var (transform, speed) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotationSpeed>>())
    7.                 transform.ValueRW = transform.ValueRO.RotateY(speed.ValueRO.RadiansPerSecond * deltaTime);
    8.         }
    Maybe Burst eats up the ref somehow, or something else is missing.
     
    JamesWjRose likes this.
  5. JamesWjRose

    JamesWjRose

    Joined:
    Apr 13, 2017
    Posts:
    663
    This is without using Aspects.... which is indeed a thought. Thanks, I'll need to take a look into when to use them or not.
     
  6. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Just in case, there's a different approach with properties, that may look cleaner:
    Code (CSharp):
    1. struct CannonBall : IComponentData
    2.     {
    3.         public float3 Speed;
    4.     }
    5.  
    6.     // Aspects must be declared as a readonly partial struct
    7.     readonly partial struct CannonBallAspect : IAspect
    8.     {
    9.         // An Entity field in an Aspect gives access to the Entity itself.
    10.         // This is required for registering commands in an EntityCommandBuffer for example.
    11.         public readonly Entity Self;
    12.  
    13.         // Aspects can contain other aspects.
    14.  
    15.         // A RefRW field provides read write access to a component. If the aspect is taken as an "in"
    16.         // parameter, the field behaves as if it was a RefRO and throws exceptions on write attempts.
    17.         readonly RefRW<LocalTransform> Transform;
    18.         readonly RefRW<CannonBall> CannonBall;
    19.  
    20.         // Properties like this aren't mandatory. The Transform field can be public instead.
    21.         // But they improve readability by avoiding chains of "aspect.aspect.aspect.component.value.value".
    22.         public float3 Position
    23.         {
    24.             get => Transform.ValueRO.Position;
    25.             set => Transform.ValueRW.Position = value;
    26.         }
    27.  
    28.         public float3 Speed
    29.         {
    30.             get => CannonBall.ValueRO.Speed;
    31.             set => CannonBall.ValueRW.Speed = value;
    32.         }
    33.     }
    34.     #endregion
    In all cases it sets data at the same memory location.
    Which made me realize that my first example would make a copy as well. So it makes sense it doesn't work.
    This is due to RotateY returning a full struct.

    Edit: Also updated first post, try that as well.
     
    Last edited: Aug 17, 2023