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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Make face of 2D ball face direction of movement

Discussion in 'Scripting' started by legendz25, Sep 25, 2014.

  1. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    Hello Unity Community,

    I have a 2D ball with a face. I would like the face of the ball to face the direction of movement after bouncing off a gameobject. I've looked around the forums for examples of how to make the work. The code snippet I found in another post was the closest I got this to work using Quaternion.Slerp. The issue that the rotation is not instant. The face of the 2D ball does face the direction of movement but does so in a "slow" fashion. I know that using 1.0f should make the Slerp "instant" but I am not seeing that. Is it because I'm using "AngleAxis"? Any pointers, corrections, or explanations would be greatly appreciated. Also, 1st time posting on unity forums. Sorry for any errors in not knowing rules for posting. Thanks for any help.

    void Start()
    {
    origVectorPosition = gameObject.transform.position;​
    }

    void Update()
    {
    Vector3 moveDirection = gameObject.transform.position - origVectorPosition;

    if (moveDirection != Vector3.zero)
    {
    float angle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
    Quaternion newRotation = Quaternion.AngleAxis((angle), Vector3.forward);
    transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, 1.0f);​
    }​
    }
     
  2. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    If you want it to happen instantly, probably the easiest way to do it is Transform.LookAt. It will rotate your transform so that its forward is pointing to the specified point you wanna look at. In your IF there, you could just write:

    Code (CSharp):
    1. Vector3 lookAtPoint = gameObject.transform.position + moveDirection;
    2. transform.LookAt(lookAtPoint, Vector3.up);  //assuming y-axis is up in your game
     
  3. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    I'll give it a shot and report back on my results.

    ***Doesn't seem to rotate the 2D ball correctly, if it all. Been racking my brain over this issue for a few days now.
     
    Last edited: Sep 25, 2014
  4. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    Hmm...that code should work. If it is not working, then I don't think that the moveDirection vector is correct.

    It's a little hard for me to understand what you are doing with that snippet, but at the very least, I do not see any code to actually move the ball. Why is the move direction set to be the vector from the ball's initial position at the beginning of the game to its current position?

    Are you using Unity's physics engine to just let the ball drop with gravity and such? If that is the case, try measuring the movement delta each frame, then use that as the moveDirection. Something like this:

    Code (CSharp):
    1.     private Vector3 previousPos;
    2.  
    3.     private void Awake()
    4.     {
    5.         previousPos = transform.position;
    6.     }
    7.  
    8.     private void Update()
    9.     {
    10.         //vector from position in previous frame to position in current frame
    11.         Vector3 moveDirection = transform.position - previousPos;
    12.  
    13.         if (moveDirection != Vector3.zero)
    14.         {
    15.             //a point a little in front of where we are
    16.             Vector3 lookAtPoint = transform.position + moveDirection;
    17.             transform.LookAt(lookAtPoint, Vector3.up);
    18.         }
    19.  
    20.         //this is the key part: remember the where we are this frame
    21.         //so that next frame we can measure how far we moved from this
    22.         //point.
    23.         previousPos = transform.position;
    24.     }
     
  5. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    Why not just: transform.rotation = newRotation; ?
     
  6. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    I did try that...depending on what "newRotation" is...it either continuously spins or does a slow rotation.
     
  7. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    Why is the move direction set to be the vector from the ball's initial position at the beginning of the game to its current position?
    Interesting, my thinking was that I needed to know the difference in angle or direction using an initial transform. I didn't think it was actually setting the initial value as the current value.

    Are you using Unity's physics engine to just let the ball drop with gravity and such?
    Yes, I am using unity's 2D physics. The ball itself has a mass of 1 and no gravity or anything else for that matter. So my ball basically has "perfect elasticity" (perfect bounce). I do give the ball an initial velocity to move it.

    I will review what I have and report back on what I got. I think having an outside perspective to "bounce" (no pun intended hahaha) ideas off of...helps.
     
  8. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    From his code it seems he have to LookAt around Z axis.
     
  9. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    topsekret, thank you so much! You solved my issue in like 2 hours. Is there a place to mark this answered or "upvoted"?

    I was able to adapt parts of your code and merge it with what I had before...voila...it worked! The key part was this was this part! previousPos = transform.position;

    Here is the complete code that worked for my 2D ball with perfect bounce.

    BTW, your previous code worked as well except for the fact that it took 2D sprite and make it face up in the y direction. Otherwise, it worked just as well. I just couldn't figure how to use the code and still have sprite face in the z direction.

    void Start()
    {
    previousPos = transform.position;
    }

    void Update()
    {
    //vector from position in previous frame to position in current frame
    moveDirection = transform.position - previousPos;
    if (moveDirection != Vector3.zero)
    {
    angle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
    guiAngle.text = angle.ToString();

    //assuming front of you ball is normally facing right, add or subtract to/from angle for ball facing other direction
    Quaternion newRotation = Quaternion.AngleAxis((angle), Vector3.forward);
    transform.rotation = Quaternion.Lerp(transform.rotation, newRotation, 1.0f);
    }

    //this is the key part: remember the where we are this frame
    //so that next frame we can measure how far we moved from this
    //point.
    previousPos = transform.position;
    }
     
    DarkAndHigh likes this.
  10. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    Yes, I think that was the issue I was having but I whatever I tried it didn't seem to work correctly but I just finish posting my solution with regard to this. Thanks for your input too, Fraconte!
     
  11. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    I think you just had to change vector3.up with vector3.forward in LookAt().

    To make code more readable look at this: http://forum.unity3d.com/threads/using-code-tags-properly.143875/
     
  12. topsekret

    topsekret

    Joined:
    Apr 18, 2013
    Posts:
    69
    You are welcome, legendz25. Glad I could help! And I believe Fraconte is correct, changing the Vector3.up to Vector3.forward should make the LookAt work. I overlooked the fact that you were making a 2D game initially lol.
     
  13. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    Hum..Let me try the forward for the hell of it. Learning something new is always good in my book.

    I'll post results.

    ***Unfortunately, vector3.forward still produces the same results. So strange...even reading online documentation would indicate that vector3.forward should work in this case.

    Yes, thanks for the heads up on the code format Fraconte. I'll do that on my next postings.
     
    Last edited: Sep 26, 2014
  14. legendz25

    legendz25

    Joined:
    May 30, 2014
    Posts:
    17
    Doing this just to show final solution in a easier to read format. Thanks to Fraconte and topsekret for the help.

    Code (CSharp):
    1. void Start()
    2. {
    3.      previousPos = transform.position;
    4. }
    5.  
    6. void Update()
    7. {
    8.     //vector from position in previous frame to position in current frame
    9.     moveDirection = transform.position - previousPos;
    10.     if (moveDirection != Vector3.zero)
    11.     {
    12.           angle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg;
    13.  
    14.           //assuming front of you ball is normally facing right, add or subtract to/from angle for ball             facing other direction
    15.           Quaternion newRotation = Quaternion.AngleAxis((angle), Vector3.forward);
    16.           transform.rotation = Quaternion.Lerp(transform.rotation, newRotation, 1.0f);
    17.      }
    18.  
    19.            //this is the key part: remember the where we are this frame
    20.            //so that next frame we can measure how far we moved from this
    21.            //point.
    22.            previousPos = transform.position;
    23.      
    24. }
     
    Last edited: Sep 26, 2014
  15. originalterrox

    originalterrox

    Joined:
    Feb 6, 2015
    Posts:
    40
    A 2d version of LookAt, which happens instantly, I use this.
    Code (CSharp):
    1. transform.LookAt (rigidbody2D.velocity + rigidbody2D.position, new Vector3 (0, 0, 1));
    That rotates along z-axis.
    The velocity + position equals a point just in front of the 2D objects motion of travel. At velocity zero it wont rotate as far as I've tested.
    the new Vector3 is just to see that it is z axis without working out if Vector3.left etc is up or whatever.
     
    Last edited: Apr 16, 2015