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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question AI Ship controller - how to calculate torque to apply for yaw/pitch to chase target?

Discussion in 'Physics' started by MidniteOil, Jun 13, 2020.

  1. MidniteOil

    MidniteOil

    Joined:
    Sep 25, 2019
    Posts:
    342
    Greetings,

    TL/DR: I need to know how to tell if the target is to the left/right, and above/below my position (i.e. do I need to turn left or right and/or pitch up or down to point at the target?).

    I'm working on a space combat simulator. I have a ShipController which subscribes to events on a class that implements an IControllerInput interface.
    Code (CSharp):
    1. public delegate void InputEvent();
    2. public delegate void InputEventFloat(float value);
    3.  
    4. public interface IControllerInput
    5. {
    6.     event InputEvent FireEvent1;
    7.     event InputEvent FireEvent2;
    8.     event InputEventFloat ForwardEvent;
    9.     event InputEventFloat YawEvent;
    10.     event InputEventFloat PitchEvent;
    11.     event InputEventFloat RollEvent;
    12.     event InputEventFloat SideStrafeEvent;
    13.     event InputEventFloat VerticalStrafeEvent;
    14.     event InputEventFloat SlideEvent;
    15. }
    For player controlled ships the PlayerInput class fires these events based on keyboard/mouse input.
    Code (CSharp):
    1.         if (ForwardEvent != null)
    2.         {
    3.             var input = Input.GetAxis("Vertical");
    4.             isThrusting = input != 0;
    5.             if (isThrusting)
    6.             {
    7.                 ForwardEvent(input);
    8.             }
    9.         }
    10.  
    11. ...
    12.     private void HandleYaw(Vector3 mousePosition)
    13.     {
    14.         float screenCenter = Screen.width * 0.5f;
    15.         float yaw = (mousePosition.x - screenCenter) / screenCenter;
    16.         if (YawEvent != null && Mathf.Abs(yaw) > deadZoneRadius)
    17.         {
    18.             YawEvent(yaw);
    19.         }
    20.     }
    21.  
    22.     private void HandlePitch(Vector3 mousePosition)
    23.     {
    24.         float screenCenter = Screen.height * 0.5f;
    25.         float pitch = (mousePosition.y - screenCenter) / screenCenter;
    26.         if (PitchEvent != null && pitch != 0 && Mathf.Abs(pitch) > deadZoneRadius)
    27.         {
    28.             PitchEvent(-pitch);
    29.         }
    30.     }
    31.  
    For ship movement, the ShipController uses AddForce and AddTorque for physics based movement.
    Code (CSharp):
    1.  
    2. private void ForwardThrust(float thrust)
    3.     {
    4.         rigidBody.AddForce(gameObject.transform.forward * thrust * forwardThrustPower * Time.deltaTime );
    5.     }
    6.  
    7.     private void YawMovement(float yaw)
    8.     {
    9.         rigidBody.AddTorque(gameObject.transform.up * yaw * yawSpeed * Time.deltaTime);
    10.     }
    11.  
    12.     private void PitchMovement(float pitch)
    13.     {
    14.         rigidBody.AddTorque(gameObject.transform.right * pitch * pitchSpeed * Time.deltaTime);
    15.     }
    16.  
    I want the AI controlled ships to use the same physics based movement so I'm writing an AIShipController class that will fire the ForwardEvent, YawEvent, PitchEvent, etc. events.

    For starters, I want the AI controlled ships to "chase" a player ship (or for simplicity just fly to a predetermined waypoint). I need to calculate what values to pass in for the forward event (i.e. force) and yaw and pitch events (i.e. torque). I want to simulate the -1.0 to 1.0 values like you get from Input.GetAxis() and in order to do that what I really need to know is how to calculate whether to apply positive or negative torque to transform.up and transform.right. Essentially, I need to know how to tell if the target is to the left/right, and above/below.

    I was thinking that Vector3.Angle() would be useful here but I don't think that tells me whether the target is above or below me and I'd like to see an example of how to apply that to this scenario.

    Based on another post from 2015 that seemed related, I tried using Vector3.Dot to achieve this. Here's my code:

    Code (CSharp):
    1.  
    2.     void Update()
    3.     {
    4.         Turn();
    5.         Move();
    6.     }
    7.  
    8.     void Turn()
    9.     {
    10.         var heading = transform.forward.normalized;
    11.         var target = targetPosition.position.normalized;
    12.         var fwdBackTest = Vector3.Dot(heading, target);
    13.         var leftRightTest = Vector3.Dot(transform.right.normalized, target);
    14.         var upDownTest = Vector3.Dot(transform.up.normalized, target);
    15.         Debug.LogFormat("AIShipController: Our heading: {0}, {1}, {2}. Target: {3}, {4}, {5}, fwdBackTest: {6}, leftRightTest: {7}, upDownTest{8}",
    16.             transform.position.x, transform.position.y, transform.position.z, targetPosition.position.x, targetPosition.position.y, targetPosition.position.z,
    17.             fwdBackTest, leftRightTest, upDownTest);
    18.  
    19.         if (Mathf.Abs(leftRightTest) > 0.05f && YawEvent != null)
    20.         {
    21.             if (leftRightTest > 0f)
    22.             {
    23.                 yawMomentum = Mathf.Min(1.0f, yawMomentum + 0.01f);
    24.                 Debug.LogFormat("Applying {0} yaw", yawMomentum);
    25.                 YawEvent(yawMomentum);
    26.             }
    27.             else
    28.             {
    29.                 yawMomentum = Mathf.Max(-1.0f, yawMomentum - 0.01f);
    30.                 Debug.LogFormat("Applying {0} yaw", yawMomentum);
    31.                 YawEvent(yawMomentum);
    32.             }
    33.         }
    34.     }
    To start with I'm only applying torque for the yaw (left/right) but it ends up constantly applying torque because the .Dot() values never change even though the ship is rotating:

    I've been stuck on this for a few days now and could really use some help. I suspect that lack of responses is due to the fact that this is a tough problem which is why everybody seems to punt and resort to using RotateTowards instead of moving via physics.

    Thanks in advance.

    - Greg.
     
    Last edited: Jun 17, 2020
    Jean_Paul2016 likes this.