Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Transform.forward isn't forward

Discussion in 'Scripting' started by Zalosath, Jan 22, 2019.

Thread Status:
Not open for further replies.
  1. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    Instantiating the ball:
    Code (CSharp):
    1. GameObject ball = Instantiate (baseball, this.transform.position, Quaternion.Euler(0f,0f,this.transform.rotation.eulerAngles.z), null);  
    2.                 ball.transform.position = new Vector3 (transform.position.x, transform.position.y + 1f, transform.position.z);
    Setting its velocity:
    Code (CSharp):
    1. this.body = GetComponent<Rigidbody> ();
    2.         Vector3 velocity = this.transform.rotation * this.transform.forward;
    3.         this.body.AddForce (velocity * 100f);
    This only shoots the ball in a single direction no matter my rotation. The game is 3 dimensional and the camera rotates around the players rotation. How come?
     
  2. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    You are using both your transform.forward and transform.rotation. transform.forward represents the forward direction of the given transform. Multiplying by your rotation effectively applies the rotation twice. Try just using
    Vector3 velocity = transform.forward;
    . This will apply the force in the ball's forward direction. Alternatively, if you really like manually applying rotations to vectors, you can use this
    Vector3 velocity = transform.rotation * Vector3.forward;
    . This will rotate a vector that points in the global "forward" direction by the transform's rotation, which should point in the same direction as transform.forward.
     
  3. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    This still doesn't really work,
    Here's a quick youtube video I made illustrating the issue:
     
  4. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,747
    You're moving the projectile along its own forward vector, are you sure the ball forward vector matches the player forward vector?

    Either makes sure that is so or move the projectile along the player's forward vector.
     
  5. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    I set the rotation of the ball to the rotation of the player.
     
  6. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,747
    If you're doing that in the instantiation call in your code above, then you're doing it wrong, you should be setting the y value, not the z value.
     
  7. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Have you paused the game while it's running and examined one of the balls in the scene view to make sure it has the rotation that you think you're giving it?

    If your game's axes are aligned in the default way for Unity, then the Y axis points up (opposite gravity), so the player's yaw will be the Y euler, not the Z euler.
     
  8. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    This works great - except when I am standing still, it only fires correctly between the rotation 180 to 360 degrees, then it just starts firing backwards.
     
  9. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,747
    I think that might be caused by something called gimble lock (an unavoidable problem with the way quaternions convert to euler angles), does this work instead?

    Code (CSharp):
    1. var rot = this.transform.rotation;
    2. rot.x = 0; // clear vertical rotation
    3.  
    4. GameObject ball = Instantiate (baseball, this.transform.position, rot), null);
    5. ball.transform.position = new Vector3 (transform.position.x, transform.position.y + 1f, transform.position.z);
    6.  
     
  10. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    @Munchy2007: Warning! transform.rotation is a Quaternion; setting its x value to zero is NOT doing what you think it is!

    If you want to change different rotational axes separately, you need to work in euler angles, not quaternions. Quaternions have 4 dimensions and none of them corresponds directly to any rotational axis.
     
    Munchy2007 likes this.
  11. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    If it works for 0-180 but not 180-360, that suggests to me there's some problem where one function handling angles uses the interval (0, 360) but another uses the interval (-180, 180) and something isn't handling wrap-around correctly.

    Again, I suggest that you pause the game and check the rotations of various objects in the scene view/inspector to see if that offers any clues about what's going wrong. You could also try adding some Debug.Log statements.
     
  12. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    I saw no change in the problem.

    In the first frame, it has a rotation of 0,0,-70 in the second frame -1,69.7,-79 then after that there's no change.

    The initial rotation of the character that shoots the ball is 0,0,0

    Facing in the range where it works ^

    This is the range of 0-180, initially not working.
    First frame: -64.8,-19.7,-68.4
    Second frame: -54.8,51.4,-131.5
    Third frame: -60,40,-122
    Fourth frame: -63.97, 25, -108.9
    Fifth frame: -65.99, 6.75, -92.4

    And so on and so fourth.
     
  13. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    You need to be a lot more precise than that. Computer programming is the art of bargaining with evil genies: computers will grant your wishes, but you better phrase everything exactly right, because they're going to give you what you asked for rather than what you meant.

    It kinda sounds like you're saying that the Instantiate() call is assigning the ball a rotation that is completely different from what you asked for, but that's pretty implausible, so I'm guessing that either you meant something different or you're not collecting the data that you think you're collecting.

    Also, if you are expecting me to give you step-by-step instructions that you can carry out without thinking and then just report back to me and get an answer to your problem, you are going to be disappointed. This is your problem; I expect you to work at least as hard as me.
     
  14. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    I'm not expecting a step-by-step tutorial on a solution. I understand that I need to solve my own issue, and I would love to do that, but I'm not sure where I'm going wrong. Those values I gave were exact to what was given out by the editor.

    If this is helpful, here's the entirety of the classes.
    Baseball.cs
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Baseball : MonoBehaviour {
    6.  
    7.     public Vector3 direction;
    8.     private Rigidbody body;
    9.  
    10.     private float range = 0.5f;
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.         this.body = GetComponent<Rigidbody> ();
    15.         Vector3 velocity = this.transform.forward;
    16.         this.body.AddForce (velocity * 100f);
    17.         StartCoroutine ("wait");
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         Debug.Log (transform.rotation.y);
    23.         GameObject obj = this.findClosestEnemy ();
    24.         if (obj != null) {
    25.             obj.GetComponent<ZombieType> ().damage (10f);
    26.             Destroy (this.gameObject);
    27.         }
    28.     }
    29.  
    30.     IEnumerator wait()
    31.     {
    32.         yield return new WaitForSeconds (4f);
    33.         Destroy (this.gameObject);
    34.     }
    35.  
    36.     public GameObject findClosestEnemy()
    37.     {
    38.         Collider[] coll = Physics.OverlapSphere (this.transform.position, range/2);
    39.         for (int i = 0; i < coll.Length; i++)
    40.         {
    41.             if (coll [i].gameObject.tag == "Zombie")
    42.                 return coll[i].gameObject;
    43.         }
    44.         return null;
    45.     }
    46.  
    47. }
    48.  
    CharacterMovement.cs
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CharacterMovement : MonoBehaviour {
    6.  
    7.     private Vector3 moveDirection = Vector3.zero;
    8.     private CharacterController controller;
    9.     private Camera camera;
    10.     private Animation anim;
    11.     private AudioSource source;
    12.     private Animator ator;
    13.  
    14.     public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
    15.  
    16.     public RotationAxes axes = RotationAxes.MouseXAndY;
    17.  
    18.     public float sensitivityX = 2F;
    19.  
    20.     public float sensitivityY = 2F;
    21.  
    22.  
    23.  
    24.     public float minimumX = -360F;
    25.  
    26.     public float maximumX = 360F;
    27.  
    28.  
    29.  
    30.     public float minimumY = -60F;
    31.  
    32.     public float maximumY = 60F;
    33.  
    34.  
    35.  
    36.     float rotationX = 0F;
    37.  
    38.     float rotationY = 0F;
    39.  
    40.  
    41.  
    42.     private List<float> rotArrayX = new List<float>();
    43.  
    44.     float rotAverageX = 0F;
    45.  
    46.  
    47.  
    48.     private List<float> rotArrayY = new List<float>();
    49.  
    50.     float rotAverageY = 0F;
    51.  
    52.  
    53.  
    54.     public float frameCounter = 20;
    55.  
    56.  
    57.  
    58.     Quaternion originalRotation;
    59.  
    60.     private float timer2;
    61.  
    62.     public GameObject baseball;
    63.     public float speed = 5f;
    64.     public float cameraHeight = 20f;
    65.  
    66.     // Use this for initialization
    67.     void Start () {
    68.         this.controller = GetComponent<CharacterController> ();
    69.         camera = Camera.main;
    70.         this.anim = GetComponent<Animation> ();
    71.         this.source = GetComponent<AudioSource> ();
    72.         this.ator = GetComponent<Animator> ();
    73.  
    74.         Cursor.lockState = CursorLockMode.Locked;
    75.  
    76.         Rigidbody rb = GetComponent<Rigidbody>();
    77.         if (rb)
    78.             rb.freezeRotation = true;
    79.         originalRotation = transform.localRotation;
    80.     }
    81.  
    82.     void Update ()
    83.     {
    84.         float tempSpeed = speed;
    85.         if (Input.GetKey (KeyCode.LeftShift))
    86.             tempSpeed += 3f;
    87.         else
    88.             tempSpeed = speed;
    89.      
    90.         moveDirection = new Vector3 (Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    91.         moveDirection = transform.TransformDirection (moveDirection);
    92.         moveDirection = moveDirection * tempSpeed;
    93.  
    94.         if (moveDirection != Vector3.zero) {
    95.             if (tempSpeed != speed) {
    96.                 anim ["Shoot Rifle"].speed = 1.5f;
    97.                 anim ["Rifle Run"].speed = 1.5f;
    98.             } else {
    99.                 anim ["Shoot Rifle"].speed = 1f;
    100.                 anim ["Rifle Run"].speed = 1f;
    101.             }
    102.          
    103.             if (Input.GetMouseButton (0)) {
    104.                 anim.Play ("Shoot Rifle");
    105.             } else {
    106.                 anim.Play ("Rifle Run");
    107.             }
    108.         } else {
    109.             if (Input.GetMouseButton(0))
    110.                 anim.Play ("Gunplay");
    111.             else
    112.                 anim.Play ("Rifle Idle");
    113.         }
    114.  
    115.         /*Vector3 pos = this.transform.position;
    116.         pos.y += cameraHeight;
    117.         pos.x += 20f;
    118.         camera.transform.position = pos;
    119. */
    120.         moveDirection.y -= 9.81f;
    121.  
    122.         controller.Move (moveDirection * Time.deltaTime);
    123.         this.timer2 += Time.deltaTime;
    124.  
    125.         if (Input.GetMouseButton (0)) {
    126.             if (timer2 >= source.clip.length)
    127.             {
    128.                 timer2 = 0f;
    129.                 source.Play ();
    130.                 GameObject ball = Instantiate (baseball, this.transform.position, Quaternion.Euler(0f,this.transform.rotation.eulerAngles.y,0f), null);
    131.                 ball.transform.position = new Vector3 (transform.position.x, transform.position.y + 1f, transform.position.z);
    132.                 /*if (moveDirection != Vector3.zero)
    133.                     ball.GetComponent<Baseball> ().direction = this.transform.forward;
    134.                 else {
    135.                     ball.GetComponent<Baseball> ().direction = this.transform.forward * 100f * Time.deltaTime;
    136.                 }*/
    137.             }
    138.         }
    139.  
    140.         if (axes == RotationAxes.MouseXAndY)
    141.         {        
    142.             rotAverageY = 0f;
    143.             rotAverageX = 0f;
    144.  
    145.             rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
    146.             rotationX += Input.GetAxis("Mouse X") * sensitivityX;
    147.  
    148.             rotArrayY.Add(rotationY);
    149.             rotArrayX.Add(rotationX);
    150.  
    151.             if (rotArrayY.Count >= frameCounter) {
    152.                 rotArrayY.RemoveAt(0);
    153.             }
    154.             if (rotArrayX.Count >= frameCounter) {
    155.                 rotArrayX.RemoveAt(0);
    156.             }
    157.  
    158.             for(int j = 0; j < rotArrayY.Count; j++) {
    159.                 rotAverageY += rotArrayY[j];
    160.             }
    161.             for(int i = 0; i < rotArrayX.Count; i++) {
    162.                 rotAverageX += rotArrayX[i];
    163.             }
    164.  
    165.             rotAverageY /= rotArrayY.Count;
    166.             rotAverageX /= rotArrayX.Count;
    167.  
    168.             rotAverageY = ClampAngle (rotAverageY, minimumY, maximumY);
    169.             rotAverageX = ClampAngle (rotAverageX, minimumX, maximumX);
    170.  
    171.             Quaternion yQuaternion = Quaternion.AngleAxis (rotAverageY, Vector3.left);
    172.             Quaternion xQuaternion = Quaternion.AngleAxis (rotAverageX, Vector3.up);
    173.  
    174.             transform.localRotation = originalRotation * xQuaternion * yQuaternion;
    175.         }
    176.         else if (axes == RotationAxes.MouseX)
    177.         {        
    178.             rotAverageX = 0f;
    179.  
    180.             rotationX += Input.GetAxis("Mouse X") * sensitivityX;
    181.  
    182.             rotArrayX.Add(rotationX);
    183.  
    184.             if (rotArrayX.Count >= frameCounter) {
    185.                 rotArrayX.RemoveAt(0);
    186.             }
    187.             for(int i = 0; i < rotArrayX.Count; i++) {
    188.                 rotAverageX += rotArrayX[i];
    189.             }
    190.             rotAverageX /= rotArrayX.Count;
    191.  
    192.             rotAverageX = ClampAngle (rotAverageX, minimumX, maximumX);
    193.  
    194.             Quaternion xQuaternion = Quaternion.AngleAxis (rotAverageX, Vector3.up);
    195.             transform.localRotation = originalRotation * xQuaternion;        
    196.         }
    197.         else
    198.         {        
    199.             rotAverageY = 0f;
    200.  
    201.             rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
    202.  
    203.             rotArrayY.Add(rotationY);
    204.  
    205.             if (rotArrayY.Count >= frameCounter) {
    206.                 rotArrayY.RemoveAt(0);
    207.             }
    208.             for(int j = 0; j < rotArrayY.Count; j++) {
    209.                 rotAverageY += rotArrayY[j];
    210.             }
    211.             rotAverageY /= rotArrayY.Count;
    212.  
    213.             rotAverageY = ClampAngle (rotAverageY, minimumY, maximumY);
    214.  
    215.             Quaternion yQuaternion = Quaternion.AngleAxis (rotAverageY, Vector3.left);
    216.             transform.localRotation = originalRotation * yQuaternion;
    217.         }
    218.     }
    219.  
    220.     public static float ClampAngle (float angle, float min, float max)
    221.     {
    222.         angle = angle % 360;
    223.         if ((angle >= -360F) && (angle <= 360F)) {
    224.             if (angle < -360F) {
    225.                 angle += 360F;
    226.             }
    227.             if (angle > 360F) {
    228.                 angle -= 360F;
    229.             }        
    230.         }
    231.         return Mathf.Clamp (angle, min, max);
    232.     }
    233.  
    234.  
    235. }
    236.  
     
  15. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    The editor gives out millions of values. You need to explain which numbers you're looking at and the context of the test in order for those values to have any meaning.

    The general idea here is to narrow down the problem space. Usually there's many different errors that could all generate similar symptoms. For instance, if your balls are flying off in the wrong direction, that could mean that:

    A) The balls are spawned pointing the wrong direction
    B) The balls are rotated between their spawn time and when you add velocity
    C) The velocity is being applied in the wrong direction

    All of those would have the end result of the ball moving in the wrong direction.

    By checking the ball's orientation directly (rather than just its velocity), we should be able to tell the difference between A/B versus C. By checking the ball's orientation both during instantiation and when the velocity is applied, we should be able to tell the difference between A and B.

    Once you've narrowed it down some, you can iteratively get more and more specific. For instance, if you conclude that the problem has to be A, then you might want to distinguish between:

    A1) You didn't correctly detect what direction the player was facing
    A2) You didn't correctly convert the player's facing into the desired orientation for the ball
    A3) You didn't correctly apply that orientation to the ball when spawning it

    By adding more code to your function to test the values of different variables at different points in your script, you can distinguish between these sub-cases and narrow the problem down even further.

    Sometimes you'll see a value that doesn't match up with any of your theories about what's going on, in which case you need to try to come up with a new theory that could explain where that value is coming from.
     
  16. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    2,001
    This is confusing, but it's the way everyone (not just Unity) does it: rotation.x, y or z gives RAW quaternion values, which are incomprehensible. To read: rotation.eulerAngles.x (eulerAngles translates into 0-360 degrees).To write, rotation=Quaternion.Euler(x.y.z) (the Euler translates from degrees into quaternion values).
     
    Antistone likes this.
  17. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,747
    Good catch, l meant it to be transform.rotation.eulerAngles
     
  18. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    Thanks, after printing some debugs I've figured out that the velocity is always 0, no matter the direction it is fired.

    Here's the debugs when the player is facing xyz 0,0,0
    Debugs are the velocity variable in the baseball class.

    Velocity before: (0.0, 0.0, 0.0)
    Orientation before: (0.0, 293.6, 0.0)
    Velocity after: (-0.9, 0.0, 0.4)
    Orientation after: (0.0, 293.6, 0.0)

    So I'm not certain on the problem but I'm pretty sure its the velocity

    Edit: i managed to fix this. Rather than shooting from the player location a solution was to shoot from the gun. The bullets were colliding with the character causing bullet redirection
     
    Last edited: Jan 23, 2019
    Shamantiks likes this.
  19. zylo117

    zylo117

    Joined:
    Jul 20, 2020
    Posts:
    1
    You have saved my day.
     
    Zalosath likes this.
Thread Status:
Not open for further replies.