Looking Left and Right (593016)

Hey guys!

I have had a little controller made for a while and on my development machine it runs perfect. When testing some other features of my game on another one of my machines however it appeared to be having an issue. After a few hours of debugging I was able to figure out exactly what the issue is.

Let me break it down as simple as possible. I have a character that is able to look left and right from different button input. When the character is looking left they rotate -90 degrees. When they press the button again they rotate back 90 degrees. For the right it rotates 90 degrees, then back -90.

I print the value of transform.forward.x to my UI and it shows that when the character has rotated to the left their transform.forward.x equals -1.0 and when they rotate to the right it equals 1.0.. The problem I am having is, on my other computer, when I rotate left it shows -1.0 and everything is fine and good, but when I rotate right it shows 1.0 for a split second then it shows .999999 and because the value is not greater than or equal to 1, the controller ‘freezes’. I made it part of the Input.GetButtonUp conditional that the transform.forward.x be greater than or equal to 1.0..

I will take out some flags and other variables that make it more confusing to parse, but in a nutshell the following is how my controller works.

function Update()
{
if(Input.GetButtonDown("Look Left"))
{
RotateObject(transform.rotation, Quaternion.Euler(transform.rotation.eulerAngles + Vector3.up * -90), 0.8);
}

if(Input.GetButtonUp("Look Left") && transform.forward.x <= -1.0)
{
RotateObject(transform.rotation, Quaternion.Euler(transform.rotation.eulerAngles + Vector3.up * 90), 0.8);
}

if(Input.GetButtonDown("Look Right"))
{
RotateObject(transform.rotation, Quaternion.Euler(transform.rotation.eulerAngles + Vector3.up * 90), 0.8);
}

if(Input.GetButtonUp("Look Right") && transform.forward.x >= 1.0)
{
RotateObject(transform.rotation, Quaternion.Euler(transform.rotation.eulerAngles + Vector3.up * -90), 0.8);
}
}
function RotateObject(startRot: Quaternion, endRot: Quaternion, rotateTime:float)
{
var i:float = 0.0;
var rate:float = 1.0/rotateTime;

while(i < 1.0)
{

i += Time.deltaTime * rate;

transform.rotation = Quaternion.Lerp(startRot, endRot, Mathf.SmoothStep(0.0, 1.0, i));

yield;
}

}

So to recap, the issue is, this code runs perfect on my development machine, but when I try it out on any of my other machines, the transform.forward.x ends up equaling .999999 after a rotation to the right, which effectively locks the controller.

Thanks for any insight or assistance guys! If you need to see more of the flags let me know, but I have a good reason to believe those flags are not to blame.

UPDATE: I had only been executing my code on my development computer via Unity. I executed one of the build.exe’s and it did the same thing. When I look right, the transform.forward.x ends up equaling .99999 instead of 1.0 when I run it in Unity.

UPDATE #2: I was able to fix this.. by setting my Unity to compile an x86 build. For some reason when I compiled this as x86/x64 it was breaking. Setting it to x86 makes it run perfect, just like in the editor. If anyone can hint as to why that might be, that would be awesome! But for now I am content with the results, moderators can remove this thread.

Bump, Update #3

Hey guys! So I was able to solve this by switching the architexture to x86 for my Windows build. Everything runs great now!

I wanted to see if that held true for my Mac build, I tried all 3 options that Unity provides for Mac builds, but none of them work, they all give me the same problem which I created this thread for. As soon as I try to ‘Look Right’ the transform.forward.x goes to .9999999 and nothing works. It does this for my Mac x86, x86_x64 and my Universal builds.

Your lerp may never hit 1 exactly because:

while(i < 1.0)

You probably want <=

1 Like

I am still having the same issue if I set this to <=.

Hm…

I would use RotateTowards. Its much simpler and less likely to result in un-reachable rotations from misuse of lerp

It’s called a float because the value is floaty. You can just put in a small safety net like “if value is greater than .99, value = 1”, but frankly I wouldn’t even trust a direct float assignment to be >= 1 a few picoseconds later. Floats are annoying that way. I think your approach here is a little weird- I think you need to either use the RotateTowards method or simply give yourself a non-limited rotation over time that runs until it passes a threshold, then triggers something else, like rotating back.

