sin,cos movement help
BlitzMax Forums/BlitzMax Beginners Area/sin,cos movement help
| ||
Hi all Any one good wih the whole Sin,Cos stuff? I have been trying for the last hour to get the below code to work, the Red circle should go the location of the mouse when the mouse button is pressed, in a nice smooth movement with gentle acceleration and decceleration. I feel I am almost there but after a while of searching these forums I cannot quite get it to work. Any tips? Strict Graphics 800 , 600 , 0 , 32 SetBlend ALPHABLEND Global L_enemy:TList = CreateList() Type T_enemy Field x:Float Field y:Float Field size:Float Field angle:Float Field speed_x:Float Field speed_y:Float Field acceleration_x:Float Field acceleration_y:Float Field target_x:Float Field target_y:Float '// Function Add(x:Float , y:Float , size:Float) Local a:T_enemy = New T_enemy a.x = x a.y = y a.size = size ListAddLast(L_enemy,a) End Function '// Function Update() Local MaxSpeed:Float = 4 Local Acceleration:Float = 0.1 For Local a:T_enemy = EachIn l_enemy a.angle = ATan( (a.target_x - a.x) / (a.target_y - a.y) ) ' smooth acceleration? If a.target_x > a.x Then a.speed_x:+ Acceleration Else a.speed_x:- Acceleration If a.target_y > a.y Then a.speed_y:+ Acceleration Else a.speed_y:- Acceleration If a.speed_x > MaxSpeed Then a.speed_x = MaxSpeed If a.speed_y < -MaxSpeed Then a.speed_y = -MaxSpeed If a.speed_x > MaxSpeed Then a.speed_x = MaxSpeed If a.speed_y < - MaxSpeed Then a.speed_y = - MaxSpeed a.acceleration_x = a.speed_x * Cos(a.angle) a.acceleration_y = a.speed_y * Sin(a.angle) a.x:+ a.acceleration_x a.y:+ a.acceleration_y a.Draw() DrawText "angle: " + a.angle , 10 , 10 DrawText "speed x: " + a.speed_x , 10 , 30 DrawText "speed y: " + a.speed_y , 10 , 50 Next End Function '// Method Draw() SetColor 255 , 0 , 0 ; SetAlpha 0.5 DrawOval x-(size/2) , y-(size/2) , size , size SetAlpha 1.0 ; SetColor 255 , 255 , 255 End Method '// Function ChangeFocus(target_x:Float , target_y:Float) For Local a:T_enemy = EachIn l_enemy a.target_x = target_x a.target_y = target_y Next End function End Type '// There will only ever be one enemy. T_enemy.Add(GraphicsWidth()/2,GraphicsHeight()/2,250) T_enemy.ChangeFocus(0 , 0) '// Repeat ; Cls ; Delay 3 T_enemy.Update If MouseHit(1) = True Then T_enemy.ChangeFocus( MouseX() , MouseY() ) Flip ; Until KeyDown(KEY_ESCAPE) ; End |
| ||
You're mixing up cos/sin and component speeds. Speed is a vector, which you can think of as either an x-component and a y-component, OR as an angle and a magnitude. To get this clear in your head, get a bit of graph paper and draw a line at an angle. Measure the difference between the start and end of the line in horizontally and vertically. Those are the x- and y-components. Now measure the angle the line makes with the horizontal, and the length of the line (the magnitude). Where sin and cos come in is this: the x-component is the magnitude * cos(angle), and the y-component is the magnitude * sin(angle). And y/x = (m*sin(angle)) / (m*cos(angle)) = sin(angle)/cos(angle) = tan(angle). Finally, using Pythagoras' Theorem, we can get the magnitude from the x- and y-components by m^2 = x^2 + y^2 In fact, you don't really need to use sin or cos at all to do what you want to do. You can do it all using the components. Local dx:Float, dy:Float, d:Float dx = a.target_x - a.x '(dx,dy) is a vector from the enemy to its target dy = a.target_y - a.y d = Sqr( dx*dx + dy*dy ) 'get distance from enemy to target using pythagoras dx = dx/d 'divide the vector by its length to get a vector in the same direction but of magnitude 1. We can then multiply this vector by the amount we want to make it the right size dy = Acceleration * dy/d a.acceleration_x = Acceleration * dx 'Multiply by Acceleration to make the amount the enemy will accelerate by this frame a.acceleration_y = Acceleration * dy a.speed_x = a.speed_x + dx 'add the acceleration to the enemy's speed a.speed_y = a.speed_y + dy 'now the enemy might be travelling faster than is allowed, so we might have to scale its speed down, in the same way as before Local v:Float v = Sqr( a.speed_x * a.speed_x + a.speed_y * a.speed_y ) If v>MaxSpeed a.speed_x = MaxSpeed * a.speed_x / v a.speed_y = MaxSpeed * a.speed_y / v EndIf Hope that helps. |
| ||
thanks Warpy I wont pretend I understand it just yet, but when I get home ill run the code and play about till I do. |
| ||
Using Sin/Cos/ATAN2local dx:float,dy:float, d:float, a:float a=ATAN2(a.target_y-a.y,a.target_x-a.x) ' angle between destination and target dx=cos(a) dy=sin(a) Of course, Warpy's method is faster... I just added this because its another way of doing it. |
| ||
warpy's method is not necessarily faster. I really prefer using sin and cos for movements. And to make execution really, really fast you can store the sin an cos values of important, let's say 1440, angles in an array. Now the processor only has to computer a simple floating-point multiplication. |