Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Kyuu · Dec 23, 2014 at 02:43 PM · rotationphysicsquaternionrigidbody2daddforce

2D Rotate towards GameObject acting odd.

Hey, I am having a problem with a 2d (air)plane I am working on. It is a side scrolling game, and I want the plane to follow the player. To move I am using the rigidbody2D and to rotate I am using Quaternion LookAt. The problem is, when the aircraft exceeds the X position of the player, it goes in the opposite direction, so it's moving away from the player instead of towards it. When it gets behind the player again ( X<=player X), it follows the player normally.

 void FixedUpdate () 
 {
         Rotate ();
         Move ();
 }
     
 void Rotate()
 {    
     Quaternion newRotation = Quaternion.LookRotation (player.transform.position - transform.position);
     Quaternion newRot = Quaternion.Slerp(transform.rotation, newRotation, rotateSpeed * Time.deltaTime);
     transform.rotation = new Quaternion(0, 0, newRot.z, newRot.w);
 }
     
 void Move()
 {
     rigidbody2D.AddForce (transform.right * flySpeed*8 * Time.deltaTime, ForceMode2D.Impulse);
     
     if(rigidbody2D.velocity.magnitude > flySpeed)
     {
         rigidbody2D.velocity = rigidbody2D.velocity.normalized * flySpeed;
     }
 }

I want the aircraft to rotate with a rotatespeed, so it won't instantly face the player, and has to make a nice loop when it needs to. Can anyone help me with this? I've looked into multiple solutions, but haven't found anything.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Scribe · Dec 24, 2014 at 12:37 PM 0
Share

This line scares me: transform.rotation = new Quaternion(0, 0, newRot.z, newRot.w); perhaps you want to convert to an eulerian representation of the rotation before trying to manipulate component-wise, I'd say I'm reasonably competent at Quaternions but I wouldn't be able to work out the expected behaviour of the line.

I will have a go at this is a bit!

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by nu-assets · Dec 24, 2014 at 02:00 PM

You should perform your calculations in local space not in world space.

You can rewrite your Rotate() method like this:

     void Rotate()
     {
         Vector2 dir = transform.InverseTransformPoint(player.transform.position);
 
         float angle = Vector2.Angle(Vector2.right, dir);
 
         angle = dir.y < 0 ? -angle : angle;
 
         transform.Rotate(Vector3.forward, rotateSpeed * Time.deltaTime * angle);
     }

This way you have a very simple but solid implementation of a follow script.

To prevent the follower to increase its angular velocity with the size of the angle you could do the following:

     const float Threshold = 1e-3f;
     void Rotate()
     {
         Vector2 dir = transform.InverseTransformPoint(player.transform.position);
 
         float angle = Vector2.Angle(Vector2.right, dir);
 
         angle = dir.y < 0 ? -angle : angle;
 
         if (Mathf.Abs(angle) > Threshold)
         {
             transform.Rotate(Vector3.forward, rotateSpeed * Time.deltaTime * Mathf.Sign(angle));
         }
     }

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kyuu · Jan 05, 2015 at 08:39 AM 0
Share

Sorry for the late reply, holidays got me busy. This works like a charm! So thank you very much for this =] The only problem I'm facing right now is that I want to flip the sprite when it goes upside down (so it actually won't fly upside down). This is the method I'm using:

  void CheckForChanges()
         {
             Vector3 standard = new Vector3 (1, 1, 1);
             Vector3 mirrored = new Vector3 (1, -1, 1);
             if (Helper.InBetween(transform.rotation.eulerAngles.z, 90, 270))
             {
                 if(!flipped)
                 {
                     flipped = true;
                     transform.localScale = mirrored;
                     Debug.Log ("Flipped");
                 }
             } 
             else 
             {
                 if(flipped)
                 {
                     flipped = false;
                     transform.localScale = standard;
                     Debug.Log ("Normal");
                 }
             }
         }

I know this isn't the best method to do it in first place, but it works. When combined though, with the script given, it just flips each frame when going straight up, not making the loop.

I appreciate your answer non the less, so thank you very much!

avatar image Kyuu · Jan 05, 2015 at 11:16 AM 0
Share

Never $$anonymous$$d that above, I have found the solution =] (Created an additional flipped sprite, and changed it to that ins$$anonymous$$d of changing the scale)

avatar image nu-assets · Jan 05, 2015 at 06:23 PM 0
Share

Glad to hear that it's working now... :)

avatar image
1

Answer by Scribe · Dec 24, 2014 at 01:27 PM

Okay, so this is a little 'hacky' in that I create a new parent so that I can separate the rotation around z and the local rotation around x (to make the plane upright). There would be a way of doing this without the extra parent, but I should be wrapping presents and not spending hours on Quaternion rotations! :D

The following should be attached to the highest object in your plane object hierarchy:

 public float forwardSpeed = 5;
 public float turnSpeed = 90;
 public float twistSpeed = 180;
 public Transform target;
 Vector3 targetPos;
 Transform this_transform;
 Vector3 dir;
 Transform parentT;
 GameObject parentGO;
 
 void Start(){
     this_transform = transform;
     parentGO = new GameObject("rotationControl");
     parentT = parentGO.transform;
     parentT.position = this_transform.position;
     this_transform.parent = parentT;
 }
 
 void FixedUpdate(){
     dir = new Vector3(target.position.x - parentT.position.x, target.position.y - parentT.position.y, 0);
     
     //Look rotation (around Z axis)
     Quaternion q = Quaternion.FromToRotation(Vector3.right, dir);
     parentT.rotation = Quaternion.RotateTowards(parentT.rotation, q, turnSpeed*Time.deltaTime);
     
     //Twist rotation (around local X axis)
     Quaternion q2 = Quaternion.identity;
     if(Mathf.Sign(dir.x) < 0){
         q2 = Quaternion.Euler(180, 0, 0);
     }
     this_transform.localRotation = Quaternion.RotateTowards(this_transform.localRotation, q2, twistSpeed*Time.deltaTime);
     
     //Movement (you can use your forces here, this was mainly for testing)
     parentT.position += parentT.right*Time.deltaTime*forwardSpeed;
 }


This should turn the plane to face the target over time and upright the plane when it becomes upside-down, hopefully without causing any movement in the z axis (you may want to clamp the z value just to be safe)!

Merry Christmas/Happy Holidays!

Scribe

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

i have rotated an gameobject but the axis of the object did not change 2 Answers

transform.Rotate and Rigidbody.MovePosition 1 Answer

move 2d character affected by physics with velocity and/or add force 2 Answers

Problems with rotating an object using angular velocity. 2 Answers

Rotate object towards another object without using the local Y axis 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges