Rotation Math help needed!

firemaplegamesfiremaplegames Member Posts: 3,211
edited November -1 in Working with GS (Mac)
Hey all!

I am having a math problem that I hope somebody can help me out with...

I have an Actor that the player can rotate with touch. Imagine a record that a DJ would use to scratch with, or an old iPod touch wheel.
You grab the record and can rotate it either clockwise or counterclockwise.

I have this working great.

What I need to do now is to figure out if I am rotating it clockwise or counterclockwise at any given time.

I basically need a Display Text that always reads either:

"You are currently rotating the record clockwise."
or
"You are currently rotating the record counterclockwise"

Now, the trick is that you won't be lifting your finger. You can tap and hold and rotate the record in either direction as much as you want, and the text needs to always display correctly.

I BELIEVE the answer lies in figuring out the cross product of the vectors:
http://en.wikipedia.org/wiki/Cross_product

But the math escapes me...

If anybody can help me out, I would really appreciate it!

Joe

Comments

  • Rob2Rob2 Member Posts: 2,402
    your using one touch to rotate, like the edge of a disc?
  • stanimationstanimation Member Posts: 406
    It seems like the site you referred to is for 3d (euclidean or x,y,z) space solutions?
  • Rob2Rob2 Member Posts: 2,402
    if you have your actor rotating as you want why cant you keep comparing current to previous rotation and work out direction of rotation from that? I'm probably missing the point completely but the wiki link 'This article is about the cross product of two vectors in three-dimensional Euclidean space' seems a bit over the top:)
  • mrfunkleberrymrfunkleberry Member Posts: 424
    think i've gone down the same path as Rob2 here...

    on mouse down (touch inside)
    timer 0
    if 0 < wheel.rotation-lastRotation then
    direction = clockwise
    otherwise
    direction = anticlockwise
    lastRotation = wheel.rotation

    i have not tested this. It's a bit of a guess, sorry haven't had enough sleep for this. No doubt it will come to be when i close my eyes. :)
  • firemaplegamesfiremaplegames Member Posts: 3,211
    @rob2: yes, you can click anywhere on the actor and rotate it. I guess an old iPod click wheel is the best example.

    @stanimation: I believe somewhere on that page it describes 2D plane vectors, but by that point, blood was dripping out of my ears!
  • firemaplegamesfiremaplegames Member Posts: 3,211
    @rob2 and mrfunkleberry: yeah, I think I will just go with the timer like you suggested. I was trying to be all tricky!
  • stanimationstanimation Member Posts: 406
    haha yea I just wanted to say Euclidean. Kind of erotic. I asked a math guy here at work. He just made my head really hurt.
  • mrfunkleberrymrfunkleberry Member Posts: 424
    Yeah i'm sure there's a nice non timer based solution. Just can't think how you'd get around not making a time based comparison... oh how about.... na... it'll come to me.
  • firemaplegamesfiremaplegames Member Posts: 3,211
    it's also a little tricky, even with a timer, because the angles keep going from 0-360,0-360, etc...
    (you can keep rotating the disc around and around... in either direction)

    I read somewhere that you can always tell the direction of rotation of an object by using the cross product and was oping that I could plug in a math formula...
  • mrfunkleberrymrfunkleberry Member Posts: 424
    You can stick in a rule

    if abs(wheel.rotation-lastRotation) > 259 then... etc etc

    But there HAS to be a better way.
  • firemaplegamesfiremaplegames Member Posts: 3,211
    I have posted a demo of the rotation code that I have so far...

    http://gamesalad.com/game/play/58254

    Feel free to dig through it. It's just one actor.

    I stripped out all the code that I was noodling with for the past few hours, so it is clean...

    And yeah, if anybody can figure out how to tell if I am rotating the disc clockwise or counterclockwise at any given moment, that would really help me. I've been fiddling with this too long and my eyes are glazing over...
  • adadoadado Member Posts: 219
    Don't recall my vector math too well but I believe this operation would require two vectors. One represented by X/Y of the dial out to the X/Y of the touch (or mouse down in your example). Then the other would be based on a continual (or near continual) tracking of the current touch X/Y position and a previous touch X/Y position. The problem with that is you need to periodically sample and store a previous touch X/Y position. Even if your sample rate is really, really quick, you could still have a reversal of rotation by the user in between samples that may or may not yield a false rotation readout for a brief period of time.

    There are a couple other methods that could be used that involve sampling values and then using some nested rule logic to determine the rotation direction. However, these are more susceptible to quick false readout flashed too. Once such would be a rule using the difference between touch X and previous touch X and then nested rules for both the true/false results that then use the difference between touch Y and previous touch Y. I don't really recommend it. Another would be the sampling of the dial's rotation as others have suggested, but then you get false readout flashes when you go from 0 to 360 and also from 360 to 0 [or 180 to -180 and -180 to 180 if using an angle from "vectorToAngle()].

    I think a way around the sampling issue would be to have an invisible actor constrained somewhere along the outer edge of the dial (or even further out would work) using the sin/cos "circle movement" method. Instead of using the "timer" for the rotation, you would use the rotation of the dial. You would then get your first vector from the center of the dial out to the center of the invisible actor. Then your second vector would be from the center of the invisible actor to the touch. This would give you constrainable values for both vectors.

    The vector from the invisible actor to the touch *may* need a ruleset around it depending on the relative position of one to another but I'm thinking not. :-| That *may* also hold true in the touch sampling method too.

    "magnitude()" can give you a vector's magnitude.

    "vectorToAngle()" gives you the rotation angle of the vector but not direction of the vector. I think you can compute the direction with the Y coordinate difference divided by the X coordinate difference (think "rise over run" of a line -> `y = mx + b` where "`m`" is "rise over run") but I am not 100% on this fact.

    After you get your vectors, if you compute a cross product on them, you will need to leave any z coordinate values at zero. Doing this then will give you a counter-clockwise rotation when the cross product is positive and a clockwise rotation when the cross product is negative.

    Now if anyone who can remember vector mathematics can chime in to help with that!!! It's been decades since I have done any of that. :-( Sorry I couldn't close the deal!

    Would be nice if GS folks added some basic vector functions based on (x, y) coordinate inputs and even (x, y, z) coordinate inputs as we could always leave "z" at zero since things like cross product are three dimension based.
  • adadoadado Member Posts: 219
    adado said:
    The vector from the invisible actor to the touch *may* need a ruleset around it depending on the relative position of one to another but I'm thinking not. :-| That *may* also hold true in the touch sampling method too.

    I think the above may actually be the case. Play around with the real-time visualizer tool at the bottom of the web page in the following link. Make the positive z axis point straight up and the plane the vectors make be parallel with the x/y plane. Then as you move the endpoints of one vector, you will see the area of the parallelogram made by the vectors change from blue (a positive dot product) to gray (a negative dot product) based on the relative position of one vector to another (i.e. the "right hand rule" where the thumb points in the direction of the cross product of the vectors...they mention the rule at the top of that page):

    http://www.math.umn.edu/~nykamp/m2374/readings/crossprod/

    The positive/negative aspect of the dot product appears to toggle at a 180 degree split of a circle centered on the plane at the origin.

    -----

    Also, for general vector reference, this is a pretty good page:

    http://www.uib.no/med/avd/miapr/arvid/MOD3/Bildematematikk/vectors_nmt.pdf

    Edit: Re-did the first part a bit.
  • firemaplegamesfiremaplegames Member Posts: 3,211
    Thanks, I will dig into it!
  • adadoadado Member Posts: 219
    Mainly documenting my findings in this thread as I had a need for this as well but didn't want to re-learn vector math. Getting closer but need to hit the hay.

    Share you solution if you find one!
  • adadoadado Member Posts: 219
    I don't think the cross product gets you anything more than we got already (just a slightly different form of what we have)!!? :-( I think I have the math down and the "right hand thumb" rule does indeed pan out based on the vectors of two points.

    However, it all comes down to where the user clicks relative to another point - the other point moving or otherwise. They could click in one area that makes the thumb rule evaluate to positive (i.e. counterclockwise) and rotate counterclockwise for a bit with the rule holding true. However, they can then reverse the direction (clockwise) and since the thumb rule still holds true, it evaluates to positive even though they are now going clockwise.

    The reason being, the vectors stay relative to each other throughout the mouse/touch move keeping the thumb rule consistent - that is until they rotate 180 and the relationship to each other is reversed (reversing the thumb rule). So basically you something akin to the "vectorToAngle()" value when applied to the actor's X/Y and the touch/mouse X/Y.

    Hard to explain. I don't think it is going to work.

    Will probably need to do the sampling thing and live with a brief incorrect report of the direction as stated above in my long post (i.e. the "flash"). You can minimize it by having the sample period very small/short and use real instead of integers to allow finer comparing between the current rotation and the previous sampled rotation. Although the integer vs. real is mainly if the user tries to "fine tune" the rotation on a large dial. It won't matter for large arc movements and/or small dials.

    Grr!

    If anyone can work this out, feel free. Pretty sure I am correct but it is still a tad hazy from lack of use over the years so you never know.
  • firemaplegamesfiremaplegames Member Posts: 3,211
    In the end, I decided to go with the Timer approach. This isn't a large enough part of the game to warrant spending this much time on..

    I ALMOST have it completely working. It now works consistently except where it switches from 0 to 360 and vice-versa. I get a momentary blip where it shows the opposite direction.

    I'll dig into this again in the morning.
  • Rob2Rob2 Member Posts: 2,402
    Thanks very much for posting that, I had done it with just one constrain so there was a nasty jump on touching, concise and to the point, but butt ugly :) If I come up with anything neat for the notification I will post, but you may also win the lottery:)
  • jmp909jmp909 Member Posts: 73
    i believe i've solved this thanks to someone from #actionscript IRC.
    http://gamesalad.com/game/play/58443

    i'm replicating this function to get the angle difference between the current angle and the last one

    private function angleDifference(a1:Number, a2:Number):Number {
    var angle:Number = a1-a2;
    if (Math.abs(angle) > Math.PI) {
    angle = angle > 0 ? angle-Math.PI*2 : Math.PI*2+angle;
    }
    return angle;
    }

    there's still a problem when the wheel crosses 0 angle, so i just check the diff is > -270 and < 270 etc

    maybe this is actually just a more complicated version of what mrfunkleberry suggested anyway... i'll compare the two

    j
  • firemaplegamesfiremaplegames Member Posts: 3,211
    Hey jmp909!

    Thanks for making that! I appreciate all the help!

    I just figured it myself a few minutes ago...

    I am actually making an old combination lock for a safe in my new game. You have to turn the dial Right-Left-Right to specific numbers to open the lock.

    I now have it all working correctly. You can now open the safe!

    I am pretty much doing that exact function as you have above. I am a Flash programmer too, so I always look at Actionscript code first when I am trying to figure something out!

    Again, I appreciate the time!

    Joe
  • jmp909jmp909 Member Posts: 73
    seems i don't need any of that stuff

    you can just use game.diffangle = game.lastangle - self.Rotation as suggested previously

    i don't use any timers though..

    download here
    http://gamesalad.com/game/play/58447
  • firemaplegamesfiremaplegames Member Posts: 3,211
    Oooh, that's interesting!

    I need to check out how you are capturing lastangle without a Timer...

    Thanks!!!
  • jmp909jmp909 Member Posts: 73
    how did that function help then? i'm not sure. both my versions seem to work the same. I think in actionscript the angle could be eg -400 so that function is needed to normalize the values. but in GS the only possible angles for rotation i believe are 0-359 anyway.

    I'd be interested to see how you've used it anyway

    j
  • jmp909jmp909 Member Posts: 73
    lastangle is just constrained after i've constrained diffangle.

    does constrain cause performance issues? surely no more than timer though. I'm new to gamesalad so i'm just doing whatever seems to work :)
  • firemaplegamesfiremaplegames Member Posts: 3,211
    Ok, cool.

    The stacking order in a Rule USUALLY happens from the top down, but sometimes certain behaviors will execute first. Just something to watch out for...

    Both Constrains and Timers are resource hogs, but since they are only happening when the mouse is down, it's not so bad.

    Plus, in this case you have to use them, so it doesn't really matter.

    Yes, like Flash, doing whatever seems to work is often the best strategy with GameSalad!
  • adadoadado Member Posts: 219
    Good job guys. A "spin" on the sampling (i.e. constant) method. :-)

    Yeah, the only problem I see with jmp909's last "simpler" solution is what FMG alludes to in his post above this one:

    "The stacking order in a Rule USUALLY happens from the top down, but sometimes certain behaviors will execute first. Just something to watch out for..."

    They *usually* execute top down and they almost always execute entirely at a given logic or nest level. However, as your scene gets more and more complex, time sensitive things can start to break down so you may find you end up having to insert a timer in there and/or re-organize the order of the behaviors.

    So if something you made early on in a project starts to work less as your scene gets more complex, it may be a performance thing.

    Just something to watch out for as Joe mentions.
Sign In or Register to comment.