Posted: Mon Feb 16, 2004 6:03 pm Post subject: [tutorial] spaceship movement: asteroids style
This tutorial is meant to teach you how to program an image to respond to key input and to create an effect of movement in space ie you keep moving it the same direction even if you aren't pressing the throttle key...
var x : real := maxx div 2
var y : real := maxy div 2
var ax, ay : real
var vx, vy : real := 0
var spd : real := 0
var ang : int := 0
var ship : int
var move : array char of boolean
procedure moveShip
if x > maxx - rotX then
x := -rotX
elsif x < -rotX then
x := maxx - rotX
elsif y > maxy - rotY then
y := -rotY
elsif y < -rotY then
y := maxy - rotY
end if
ax := cos (ang * (Math.PI / 180)) * spd
ay := sin (ang * (Math.PI / 180)) * spd
vx += ax
vy += ay
vx *= decay
vy *= decay
x += vx
y += vy
ship := Pic.Rotate (spaceship, ang - 90, rotX, rotY)
Pic.Draw (ship, round (x), round (y), picMerge)
Pic.Free (ship)
end moveShip
procedure getKeyStrokes
Input.KeyDown (move)
if move (KEY_UP_ARROW) then
spd := forwardSpd
elsif move (KEY_DOWN_ARROW) then
spd := -backwardSpd
else
spd := 0
end if
if move (KEY_LEFT_ARROW) then
ang += turnSpd
elsif move (KEY_RIGHT_ARROW) then
ang -= turnSpd
end if
end getKeyStrokes
in the above code, we store the image "spaceship.bmp" in a variable for later use. next we draw the spaceship on the screen and store the picture in the same variable. there is a reason for this... this time when we store the image we select and area greater than the actual image which leaves a border of nothingness around it. this is important since later when we rotate the ship, some clipping occures at the edge of the picture. with the edge being further away, the cliping doesnt occure.
this chunk of code controls all the characteristics of the movement such as the speed of the ship when its accelerating forwrad or how fast the ship turns. the constants rotX and rotY is where the ship will pivot when it's being rotated.
code:
procedure moveShip
if x > maxx - rotX then
x := -rotX
elsif x < -rotX then
x := maxx - rotX
elsif y > maxy - rotY then
y := -rotY
elsif y < -rotY then
y := maxy - rotY
end if
ax := cos (ang * (Math.PI / 180)) * spd
ay := sin (ang * (Math.PI / 180)) * spd
vx += ax
vy += ay
vx *= decay
vy *= decay
x += vx
y += vy
ship := Pic.Rotate (spaceship, ang - 90, rotX, rotY)
Pic.Draw (ship, round (x), round (y), picMerge)
Pic.Free (ship)
end moveShip
this is the procedure which controls all the movements of the ship...
code:
if x > maxx - rotX then
x := -rotX
elsif x < -rotX then
x := maxx - rotX
elsif y > maxy - rotY then
y := -rotY
elsif y < -rotY then
y := maxy - rotY
end if
this is where we check whether the ship has reached the edge of the screen, if so, we "rollover" the ship to the other side of the screen.
code:
ax := cos (ang * (Math.PI / 180)) * spd
ay := sin (ang * (Math.PI / 180)) * spd
vx += ax
vy += ay
vx *= decay
vy *= decay
x += vx
y += vy
since this type of movement is a bit more complex than the tradition point and go movement, we need a few more variables.... the ax and ay variables store the value of the acceleration upon that axis. this value is calculated with a bit of trig
code:
cos (ang * (Math.PI / 180))
sin (ang * (Math.PI / 180))
this returns a value betwee 0 and 1 depending on the angle spcified. the angle is converted into radians by multiplying it by PI/180. this number is then multiplied by the speed and you end up with your acceleration values.
code:
vx += ax
vy += ay
vx *= decay
vy *= decay
x += vx
y += vy
this bit is fairly self explanitory especially if you've taken physics. it adds the acceleration vectors to the velocity vectors and then the velocities are added to the x and y coordinates of the spaceship.
here we rotate our original spaceship image around the rotX and rotY coordinates (the pivot point) by the specified angle and then we draw it and free the memory. we free the image from the memory because that's the only time we will use it -> the next loop will update it.
code:
procedure getKeyStrokes
Input.KeyDown (move)
if move (KEY_UP_ARROW) then
spd := forwardSpd
elsif move (KEY_DOWN_ARROW) then
spd := -backwardSpd
else
spd := 0
end if
if move (KEY_LEFT_ARROW) then
ang += turnSpd
elsif move (KEY_RIGHT_ARROW) then
ang -= turnSpd
end if
end getKeyStrokes
this simply checks which keys are pressed and alters the appropriate variables accordingly.
finally we put the two procedures together in a loop.
everytime it loops, we erase our old screen by drawing a blackbox over it. then we check which keys are being pressed by calling the getKeyStrokes procedure. then we move and draw the space ship by calling the moveShip procedure. finally we update the screen and add a delay to control the speed of the game.
phew!!! that took some time! hope you guys enjoy this tutorial
-zylum
by the way here's the graphic for the spaceship:
Sponsor Sponsor
zylum
Posted: Mon Feb 16, 2004 6:05 pm Post subject: (No subject)
just like the cosine-sine problem you had with the 3d thingie, it's not as fast as generating all the pictures and then call them when you needed it.
here, have some bits for your effort.
+25 bits
Edit: it seems the donate and the +- bits option are messed, I'll owe you 25 bits for now, remind me later.
Cervantes
Posted: Mon Feb 16, 2004 6:35 pm Post subject: (No subject)
niiiice...
This is really similar to Asians tutorial but meh, still good
This brings up memories of comet busters
zylum
Posted: Mon Feb 16, 2004 6:41 pm Post subject: (No subject)
what do you mean by:
"just like the cosine-sine problem you had with the 3d thingie, it's not as fast as generating all the pictures and then call them when you needed it. "
my 3d engine doesnt draw pics, it draws polygons... further more, it just has to generate 1 pic every frame which isnt that bad.
btw i already made an asteroids game and it runs just fine... i'll post it tomorrow since the latest draft is stored there, but for now heres a basic version:
AsianSensation
Posted: Mon Feb 16, 2004 6:43 pm Post subject: (No subject)
I meant that instead of generating on the spot and then freeing the picture memory, it's faster to pre-generate everything and then call on the appropriate picture. Much like instead of generating sine and cosine values, it's faster to pre-generate a table and then call it instead of calling it on the spot. The difference being Pic.Rotate takes up alot of time, so when you have asteroid flying all over, it's going to lag the game down very badly.
Sponsor Sponsor
zylum
Posted: Mon Feb 16, 2004 6:47 pm Post subject: (No subject)
well, i'd have to store 72 images if i wanted im increment of 5 degrees while turning -_- i think one Pic.Rotate isn't that bad (the asteroids themselves dont rotate)
Cervantes
Posted: Mon Feb 16, 2004 7:18 pm Post subject: (No subject)
An increment of 10 looks fine. that's 36 different images. If you think about it, that's a lot. It wouldn't look all that smooth if the image you were rotating was a long thin line, but with a small fat ship like that (jk it looks really cool) you don't really notice it.
AsianSensation
Posted: Mon Feb 16, 2004 7:27 pm Post subject: (No subject)
I was assuming that you were also rotating the asteroid, then you would need to generate pics pre-hand. Also, from my experience, 10 degree increments would look fine on most pictures (not extremely large ones)
but generating pictures and storing them won't take up that much memory at all, if you want, you could even declare them as const int instead of int.
paladin style
Posted: Wed Feb 18, 2004 10:25 am Post subject: (No subject)
a cool program
Jodo Yodo
Posted: Tue Mar 02, 2004 10:53 pm Post subject: (No subject)
How come when I use Math.PI, it says it's not an export of 'Math'?
zylum
Posted: Tue Mar 02, 2004 10:59 pm Post subject: (No subject)
you need version 4.0.5 to use Math.PI... you can always replace that with 3.14159 if you dont want to update
-zylum
Paul
Posted: Sat Jan 08, 2005 9:44 am Post subject: (No subject)
Sorry for bringing this old one up, but I'm making one right now. Basically what I've got so far is your code (but I made it myself from understanding every part of your code first). And a second picture for when the ship is thrusting, it has exhaust. But there are still a couple of things I don't understand:
code:
AccX := cos (angle * (Math.PI / 180))*speed
AccY := sin (angle * (Math.PI / 180))*speed
since I haven't learnt radians yet, how does "cos (angle * (Math.PI / 180))*speed" give you the component of acceleration for x, similarly for y. Could you possibly explain this in non-technical terms?
also: why "angle - 90"? why 90? I think this also has something to do with not knowing radians.