Moving in a circle from one position to another?

BlitzMax Forums/BlitzMax Programming/Moving in a circle from one position to another?

Chroma(Posted 2007) [#1]
Here's what I'm trying to do. The center of my screen is 400,300. My tile is at 500,500. I want to move the tile to 300,100 in a clockwise arc over a period of 2 seconds.

I'm trying to get my head around how to do this. I know I'll be using sin and cosine.


ImaginaryHuman(Posted 2007) [#2]
Um.. a guess..

Find the distance between the center and the old position.
Find the distance between the center and the new position.

These are the radius's of the arc at the start and end points in the animation.

Then over a period of 2 seconds, resize the radius, starting at the old radius and approaching the new radius.

Find the angle that the old position is at compared to the center, and the angle that the new position is at. Then move through the angles over the 2 seconds while you are simultaneously adjusting the radius.

This would work, but it won't give you a pure circular arc because the radius is changing. You can't have it be a circular arc anyway unless you are choosing a different center of rotation. If you want it to move on a perfect circular arc then you need to find the center of that circle where both tile positions intersect it as the same radius.


Chroma(Posted 2007) [#3]
It doesn't have to be perfect because when the time is up I'm going to just position the tile at the new xy coords anyhow. Thanks for the help tho.


sswift(Posted 2007) [#4]
Here are the equations you need to do it:

x = radius * cos(angle)
y = radius * sin(angle)

And the inverse:

angle = atan(y, x)
radius = sqr((x2-x1)^2 + (y2-y1)^2)


What you need to do is put the tile at 400+x, 300+y, where X and Y are calculated using the first two equations.

To make it rotate you have to calculate the angle and the radius of the start position, and the angle of the end position. You could also calculate the radius of the end position if it is different and interpolate that as well.

The radius would be radius = sqr((400.0-x)^2 + (300.0-y)^2)
The angle would be angle = atan(y-300, x-400). ( Your coordinate system has 0,0 in the center of the screen, so you need to transform the x and Y of the tile into that space, which is why I subtract 300 and 400. And yes, in arctan Y comes before X.)

Once you know that, and calculate the end angle of the desired position, use this function to tween the value over the course of a second from one to the other:

' -------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function allows you to do a linear interpolation between two values.
	'
	' If tween is  0, then the value returned will be x1.
	' If tween is  1, then the value returned will be x1 plus 1 times the difference between x1 and x2. (Ie: x2)
	' If tween is .5, then the value returned will be x1 plus 0.5 times the difference between x1 and x2. 
	' (Ie: The value halfway between x1 and x2)
	'
	' You may also specify values for tween outside the 0..1 range.
	'
	' For example, if you specify a value of 2 for tween, then the value returned will be x1 plus 2 times the difference
	' between x1 and x2.
	'
	' It doesn't matter whether x1 or x2 is the larger number.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------
		
		Function TweenLinear#(X1#, X2#, Tween#)
			Return X1# + (Tween# * (X2# - X1#))
		End Function


To calculate the tween value for that function, you can use this function:

' -------------------------------------------------------------------------------------------------------------------------------------------------------
	' This function allows you to do the reverse of a linear interpolation between two values.
	'
	' Instead of specifying the tween value, you specify the value which you want the know the tween of.
	'
	' Essentially, this function will tell you where MidX# is between two other values.  If the value is between
	' the two values, then the result will be in the range of 0..1.
	' -------------------------------------------------------------------------------------------------------------------------------------------------------

		Function InverseTween#(X1#, X2#, MidX#)
			
			' If the difference between x1 and x2 is 0, then there is no tween value which will give you the value of
			' median, unless median is equal to x1 or x2, in which case all tween values will give you the correct result.
			' So we just return 0 for the tweening value if the difference is 0.
		
			If (X2# - X1#) <> 0
				Return (MidX# - X1#) / (X2# - X1#)
			Else
				Return 0
			EndIf
			
		End Function



So pass to the second function your start time, and your end time, and your current time. The returned value is the tween value you pass to the first function. Pass the start angle, the end value and this tween value to the first function, and then use the first two equations I posted to calculate the point where you should plot the tile. (Add 400 and 300 to the X and Y values you get, like I showed you.) If the tween value is greater than 1 then you have finished the animation.

If all you want to do is move in an arc and you know the radius and angle of the start position, then you don't need to calculate those, and you can just use the first two equations and the tweening functions.

Btw, my sprite system makes rotating things in an arc like this easy. Just attach a child to a parent in the middle of the screen, and tell the parent to animate its rotation for 200 milliseconds from angle A to angle B. Maybe flag the child not to rotate with the parent so it stays in a vertical orientation if desired.


Chroma(Posted 2007) [#5]
Cool thx guys.

Basically the effect I'm after would be something like a board full of scrabble tiles getting hit by a cyclone. The tiles swirl around and then land on a random square. The square that the tile is headed to is determined first, and then the arc is calculated, then the tile is sent on it's journey.


Chroma(Posted 2007) [#6]
While working on the arc movement code, I came up with a way to make an image "breathe". It's pretty handy and I'll definitely be using it.

Local osc_speed# = 100 / 100.0	'1 to 100
Local osc_size# = 	20  / 100.0	'1 to 10
		
current.xscale = 1 + Sin(MilliSecs() * osc_speed) * osc_size
current.yscale = 1 + Sin(MilliSecs() * osc_speed) * osc_size


Just plug in your image x and y scale to in place of the current.xyscale.