I will investigate the RotateTowards method. Would anyone be willing to help me plug that into my current code? It would be very much appreciated.

Using the same method I have been using which is above in this thread, I just changed the Lerp to a RotateTowards but now nothing seems to move very much at all.

//transform.rotation = Quaternion.Lerp(startRot, endRot, Mathf.SmoothStep(0.0, 1.0, i));

transform.rotation = Quaternion.RotateTowards(startRot, endRot, Mathf.SmoothStep(0.0, 1.0, i));

The third parameter is how many degrees per second you want it to rotate, so you will need a value between 1-90

Is that similar to how it was working before with Quaternion.Lerp?

It doesn’t move much at all when I do this:

function RotateObject(startRot: Quaternion, endRot : Quaternion, rotateTime : float)
{
  var i:float = 0.0;
  
  var rate:float = 1.0/rotateTime;
  while(i < 1.0)
  {
  
  i += Time.deltaTime * rate;
  
   //transform.rotation = Quaternion.Lerp(startRot, endRot, Mathf.SmoothStep(0.0, 1.0, i));
   transform.rotation = Quaternion.RotateTowards(startRot, endRot, Mathf.SmoothStep(0.0, 1.0, i));

  yield;
  
  }
}

This is an example of one of my calls:

RotateObject(transform.rotation, Quaternion.Euler(transform.rotation.eulerAngles + Vector3.up * -90), 0.8);

0.8 is too small. start using values that are larger, start with 5 and work your way up to you find a rate you want.

at 0.8, its going to take over 90 seconds to rotate 90 degrees.

at 90, its going to rotate 90 degrees in 1 second.

Lerp is different, lerp wants to give you a target value based on the percentage of completion. most people use this in-correctly and only ever pass in a value of 10% or less (0.1) because they are multiplying by deltatime. I notice you are using it correctly though.

Okay I played around with the 0.8 but it still hardly was budging my character.

Did you want me to be using the Lerp with something other than 0.8? Or the RotateTowards? I tried it with RotateTowards and it does not seem like it wants to move at all after a few pixels.

It’s hardly moving your character because you’re escaping the co-routine after 0.8 seconds. You have to rework all the logic, not just the single line with Lerp.

Are you looking to create a character that rotates 90 degrees per key press?

That is a shame, it would be nice if I could some how use it with my current method to salvage what I already have.

What still doesn’t make any sense to me, is this works perfectly if I compile for x86. As soon as I compile for x86_x64 is when it no longer works.

I suppose another full re-write is in order!

@JamesLeeNZ When the player presses the Left key they spin -90 degrees. Once they have spun -90, they stop spinning. Then when they release the Left key, the spin 90 degrees, effectively spinning them back to facing forward. And same goes with the Right key, except with the Right key they spin 90 degrees to the right, then back -90.

I check for the spin to be complete by checking the transform.forward.x. If the player is facing left the transform.forward.x = -1. If the player is facing right the transform.forward.x = 1… But for some reason when I play this in the 64 bit version, left works perfect but right will only equal .999999

I think something like this should work… untested and in c#.

Quaternion targetRotation;

void Update()
{
    if(Mathf.Abs(Quaternion.Angle(transform.rotation, targetRotation) > 0)
      transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 45 * Time.deltaTime);
    else
    {

    if(Input.GetButtonDown("Look Left"))
          targetRotation = Quaternion.Euler(0,270,0);
    if(Input.GetButtonDown("Look Right"))
          targetRotation = Quaternion.Euler(0,90,0);
    if(Input.GetButtonUp("Look Left") || Input.GetButtonUp("Look Right"))
          targetRotation = Quaternion.Identity;
}
  

}
1 Like

Exactly. This avoids the accumulation of tiny math errors by setting hard global values to the rotational goal- I like it.

1 Like

Okay I am trying this out now.

It does not seem to do anything, also I think you missed a parentheses right before the > 0.

Was this code intended to run assuming the character was already in rotation?

For now, using a combination of new and old code I was able to get around my issue by checking for 0.9999999 instead of 1.0 and that seems to have it working perfectly.

Thanks so much everyone who contributed! It has been greatly appreciated!