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 Lylek · May 15, 2015 at 03:46 AM · rotationjavascriptloopwhile

While loop won't end. [closed]

Hello all =)

I am trying to make a simple rotation script for a door. The door will open and close, but the while loop for closing the door won't end. Here is my script:

 var startRot : Vector3; //the door's starting rotation
 var newRot : Vector3; //the door's new (open) rotation
 var rotateSpeed : int; //how fast the door opens
 var opened = false; //whether the door is opened or closed

 function Start() {
     startRot = transform.rotation.eulerAngles;
 }
 function RotateObject() {
     //if door is shut
     if(opened == false) {
         //while door's rotation is not equal to the new rotation
         while(transform.rotation.eulerAngles != newRot) {
             //rotate door
             transform.rotation.eulerAngles = Vector3.MoveTowards(transform.rotation.eulerAngles, newRot, Time.deltaTime * rotateSpeed);
             
             yield;
         }
         //when while loop ends, opened is true
         opened = true;
     }//if door is open
     else {
         //while door's rotation is not equal to its starting rotation
         while(transform.rotation.eulerAngles != startRot) {
             //rotate door
             transform.rotation.eulerAngles = Vector3.MoveTowards(transform.rotation.eulerAngles, startRot, Time.deltaTime * rotateSpeed);
             //print coordinates of startRot
             Debug.Log("(" + startRot.x + ", " + startRot.y + ", " + startRot.z + ")");
             //print coordinates or current rotation
             Debug.Log("(" + transform.rotation.eulerAngles.x + ", " + transform.rotation.eulerAngles.y + ", " + transform.rotation.eulerAngles.z + ")");
             yield;
         }
         //when while loop ends, opened is false
         opened = false;
     }
 }

Once the door closes, the debug logs in the second while loop both print the same coordinates (270, 180, 0), so the while loop should end... but it never stops. I am confused. Thank you for any help.

Comment
Add comment · Show 7
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 sas_88 · May 15, 2015 at 04:21 AM 1
Share

Use break after the yield statement in while loop...

avatar image Lylek · May 15, 2015 at 04:27 AM 0
Share

Thank you for your comment, but if I did that the while loop would break on the first frame and I need it to run until the door is closed.

avatar image sas_88 · May 15, 2015 at 04:45 AM 0
Share

create another boolen variable doorclose=false. change the doorclose=true when all the frames completed playing.

 if(doorclose)
 {
    break;
 }
avatar image Lylek · May 15, 2015 at 05:02 AM 0
Share

I do not see any reason to add a second variable... I tried this in the while loop:

 if(transform.rotation.eulerAngles == startRot) {
     break;
 }

Doesn't work though. It's like it doesn't realized they're the same...

avatar image Eno-Khaon · May 15, 2015 at 05:17 AM 1
Share

if you try something like

 Debug.Log((transform.rotation.eulerAngles).ToString("F7") + " --- " + newRot.ToString("F7"));

are they the same value or both different? I would suspect that the greater the precision displayed for the float values, the more likely they're not all EXACTLY identical, which is the condition for your while loop.

The reason I bring this up is because of your use of (Time.deltaTime * rotateSpeed) for your "time" value in $$anonymous$$oveTowards. You're moving a small percentage of the distance per frame between the current angle and the intended angle, but never genuinely reaching 100%.

Show more comments

4 Replies

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

Answer by Lylek · May 15, 2015 at 09:20 AM

Thanks for everyone's posts. @Dave29483 I wasn't sure how to implement your code, or how to convert it to JS, but if close enough is good enough, I ended up doing this to solve it:

     while(transform.rotation.eulerAngles != startRot) {
         //rotate door
         transform.rotation.eulerAngles = Vector3.MoveTowards(transform.rotation.eulerAngles, startRot, Time.deltaTime * rotateSpeed);
         var distanceBetween : float = Vector3.Distance(transform.rotation.eulerAngles, startRot);
         if(distanceBetween < 0.1) {
             break;
         }
         yield;
     }

Thought about that earlier, then forgot. >.< Still very confused as to why the while loop would end properly when opening the door, just not when closing it... Thank you all though.

Comment
Add comment · 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 fafase · May 15, 2015 at 09:45 AM 0
Share

What is the value fo newRot? $$anonymous$$aybe it turns out to be some round value that converting from Quaternion to euler is not creating any problem. Like some (0,0,0) where the sin of it is a sharp 0.

avatar image
1

Answer by Eric5h5 · May 15, 2015 at 06:54 AM

Comparing floating point values for equality is typically doomed to failure for various technical reasons, so don't do it. Use Lerp instead of MoveTowards.

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 Lylek · May 15, 2015 at 07:11 AM 0
Share

Actually, that is why I used $$anonymous$$oveTowards. Lerp slows down immensely as it approaches its destination, and takes a very long time until it actually reaches the point.

Tried it anyway though, and increased rotateSpeed greatly so the door pretty much fully opens instantly. I get the same problem though. The door opens and closes - but the while loop for closing just doesn't end.

avatar image Eric5h5 · May 15, 2015 at 07:17 AM 0
Share

