Hi there! I'm trying to have an action trigger whenever an object rotates 360 degrees in 2 seconds.
Simple enough, I imagined, just store the current angle for 2 seconds and check whether it has increased or decreased by 360 compared to the oldest stored value every tick. However, the Sprite.Angle function resets the value back to 0 after reaching 360, instead of continuing as the Angle value does in the Debug Mode.
I failed to find a way to get the object's 'absolute' angle, as in, if they had started at zero and rotated 360 degrees clockwise twice, it would return '720'. Is there one? If not, has anyone succeeded at detecting when an object rotates 360 degrees - regardless of the initial position - in another fashion?
Thanks in advance!
(Edit) I just checked the System >> "angleDiff" expression, and it always gives a zero or positive answer, meaning it doesn't give you the direction of the change in the angle, so it won't work here.
One possible approach is to calculate the change in angle between ticks,
store that change in a running total,
and track that running total instead of tracking the objects rotation property directly.
Here is a formula that will give you the change in angle as the shortest CW or CCW rotation, and it works seamlessly across the 360-to-0 transition.
angle_delta = ( ( ( a - b ) + 180 ) - floor( ( ( a - b ) + 180 ) / 360 ) * 360 ) - 180
Where a and b are your two angles.
a = 5, b = 355: ... ( ( ( 5 - 355 ) + 180 ) - floor( ( ( 5 - 355 ) + 180 ) / 360 ) * 360 ) - 180 355: ... = 10
a = 355, b = 5: ... ( ( ( 355 - 5 ) + 180 ) - floor( ( ( 355 - 5 ) + 180 ) / 360 ) * 360 ) - 180 355: ... = -10
Remember, if you compare two angles with a difference greater than 180 degrees, the angles will be treated as a shorter rotation in the opposite direction.
e.g. A raw difference of +270 is treated as -90.
As long as the total distance rotated per tick is less than 180 degrees that shouldn't be a problem though.
So, to use this in place of directly tracking the object's angle property, you can do the following:
Create a custom variable "unwrapped_angle".
Every tick, get the change in angle between ticks, angle_delta( currentAngle , angleRecordedLastTick ), and add it to "unwrapped_angle".
Then you should be able to use the unwrapped_angle in place of the objects built-in angle property.
Thanks, fisholith! The mathematics behind your formula are somewhat beyond me, but it works flawlessly.
Inspired by your well-written, color-coded explanation, I made a simple commented project that uses your method, in case anyone stumbles here in search of the same thing I was looking for. Not very clean and surely not the best way to apply it, as I'm not very familiar with this stuff yet, but it should be enough for anyone who wishes to achieve this effect.
Develop games in your browser. Powerful, performant & highly capable.
Glad I could help out.
I built an example as well, though it only shows the process of calculating the unwrapped angle.
I'm afraid it doesn't apply it to a gloriously cucumber rotating cause.
I checked out the cucumber example. Very cool, as one might expect a cucumber to be.
Using System > Wait to time travel
One way to compare the current unwrapedAngle against the 2 seconds old unwrapedAngle is to:
That should make unwrapedAngleOld continuously play back the unwrapedAngle values from 2 seconds ago.
I have no idea how optimal this is, but I've never seen a performance hit. Granted I'm using a desktop, and it might be a different story on a mobile device.
Angle delta math
As for the mathematics behind the angle_delta formula from my previous post, I can hopefully simplify it a bit.
In my prior post I wrote it out as:
The reason it looks so awful is that the formula contains a mod() function, which I've written out long hand.
Here is the formula as it appears if you have an appropriate mod() function available:
mod( ( a , b ) + 180 , 360 ) - 180
Unfortunatly you don't have the appropriate mod() function in C2 by default, and that's why I wrote it out in expanded ugly form.
(Further explained in "C2's modulus" section below.)
That mod formula I'm using above has the following behavior:
mod( val , div ) ... = ... val - ( floor( val / div ) * div )
This is a "floored division" style mod.
Terrible as it might sound, there are a few different versions of the mod formula, all called the same thing, but all slightly different.
There's a nice chart showing mod variations on the modulus wiki page.
(I'm actually building my own math utility plugin right now, and I was initially inspired by the lack of a "floored division" mod.)
Getting "floored division" mod into C2
Granted the formula does look a lot nicer with the mod(), and it would be nice to be able to use it in C2.
There is a way, and I show it in the example capx I attached.
You can use C2's Function object to create a custom "floored division" style mod function.
Again, you can see this setup in the example capx if you're interested. It does make the angle_delta function much nicer to look at.
Note that I renamed the Function object from "Function" to "oF", which just makes it easier for me to read expressions that involve the function object.
I hope that helps clarify some of the stuff I explained a bit hastily in my prior post.