• 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
Question by Jason B · Apr 17, 2011 at 03:06 AM · rotation

Having trouble checking my rotational values.

I'm trying to rotate an object and check when it's rotated a certain amount so it knows when to stop. I have a playable character that banks left while you hold down left, and banks right when you hold down right, but they need to stop once they bank about 10 degrees in either direction.

This is all pretty easy logically until you factor in that rotations "wrap around" and go from 360 back to 0, so now I'm a little confused about how to actually do this.

I was going to post my code, but none of it works the way I originally planned it, so any help would be greatly appreciated as I'm back to square one.

Comment
Joshua
Bravini

People who like this

2 Show 3
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 Jason B · Apr 17, 2011 at 07:01 PM 0
Share

As a quick update to what I've tried, I also tried doing a simple check such as "if Z rotation is less than 10, increase, if greater than 350, decrease" but this again causes problems with the wrapping.

avatar image Owen-Reynolds · Apr 21, 2011 at 02:30 AM 0
Share

So, by bank, you mean a Z-rotation? When you bank, are you also turning that direction? Side-slipping (not changing Y-angle, but sliding a little sideways as you move forwards?) Bank+turn or move can drive you into the ground if you aren't careful.

avatar image Jason B · Apr 21, 2011 at 07:05 PM 0
Share

Right, z-rotation. There's no other turning happening, just a z-rotation.

5 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by _MGB_ · Apr 20, 2011 at 08:52 AM

Probably better to maintain a separate roll offset value in the player [-10 to +10] and then just set the roll with this value wrapped.

Comment
Joshua

People who like this

1 Show 2 · 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 Jason B · Apr 21, 2011 at 07:06 PM 0
Share

I suppose... I was mostly worried that somehow the variable and the actual rotation angle might get out of sync (somehow). I'll try doing something similar.

avatar image Owen-Reynolds · Apr 21, 2011 at 10:35 PM 0
Share

If you set the rotation to -10, then look it up, it might say 350, so DON'T LOOK IT UP. Code looks like: if(Input.GetKey("a")) { zAng-=0.1; if(zAng<-10) zAng=-10; } transform.eulerAngles=Vector3(0,0,zAng); To "synch," only ever look at and change zAng, and set "real" rotation from it last.

avatar image

Answer by synapsemassage · Apr 20, 2011 at 09:36 AM

Maybe this is a starting point for you? I haven't tested the code though.

public var maxRotationDelta : float = 10; public var speed : float = 45.0; private var initialAngleY : float; private var bankLeft : boolean; private var angleY : float;

function Start() { initialAngleY = transform.eulerAngles.y; } function Update () {

if(bankLeft) { maxRotationDelta = maxRotationDelta + 180; } angleY = Mathf.MoveTowardsAngle(transform.eulerAngles.y, initialAngleY + maxRotationDelta, speed * Time.deltaTime); transform.eulerAngles = Vector3(0, angleY, 0); }

Comment

People who like this

0 Show 1 · 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 Jason B · Apr 21, 2011 at 07:08 PM 0
Share

Thanks for that. Didn't even know about MoveTowardsAngle, might help in coming up with a solution. Once I do, I'll be sure to post what I did in my question.

avatar image

Answer by hellcats · Apr 21, 2011 at 12:20 AM

You could just maintain a separate variable which is the amount of rotation you have added so far. Then just check this variable instead of transform.rotation.

Comment

People who like this

0 Show 2 · 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 Jeston · Apr 21, 2011 at 08:53 PM 0
Share

This is better solved with a dot product, on normalized Vectors it represents a normalized range from -1, 0, 1 where -1 and 1 represent orthogonal and 0 represents parallel, so you will know when your rotation is close to 90 degrees by testing a dot product.

In a flight sim I made I used this to test if the plane was flying up or forward by its +Z axis as shown below:

Get degrees of plane in regards to horizon: Vector3.up is world up(sky) and transform.forward is jet's current direction.

float horizonAngle = Vector3.Dot( transform.forward, Vector3.up) Mathf.PI/2 Mathf.Rad2Deg;

avatar image hellcats · Apr 22, 2011 at 04:52 AM 0
Share

Actually, I think you have that backwards: a Dot product of 1 means parallel, and 0 means orthogonal. (BTW: I'm making a flight sim too!)

avatar image

Answer by TheDemiurge · Apr 24, 2011 at 11:12 AM

If there's no other rotation (and even if there is) this should be pretty simple. What works for me is using the input axes. Let's say you're using the "Horizontal" (A/D/Left/Right) keys:

var maxBankAngle: float = 10; var bankInput: float = 0; var tempZRot: float = 0; var refTransform: Transform = transform;

function Update() {     // store the axis' value in case we want it later     bankInput = Input.GetAxis("Horizontal"); // returns between -1 and 1     tempZRot = maxBankAngle * bankInput; // between -10 and 10     if (tempZRot < 0)     {          tempZRot += 360;     }     // using local angles will keep proper rotations if we're parented     refTransform.localEulerAngles.z = tempZRot; }

By using the axis, you get 4 things:
1. a way of easily maxing out your rotation
2. have it reset without extra checks for key held/released
3. automatically turn the proper direction; if you find directions are opposite from what you need, simply change +/- somewhere in that equation
4. (bonus!) you get to play with the sensitivity / gravity values on the axis (see documentation on Input), to adjust how fast we reach this maximum bank degree or recover from it

Comment

People who like this

0 Show 0 · 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

Answer by Wolfram · Apr 26, 2011 at 09:21 AM

We solved this problem in the past by converting both the upper and lower limit, as well as the current angle, into a defined "clamping space" (e.g., 0<=limitRight<=360 and limitLeft<=limitRight). Using this method, we can supply our limits as an arbitrary number (e.g., even way outside the 0..360 interval), and it will still be interpreted correctly. One of the main advantages is, that you can define any interval without twisting your brain thinking about wrap-around problems. For example, limitLeft=-10 and limitRight=10 maps to -10..10, but so does 350..10, or even -370..-350. On the other hand, it is also possible to map to the inverse interval: limitLeft=10 and limitRight=-10 maps to 10..350, and therefore allows only values >10 and <-10, and omits the range -10..10.

Furthermore, we added additional checks to a) correctly initialize the angle to the nearest border if it is outside the given interval, and b) if the current angle is set outside the allowed interval externally (e.g., by editing it directly in the Inspector), limit the interaction to one direction, the direction towards the nearest limit border (hard to explain, try it for yourself).

