Be an Angel fix my Angle. Stop rotating the long way round to a given angle?

StormyStudioStormyStudio United KingdomMember Posts: 3,989
edited November -1 in Working with GS (Mac)
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...
«1

Comments

  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    (BUMP) anybody?
  • JohnPapiomitisJohnPapiomitis Member Posts: 6,256
    have you tried interpolating the rotation to -the angle? Im pretty sure having the - will rotate it the other way. Im not 100% sure but its worth a try :)
  • DreamLabDreamLab Member Posts: 2,127
    Yah do what john said. Like say you wanted it to go to 90 degrees. Make it -90 degrees. And if you want it to rotate to 0, try 360, that always works. I remember a while back dealing with this stuff.
  • cbtcbt Member Posts: 644
    Hi there Stormy,

    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?
  • GamersRejoiceGamersRejoice Member Posts: 817
    I've run into this problem too and would love to know the answer. As far as I could tell I couldn't trick interpolate to do what I wanted.
  • osucowboy18osucowboy18 Member Posts: 1,307
    GamersRejoice said:
    I've run into this problem too and would love to know the answer. As far as I could tell I couldn't trick interpolate to do what I wanted.

    +1. Any advice on this would be helpful :)
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    gonna give it another go now...

    @CBT.... is it interpolating to the angle in your video, looks like the angle changes instantly?
  • JohnPapiomitisJohnPapiomitis Member Posts: 6,256
    yeah try out my method and let me know how it is. I know that works for a fact, just not sure itll work for what you doing.
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    My first post!

    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.
  • DreamLabDreamLab Member Posts: 2,127
    Well me and johns way works. Here are the angles I used.

    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.
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    Thanks rthurman that looks right for what I want.

    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.
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    SUCCESS... many thanks everyone...

    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...
  • GamersRejoiceGamersRejoice Member Posts: 817
    Nice! Thanks for sharing.
  • osucowboy18osucowboy18 Member Posts: 1,307
    Good to know this can be done! Thanks for sharing this info guys :)

    - Alex
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    Cheers guys... check out my latest post over at
    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)
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    stormystudio said:
    SUCCESS... many thanks everyone...

    I am glad it worked for you (in principle at least).

    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.
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    yeah, if there's anyway to simplify it further that would be great
  • LumpAppsLumpApps Member Posts: 2,880
    I used this in Shell Ops (TOTB3) the same way you use this now.
    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:
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    Hey Ludwig

    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
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    Ah… Sweet Mystery of Life, At Last I've Found Thee!

    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.
  • StormyStudioStormyStudio United KingdomMember Posts: 3,989
    amazing...

    amazing...

    amazing..

    I'm amazed..

    Cheers so much for sharing
  • LumpAppsLumpApps Member Posts: 2,880
    Wow! I'll try that 1st thing tomorrow morning.
    A m a z i n g ! ;)
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    Glad to help!

    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!
  • LumpAppsLumpApps Member Posts: 2,880
    For the pendulum part. There is an example available which is almost good. Do a search in the gamesalad application. I believe it is named swing example or something. I have it working in my next update for Kung Fu Finger with the accelerometer. The only thing I couldn't get fixed is that they start at upside down when the level starts.
    I will have a look at your daughters artwork now ;)
  • LumpAppsLumpApps Member Posts: 2,880
    Wow! Your daughter has skills!!!
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    LudwigHeijden said:
    For the pendulum part. There is an example available which is almost good. Do a search in the gamesalad application. I believe it is named swing example or something. I have it working in my next update for Kung Fu Finger with the accelerometer. The only thing I couldn't get fixed is that they start at upside down when the level starts.

    Thanks! I found one called "Hanging/Swinging DEMO" by Fire Maple Games. Is that the one? It is a great example to start with. (It starts with stuff flipping wildly, as you intimated, but settles down pretty quickly.) I will study it for a bit, but I can already see that it has all the right ingredients for the kind of pendulum I need to simulate.

    Thanks again!
  • LumpAppsLumpApps Member Posts: 2,880
    That is what I ment.
    Please post if you get the "flipping" better.

    Cheers!
  • LumpAppsLumpApps Member Posts: 2,880
    RThurman said:
    ...

    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.

    ...

    Okay, here we go:

    ((((( 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
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    @ Ludwig

    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?
  • LumpAppsLumpApps Member Posts: 2,880
    Lol!

    Indeed you can't use the self.rotation because it changes during the rotation.

    (((nice)(work));)
Sign In or Register to comment.