Be an Angel fix my Angle. Stop rotating the long way round to a given angle?
Ok, so I'm at work at the moment and not able to carry on testing this, but if anyone knows the way to solve my problem then I can be super productive tonight...
The Problem:
I've setup the actor to rotate to the angle of the destination its travelling to. I get the angle correctly and it all looks as if its working fine. Though if I click a certain direction the angle must go from something like 270 to 10, and instead of rotating the shorter path, it spins back round the long way, which just looks a bit stupid.
What I've got setup for rotate to angle:
I've got an actor who moves to touch. (there is a camera offset setup to keep touch working properly as the scene is larger than the viewer window).
Interpolate to angle over a set duration (1 second).
I find the angle by:
Change attribute: ...self.angle..... to .....'vector to angle(game.touch x with offset - self.position X, game.touch Y with offset - selp.position Y).
Then an extra rule to try and stop the crazyness....
if... self.angle is less than or equal to 0
change attribute:...self angle to self.angle +360
............
thanks for any help in advance..
Note** I want to use interpolate, not 'rotate to angle', as its nicer...
Edit** I'm sure I've read something about this before in the forum but can't think where or what to search for...
The Problem:
I've setup the actor to rotate to the angle of the destination its travelling to. I get the angle correctly and it all looks as if its working fine. Though if I click a certain direction the angle must go from something like 270 to 10, and instead of rotating the shorter path, it spins back round the long way, which just looks a bit stupid.
What I've got setup for rotate to angle:
I've got an actor who moves to touch. (there is a camera offset setup to keep touch working properly as the scene is larger than the viewer window).
Interpolate to angle over a set duration (1 second).
I find the angle by:
Change attribute: ...self.angle..... to .....'vector to angle(game.touch x with offset - self.position X, game.touch Y with offset - selp.position Y).
Then an extra rule to try and stop the crazyness....
if... self.angle is less than or equal to 0
change attribute:...self angle to self.angle +360
............
thanks for any help in advance..
Note** I want to use interpolate, not 'rotate to angle', as its nicer...
Edit** I'm sure I've read something about this before in the forum but can't think where or what to search for...
Comments
Take a look at my TOTB3 entry video; (Minutes 1:50 and 3:20)
Is that what you want? To actor to rotate the "shortest" angle?
@CBT.... is it interpolating to the angle in your video, looks like the angle changes instantly?
Here is how I just did it. (You experts can tell me if its a kludgy fix for what should be a simple problem.)
In the prototype, make two new attributes:
oldRotation (real)
difference (real)
Next add the following behaviors:
Change Attribute: self.oldRotation To: self.Rotation
When actor receives event (mouse button is down)
....Change Attribute: self.difference To: self.Rotation-vectorToAngle( game.Mouse.Position.X - self.Position.X , game.Mouse.Position.Y - self.Position.Y )
....When self.difference < -180
........Change Attribute: self.difference To: self.difference+360
....When self.difference >180
........Change Attribute: self.difference To: self.difference -360
....Interpolate Attribute: self.Rotation To: self.oldRotation - self.difference
....Change Attribute: self.oldRotation To: self.Rotation
It seems to work OK. The two If's (um... Whens) could probably be redone with some fancy min,max formula stuff. Lets leave that stuff to the mathematically minded.
90 degrees
270 degrees
360 degrees
180 degrees
0 degrees
180 degrees
90 degrees
-90 degrees
Just experiment with those. If you are trying to get to 0 degrees the other way, use 360 degrees. If you have any more questions just email me. Cameron_reynoldson@yahoo.com
I can send you what they are.
Just interpolate the rotation. and you have to set it up like this
If self rotation = this, rotate to that. And do that for all of them.
Thanks for honouring me with your first post. Much appreciated.
At John/dreamlab. Thanks but with angle changing I needed a rule that varied depending if it was less or more than 180 degrees of current angle.
Currently stuck in traffic.
What I've ended up with:
Firstly and most importantly:
I needed to change my 'self.angle' attribute to a real number not an 'angle' as it seems if its an angle you are limited to 0 to 360 and can't have negative numbers.
Working on the same principle posted by RThurman but tweaked a bit and reduced the needed number of attributes.
My winning setup is:(Bare in mind this is for a scene with a camera offset)
I have created one attribute:
self.angle (which is to save the desired angle to turn to)
Find the angle to turn to with,
Change Attribute:
self.angle to vectorToAngle( game.touch X with offset - self.Position.X , game.touch Y with offset - self.Position.Y )
stop spinning round the long way counter clockwise,
if:
self.Rotation < self.angle-180
change attribute:
self.angle to self.angle-360
stop spinning round the long way clockwise,
self.Rotation > self.angle+180
change attribute:
self.angle to self.angle+360
Interpolate actor to face new angle,
self.Rotation to self.angle
duration 0.5
.......
Thanks again...and I hope this post is of use to someone...
- Alex
http://gamesalad.com/forums/topic.php?id=13706
to see what the work has been for... (a new top down viewpoint for my Dark Asylum game)
I believe it is also possible to get rid of the two "if's" by using the modulo operator in a single formula. But I can't quite figure out the math.... yet. It involves getting the modulo operator to return the sign (+ or -) of the result. It would be nice if anyone can figure that out.
This site explains how it works pretty good for a non math guy like me:
http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the-sign
This will calculate the difference between angles where one angle is for example 5 degrees and one 355 degrees. Normally you would get a difference of 350 degrees instead of 10degrees which would be wrong. (Or as Stormy puts it: stop spinning round the long way counter clockwise)
In Shell Ops I want my crab to never tun more then 90 degrees as well. Because it walks sideways. When the crab is in 'neutral' position so 0 degrees it all goes well when you click on the right of this crab because the difference between the initial angle (0 degrees) and the angle to turn to is less then 90 degrees. When it is more then 90 degrees, so when you click on the left of the crab it will turn more then 90 degrees which is unwanted because it a crab walk sideways to the left as well. What I did to prevent this is to build a rule: when angle is >90 then angle is angle - 180.
There are some rules in there that I have used as a timer-like thingy to make sure the rules only apply when the values have been taken from the current positions. Sometimes my crab still turns more then 90 degrees. When I read the code it should never happen if any one knows why please let me know.
Hope my Dunglish makes sense. I will ad some screenshots from Shell Ops code to clarify...
Let me know if I need to explain it better.
(please someone help me get this image in the story instead of links
http://farm7.static.flickr.com/6017/5964236590_62b473a585_b.jpg
This is how it works now:
Lump Apps and My Assets
Thanks for sharing...not entirely sure what your doing wrong...check your numbers are all 'real' numbers.
But looking through your rules it all looks like it should work, and that your crab should only move once it has reached the previous rotation angle...
...anyone else see where its going wrong...
feel free to send it over if you want me to take a look in person..
You have the if
OK -- I've got two solutions that are functionally equivalent.
First, as far as I can tell, GameSalad's modulo function (the % operator) returns the sign of the second number and not the first. But for this purpose, we need the modulo operator to return the sign of the first number. (Some languages do it one way, and some do it the other.) So… I wrote my own modulo operator (NOT FUN). It goes like this in a change attribute behavior:
Change Attribute: differenceAngle To: differenceAngle-(360*(ceil((floor((differenceAngle/360)*2))/2)))
The attribute "differenceAngle" is the difference between an actlor's current rotation and the angle of the mouse click. Just put the same number in both places where it says "differenceAngle". Thats all you gotta do.
This gives you an angle that is positive for touches (or clicks) that are on the 'left' of the object -- and gives you an angle that is negative for touches that are on the 'right' of the object.
Now all you have to do is set the rotation of the object to its current rotation plus the "differenceAngle". Because the differenceAngle now has the correct sign, the rotation will move left or right depending on it being a positive or negative angle. (You can use "Rotate to Angle" or "Interpolate")
But wait -- there's more!
Just a few short minutes ago, LudgwigHeijden posted a website that he used to come up with his solution. The comment section of that site shows yet another way of doing this. (It is comment #7 by tk) As soon as I saw this I realized it would work with the GameSalad modulo operator. In GameSalad it goes like this:
Change Attribute: differenceAngle To: (( differenceAngle +180)%360)-180
And it works!
Now, I don't know about you -- but I like formulas with a lot less parentheses and a fewer parts. So… even though I sweated bullets creating my own modulo operator, I'm still opting for Ludwig's (er… tk's) shorter, sweeter, more 'fun' solution.
I've tested both solutions with attributes of type 'real' and type 'angle'. I'd suggest using reals -- they seem to give more predictable results.
amazing...
amazing..
I'm amazed..
Cheers so much for sharing
A m a z i n g !
Lump Apps and My Assets
Even the foray into modulo math was useful. At least it helped me recognize the correct formula when presented (which I wouldn't have done without trying to roll my own.)
Its not all altruistic, of course. I've been trying to figure it out so that I can get an actor to spin. I'm prototyping an interactive storybook in GameSalad for my daughter. In one of her illustrations, she has two pictures hanging on a wall. The pictures need to 1)spin when flicked, 2)rotate when slowly dragged, and/or 3)swing to remain pointed "down" when the iPad changes orientation -- your basic pendulum. Having the pictures go backwards and act weird when hitting the 0-360 boundary was a little frustrating. So I am glad that part is done.
Here is a url of the illustration:
http://2.bp.blogspot.com/--ShBCtGrDgk/TfRJQoo52OI/AAAAAAAADI4/sTBFuq2AZZw/s1600/page1.jpg
By the way she is an illustrator and does do ios art on contract. Here is her portfolio URL:
http://artoferintaylor.blogspot.com/
Ahem…. shameless "parental" plug aside…. I am learning lots about GameSalad. So its a fun little adventure. The next trick will be to get the pictures to swing "down" as the device changes orientations. That means I will need to simulate gravity via the accelerometers. Then comes the issue of simulating a pendulum that obeys the laws of 'gravity'. Then comes the fun part of figuring out how to rotate actors from any any arbitrary point (not just the center). But lets save that for another thread!
I will have a look at your daughters artwork now
Lump Apps and My Assets
Lump Apps and My Assets
Thanks again!
Please post if you get the "flipping" better.
Cheers!
Lump Apps and My Assets
((((( self.currentangle + self.differenceangle +180)%360)-180)+90)%180)-90
Hèhè, more brackets as you asked for
I have this formula in the rotate to angle attribute.
The attribute "differenceAngle" is the difference between an actlor's current rotation and the angle of the mouse click.
The actor has to turn from its current angle to this angle so that is why there is a + current.angle
Else the actor would turn from its zero angle.
To make sure the Actor never turns more then 90 degrees (se my video above) I took your modulus and converted it to 90 degrees instead of 180.
What it does:
angle + 90
modulate to 180
and then subtract 90
Example: An angle below 90: 89
89+90 = 179
179 modulate 180 = 179
179-90 = 89 (correct the angle is below 90 so stays what it is)
Example: An angle above 90: 91
91+90 = 181
181 modulate 180 = 1
1-90 = -89 (correct, the actor now rotates with the shortest angle!)
I still have the same problems as before that it sometimes takes the longest angle.
But I found out why: my gametouchx and y attributes are integers! (Thanks Stormy for pointing that out!!)
I have to change this but I use it on more occasions so this will take me some time (Why can't I just make an integer real and vise versa).
Cheers!
Ludwig
Lump Apps and My Assets
Great that you got it working!
I see that your challenge was slightly different than Stormy's. He was looking for rotating only one 'end'. But you wanted to rotate toward opposite ends. (Whichever provided the shortest rotation to point at the mouse click.) You defined shortest by if the difference angle was greater than 90 degrees (in either the positive or negative direction). That's pretty cool!
Here is a slightly different approach, but in the end it probably does the same as yours:
Change Attribute: self.differenceAngle = self.clickAngle - self.Rotation
Change Attribute: self.differenceAngle = (( self.differenceAngle +180)%360)-180
Change Attribute: self.diferenceAngle = self.differenceAngle +180*floor(abs( self.differenceAngle )/90)
Rotate to Angle: self.Rotation + self.differenceAngle
The third Change Attribute behavior was just to add 180 if the difference angle is greater than 90 degrees. The "floor(abs( self.differenceAngle )/90)" part was just a mathematical way of saying "if the absolute value of self.diffenenceAngle is greater than 90"
Or -- I suppose if you want to combine all the operations into one behavior:
Rotate to Angle: self.Rotation +(( self.differenceReal +180)%360)-180+180*floor(abs((( self.differenceReal +180)%360)-180)/90)
I better test it out to see if it works .....
Yup -- it does work. But I had to change it slightly. I could not get it to rotate on itself (couldn't get it to use self.Rotation). So I had to create an oldRotation (real) attribute that contains the updated angle. So it ended up looking like this:
Rotate to Angle: self.oldRotation +(( self.differenceReal +180)%360)-180+180*floor(abs((( self.differenceReal +180)%360)-180)/90)
Hey do I win the "who can use the most parentheses" contest?
Indeed you can't use the self.rotation because it changes during the rotation.
(((nice)(work));)
Lump Apps and My Assets