(Note that it can happen for large rotSpeed and the special case of "almost-full" 360 intervals (for example, 1 to 360) that the change in angle between two frames is too large and it "jumps" over the interval that is outside the allowed range (0 to 1))

using UnityEngine;

public class LimitedRotation : MonoBehaviour { // limitLeft is the minimal allowed angle public float limitLeft = -10;

 // limitRight is the maximal allowed angle
 public float limitRight = 10;

 // rotSpeed is a general scaling factor
 public float rotSpeed = 200;

 private bool haveLimits;

 void Start(){
     float newAngle=0;

     // prepare rotation limit tests (left/right)
     if(limitLeft==limitRight){
         // unrestricted rotation
         haveLimits=false;
     }else{
         haveLimits=true;
         // make sure 0&lt;=limitRight&lt;=360 and limitRight-limitLeft=(0..360) (-360&lt;=limitLeft&lt;=360)
         while(limitRight&lt;0)
             limitRight+=360;
         while(limitRight-limitLeft&gt;=360)
             limitLeft+=360;
         while(limitLeft&gt;limitRight)
             limitLeft-=360;

         if(limitLeft&gt;0){
             // 0 is not in allowed interval; initialize the angle to the nearest valid boundary
             float rightLimit=Mathf.Min(limitRight,360-limitRight);
             float leftLimit=Mathf.Min(Mathf.Abs(limitLeft),360-Mathf.Abs(limitLeft));
             if(leftLimit&gt;rightLimit)
                 newAngle = limitRight;
             else
                 newAngle = limitLeft;
         }
     }

     transform.localEulerAngles=new Vector3(0,0,newAngle);
 }

 void Update(){
     float deltaAngle=Input.GetAxis("Horizontal");
     float oldAngle = transform.localEulerAngles.z;
     float newAngle = oldAngle - rotSpeed * deltaAngle * Time.smoothDeltaTime;
     if(haveLimits){
         while(oldAngle&gt;limitRight)
             oldAngle-=360;
         if(oldAngle&gt;=limitLeft)
         {
             // clamp to limit
             while(newAngle&gt;limitRight)
                 newAngle-=360;
             if(newAngle&lt;limitLeft)
                 if(deltaAngle&lt;0)
                     newAngle=limitRight; // rotate left limit
                 else
                     newAngle=limitLeft; // rotate right limit
         }else{
             // we are outside the limit
             // so only allow movement towards nearest limit
             float distToRight=Mathf.Abs(oldAngle-limitRight);
             distToRight=Mathf.Min(Mathf.Abs(oldAngle-limitRight-360),distToRight);
             distToRight=Mathf.Min(Mathf.Abs(oldAngle-limitRight+360),distToRight);
             float distToLeft=Mathf.Abs(oldAngle-limitLeft);
             distToLeft=Mathf.Min(Mathf.Abs(oldAngle-limitLeft-360),distToLeft);
             distToLeft=Mathf.Min(Mathf.Abs(oldAngle-limitLeft+360),distToLeft);
             if(deltaAngle&lt;0 &amp;&amp; distToLeft&gt;distToRight ||
                deltaAngle&gt;0 &amp;&amp; distToLeft&lt;distToRight)
                 newAngle=oldAngle;
         }
     }
     while(newAngle&lt;0) newAngle+=360;
     while(newAngle&gt;360) newAngle-=360;

     transform.localEulerAngles=new Vector3(0,0,newAngle);
 } 

}

(yes, all "while()..." commands can be optimized by using an appropriate %/multiplication/fraction computation, instead of a stupid loop)

Note, in the code above limitLeft/limitRight can only be adjusted to a certain amount on-the-fly, since the initialization is done in Start(). If you want to adjust the limits freely (e.g., via script etc.), you should move the that initialization from Start() to an Update() function.

Comment

People who like this

0 Show 0 · 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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

No one has followed this question yet.

Related Questions

Flip over an object (smooth transition) 3 Answers

How do I check a rigidbody's rotation? Help with the madness 2 Answers

Objects not always Spawning At Correct Location 2 Answers

How to use one animation and Animator Controller on multiple objects? [2D] 0 Answers

how to ignore transform.position.y 3 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