No, Lerp doesn't do that when used correctly. Lerp stands for Linear intER$$anonymous$$tion and doesn't have any inherent slowdown-at-the-end. http://answers.unity3d.com/questions/14288/can-someone-explain-how-using-timedeltatime-as-t-i.html

avatar image Lylek · May 15, 2015 at 07:43 AM 0
Share

I set the third parameter to 1 (removed Time.deltaTime) and the loop still continues.

avatar image
1

Answer by Dave29483 · May 15, 2015 at 07:06 AM

It seems highly likely that the two values will never be truly equal due to floating point innacuracies. You are still converting back to float when you create a new Vector3 from the 3 Ints.

When comparing floats you always need to use an epsilon value or threshold to determine if the two values are "close enough" rather than equal.

E.g. ( threshold is how many degrees are considered close enough )

 float threshold = 1.0f;
 
 bool isCloseEnough(Vector3 vecA, Vector3 vecB)
 {
     if ( Mathf.Abs( vecB.x - vecA.x ) < threshold &&
     Mathf.Abs( vecB.y - vecA.y ) < threshold &&
     Mathf.Abs( vecB.z - vecA.z ) < threshold )
     {
         return true;
     }
 
     return false;
 }
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
avatar image
1

Answer by Griffo · May 15, 2015 at 08:25 AM

Like Eric5h5 said use Lerp instead ..

 #pragma strict
 
 var openTime : float;
 var openPosition : Vector3;
 
 private var originalRotation : Vector3;
 private var targetRotation : Vector3;
 private var originalTime : float;
 private var originalOpenTime : float;
 private var z : int;
 
 function Update ()
 {
     if (Input.GetKeyDown ("y"))
     {
         RotateObject();
     }
 }
 
 function RotateObject ()
 {
     z = (z % 2) + 1;
     if(z == 1)
     {
         originalRotation = transform.localRotation.eulerAngles;
         targetRotation = transform.localRotation.eulerAngles + openPosition;
         originalOpenTime = openTime;
 
         while (openTime > 0.0f)
         {
             openTime -= Time.deltaTime;
             transform.localRotation.eulerAngles = Vector3.Lerp(targetRotation, originalRotation, openTime / originalOpenTime);
             yield;
         }
         openTime = originalOpenTime;
 
     }else{
 
         originalRotation = transform.localRotation.eulerAngles;
         targetRotation = transform.localRotation.eulerAngles - openPosition;
         originalOpenTime = openTime;
 
         while (openTime > 0.0f)
         {
             openTime -= Time.deltaTime;
             transform.localRotation.eulerAngles = Vector3.Lerp(targetRotation, originalRotation, openTime / originalOpenTime);
             yield;
         }
         openTime = originalOpenTime;
     }
 }
Comment
Add comment · Show 5 · 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 fafase · May 15, 2015 at 08:38 AM 0
Share

Using Lerp or $$anonymous$$oveTowards is not really the issue here. The problem is that the equality is not happening. Lerp or $$anonymous$$oveTowards is just a matter of how the movement should be performed, using a ratio or the remaining distance or using a step value regardless of the remaining distance.

In both cases, the final value will be the exact target with exact same value since it is copied from target to current, including the float inaccuracy. So if you expect 0.0f and it is actually stored as 0.00000001f in target then current will be 0,00000001f (is there enough 0's?) and the comparison will return true.

I often use the code below and it always works for me.

 while (current != target){
      current = Type.$$anonymous$$oveTowards(current, target, step);
      yield return null;
 } 


But I use this for position comparison and I think the inaccuracy here comes from the fact that the rotation is stored as quaternions and requires a calculation to convert to euler angles and that is where the inaccuracy comes in.

So using an approximation to define the target may solve the problem as mentioned in this answer.

avatar image Lylek · May 15, 2015 at 09:10 AM 0
Share

Griffo, this works somewhat, but am getting very strange, obscure rotations. I solved the problem by doing this:

     while(transform.rotation.eulerAngles != startRot) {
         //rotate door
         transform.rotation.eulerAngles = Vector3.$$anonymous$$oveTowards(transform.rotation.eulerAngles, startRot, Time.deltaTime * rotateSpeed);
         var distanceBetween : float = Vector3.Distance(transform.rotation.eulerAngles, startRot);
         if(distanceBetween < 0.1) {
             break;
         }
         yield;
     }

Thank you though.

avatar image fafase · May 15, 2015 at 09:12 AM 0
Share

You should use Quaternion.Lerp/Slerp for your purpose. Those are the appropriate methods for rotation movement.

avatar image Griffo · May 15, 2015 at 09:20 AM 0
Share

I agree with fafase .. you should really use Quaternion.Lerp/Slerp, it looks better, but hey whatever works for me :)

avatar image Lylek · May 15, 2015 at 09:23 AM 0
Share

Ya... that's what I tried to use at first but I was getting see$$anonymous$$gly random rotations.

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

24 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I call a function containing a while loop, inside the update function? 2 Answers

How come my boost comes to an abrupt stop? 1 Answer

Looping a function 1 Answer

How to rotate a object against another 1 Answer

(2d in 3d) Movement relative to camera using JS 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