So I’ve figured out that the bug in my code lies in this line
“if (angle1 > 87 || angle1 < 93)”
It’s supposed to “snap” the rotation angle of my object to a certain direction once it angles itself close enough to said direction, but currently it will do this no matter the angle.
angle1 is set to
“angle1 = transform.rotation.z;” in void Start.
Any ideas?
Extra info if helpful: I tried making it if (angle1 > 87) but instead of snapping no matter what angle, it won’t snap no matter what angle. I kept experimenting and found that somewhere between if (angle1 > .7) and if (angle1 > .8) there is a crossing point. > .8 results in no snap whatsoever, and > .7 results in a snap at all angles. This is just bizarre to me, but I’m very new so I’m probably missing some sort of measurement translation or something, I’ve honestly got no clue. Any help clearing up this issue would be greatly appreciated!
Look at what you’ve written there very carefully. “Be the computer,” as they say, and interpret it very literally as we try a few examples.
Let’s take 89. Is 89 > 87 or < 93? Yes (in fact it’s both.)
How about 42? Is 42 > 87 or < 93? Yes (it’s < 93).
How about 123? Is that > 87 or < 93? Yes (it’s > 87).
In fact any number is either greater than 87, or less than 93 (or both). So, that’s why it snaps all values to that.
I think you meant to say “and” rather than “or” (or in C# syntax, && rather than ||).
But note that when you start doing this for other angles, you’re likely to run into some grief around 180 and/or zero… you might consider using Mathf.DeltaAngle instead.
Funny that’s there actually, I caught that mistake earlier, I don’t know why it’s still there. Anyway, even after changing it it will still snap no matter what. See any other possiblities?
I see you assigning to angle1 in Start. But I don’t see you ever changing it.
Probably you should restructure your code this way:
If A is pressed, reduce angle1 by some amount (like 60 * Time.deltaTime, so it’s frame-rate independent).
If D is pressed, increase angle1 by some amount.
If it’s close to 90, set the rotation to exactly 90; otherwise, set the rotation to whatever angle1 is.
Note that it’s always a good idea, especially as a beginner, to write your idea out like this first, in plain English, before you go try to write code. If you can’t clearly explain your idea, there’s not much hope of coding it.
Thanks that did the trick! I just inserted angle1 = transform.rotation.eulerAngles.z; after the A and D if functions and it works perfectly, wish I had caught that sooner but it makes perfect sense.
That’s not what I suggested, and I don’t recommend it, even if it happens to work in this case.
What you must understand is that a rotation (orientation) is not really Euler X, Y, and Z angles. When you ask for the eulerAngles, they are being constructed out of the true rotation (which is represented as a Quaternion). And the values that you get are not always what you expect. Sooner or later, if you’re working with 3D rotations and doing something with these eulerAngle values, it’s going to bite you.
Instead, what you should do is keep your own angle values, update these, and then use them to assign a rotation. To quote myself:
This will always work, not just sometimes happen to work.
Note that if you’re working in a strictly 2D game, and never rotate around anything other than Z, then you’ll be OK reading rotation.eulerAngles.Z. But in any 3D case, it’s a recipe for trouble. So the rule of thumb is: never read from rotation.eulerAngles except for debugging purposes; only assign it new values.
It is a 2D game, but I would still like to understand how to work with both Euler and Quaternion angles, which I’ll have to know eventually. I’ve been messing around with what you said but I’m not sure how I’m supposed to program it.
If I set angle1 = transform.eulerAngles.z, then say if W is pressed then make angle1 = (what should I put here), then does it update transform.eulerAngles.z indirectly? I just don’t fully understand what you’re saying I think.
RE: JoeStrout and eulerAngles.z not being reliable:
The short version is that using rotation.eulerAngles.z is a hack which will only work for certain simple cases. I think it’s fine for 2D, when x and y rotations are always 0. Like all hacks, test it for every angle you will ever need, and if it works, use it, since it’s simple.
Just know that for some ways of spinning yourself, mostly 3D, it completely breaks. eulerAngles.z will “randomly” change as you rotate. But now that you know it was just a shortcut trick, you won’t think Unity is broken. You just have to learn a better trick. My long explanation is at taxesforcatses-dot-com (Movement/Rotation section, chapter labelled Rotation, section 4 “Quaternions”.) But, like JoeStrout wrote, it’s complicated.
One neat trick is using transform.up (or transform.forward, and so on.) If transform.forward is (0,0,1), you’re facing perfectly along +z. If transform.forward.z>0.98f, you’re facing very close to perfectly along +z.
I’m saying, never read from transform.rotation.eulerAngles. Ever. When you find yourself doing that, stop and reconsider.
So what do you do instead? You keep track of the angle you want in your own field (angle1 in your case). You add to that. You subtract from it. You compare it to things. You do whatever you want to with it.
And then, at the end of your Update loop, you use that angle field to set the rotation:
No, this doesn’t happen automatically. It happens when you do it. But that’s OK — your own angle1 field isn’t going to do anything wonky; it’s just a number that keeps whatever value you give it. Rotations are more squirrely than that, but it’s OK, because with this trick you’re never reading the rotation values. You’re only assigning them.
But @Owen-Reynolds is quite right; it’s OK to read the Z value in the 2D case. It’ll work. But for the future, and since you were 95% of the way there already, you might want to just adopt the habit of never reading these values. It’ll save you grief in the long run.