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 Ship Turret rotate towards target in Parent Space?

Discussion in 'Entity Component System' started by Lapsapnow, Jan 29, 2022.

  1. Lapsapnow

    Lapsapnow

    Joined:
    Jul 4, 2019
    Posts:
    51
    I have a parent entity, and a child entity. Ship and Turret.
    The turret acquires a target, in world space.
    It rotates towards the target, using Vector3.Slerp( turret_forwards, target_direction, percent )

    That's all fine. But.

    When I want to set the new rotation for the given turret, I want to set the rotation in Parent Space. However, when I do " ref Rotation rotation " rotation.Value = new_direction it sets the rotation in World Space.

    I assume I'm missing something basic here?
    How do I set local to parent rotations in ECS?

    Example code ; I stripped out everything except the bare minimum requirements of the system ( ignoring the vector slerping which is perfectly fine ). Any help is greatly appreciated.
    - - -
    Code (CSharp):
    1. Entities.
    2.      WithNone<TAGDestroyed>().WithNone<TAGParentDead>().WithNone<TAGPrefab>().WithNone<COUnitArrive>().
    3.      ForEach((ref Rotation rotation, in COTurret turret, in COUnitTargeting targeting, in LocalToWorld localToWorld) =>
    4.      {
    5.           if (targeting.targetEntity != Entity.Null)
    6.           {
    7.  
    8.                float3 toDirection = math.normalize(targeting.relativeTargetPosition); // pos - targ.pos
    9.                float3 up = math.up(); // { 0, 1, 0 }
    10.                rotation.Value = quaternion.LookRotation( toDirection , up ); // Sets in World Space, but it needs to be in Parent space.
    11.  
    12.           }
    13.      }).ScheduleParallel();
     
    Last edited: Jan 30, 2022
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,904
    Do you mean local space or the parent's local space?
    This would suggest that your entity does not have a parent as normally Rotation is local space and local space only matches world space if there is no parent.
     
    ElliotB likes this.
  3. Lapsapnow

    Lapsapnow

    Joined:
    Jul 4, 2019
    Posts:
    51
    Hey Latios.

    The Parent's local space. As in, I want this rotation applied to this entity offset by it's parent's current rotation.

    Well man that's what should be happening. Which is exactly why I'm so frustrated.
    It has a parent. But the rotation is not offset. Which is why I assume I'm missing something very simple, or mis-using Rotation somehow.

    Unless the problem is actually, that I'm accidentally negating the parent's rotational offset somehow. Which would be hilarious.
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,904
    I'm getting the feeling you don't fully understand coordinate spaces as this doesn't make any sense:
    So I am going to assume what you actually want is to convert a world-space rotation into a local space rotation. If the parent is the root, then:
    Code (CSharp):
    1. rotation.Value = math.mul(math.inverse(parentRotation), worldRotation);
     
  5. DevViktoria

    DevViktoria

    Joined:
    Apr 6, 2021
    Posts:
    94
    And also if your turret has some colliders on it then it is going to be "unparented in order to take part in the physics simulation". Then you might need some trick to in get the parent rotation as well.
     
  6. Lapsapnow

    Lapsapnow

    Joined:
    Jul 4, 2019
    Posts:
    51
    I understand it, but I don't know how to say it precisely. Anyway you understood.
    Thanks.
     
    Last edited: Jan 31, 2022
  7. Lapsapnow

    Lapsapnow

    Joined:
    Jul 4, 2019
    Posts:
    51
    Thanks Vik.
     
    DevViktoria likes this.
  8. Srokaaa

    Srokaaa

    Joined:
    Sep 18, 2018
    Posts:
    169
    @Lapsapnow Here is a system I use:

    Code (CSharp):
    1.         protected override void OnUpdate()
    2.         {
    3.             var playerPosition = GetComponent<LocalToWorld>(GetSingletonEntity<CurrentPlayer.CurrentPlayer>()).Position;
    4.             var deltaTime      = Time.DeltaTime;
    5.             Entities.ForEach(
    6.                          (
    7.                              ref Rotation     rotation,
    8.                              ref TargetPlayer targetPlayer,
    9.                              in  Parent       parent,
    10.                              in  LocalToWorld localToWorld
    11.                          ) =>
    12.                          {
    13.                              if (!HasComponent<LocalToWorld>(parent.Value)) return;
    14.                              var playerDistance   = playerPosition - localToWorld.Position;
    15.                              var parentLocalToWorld          = GetComponent<LocalToWorld>(parent.Value);
    16.                              var parentRotation   = normalize(parentLocalToWorld.Rotation);
    17.                              var targetingNormal  = mul(parentRotation, targetPlayer.TargetingAreaNormal);
    18.                              var goalRotation     = quaternion.identity;
    19.                              var isInShootingArea = dot(targetingNormal, playerDistance);
    20.                              if (isInShootingArea > 0)
    21.                              {
    22.                                  var rotationAxis = mul(parentRotation, targetPlayer.RotationAxis);
    23.                                  var up = parentLocalToWorld.Up;
    24.                                  var direction = -cross(cross(playerDistance, rotationAxis),
    25.                                                         rotationAxis);
    26.  
    27.                                  var globalRotation =
    28.                                      quaternion.LookRotationSafe(normalize(direction), normalize(up));
    29.                                  goalRotation = mul(inverse(parentRotation), globalRotation);
    30.                              }
    31.  
    32.                              // FIXME: Make this rotation constant instead of slowing down
    33.                              rotation.Value = slerp(rotation.Value, goalRotation, 7 * deltaTime);
    34.                              // rotation.Value = goalRotation;
    35.                          })
    36.                     .Schedule();
    37.         }
    38.  
    It has additional checking if the target is on a correct "side" of the turret but you can just ignore this part
     
    Lapsapnow likes this.
  9. Lapsapnow

    Lapsapnow

    Joined:
    Jul 4, 2019
    Posts:
    51
    Thank you very much sir!