are you doing making this in 2d or 3d (i understand it's top down, but even that cooould be easier to make in 3d)? And if 2d-do you have a tile system? because if you don't then you will have issues when you try to fly out of the area that is covered by your background image...
I would make it in 3d and use either 3d models or plains textured with the ships (with transparency). The advantages would be the follwoing:
- you could actually and easily fly around in the x and z axis. Positioning the camera over the player's ship and looking down at it ensures that you both have actual x and z coordinates AND always have the ship at the center of the screen (or move the camera around for cutscenes etc)
- you could have one big textured plain covering the entire screen below the ship, ALWAYS MOVING along with the ship, so that it seems to remain static on screen: that's because extremely far away nebulae and stars wouldn't appear to move very much if you fly around in space.
- you could add small dust particles or whatever in different heights (y axis) which then automatically move around on the screen and give the impression of flight.
The thing about movement: You need to consider what kind of physics you want. Do you want friction? This would be unrealistic, but most space shooters have some kind of friction that automatically slows the ships down when they dont have their thrusters on.. Makes gameplay a bit more familiar and easeier, I think...
I recently made a (fairly) simple code demo for sb else on the foruma and expanded it a bit...
Note that it doesn't have any physics, really... all ships move by default in the direction they are pointing (control with arrow-keys, afterburners with shift, shoot with space).
A better system of physics would be something along the lines of (pseudo code, won't actually work like this):
thrust.x = sin(angle.y#) * thrusterpower#
thrust.z = cos(angle.y#) * thrusterpower#
velocity.x = (velocity.x + thrust.x) * friction#
velocity.z = (velocity.z + thrust.z) * friction#
position.x = position.x + velocity.x
position.z = position.z + velocity.z
so here's my example demo.. i stopped documenting the controls at some point, unfortunately

maybe it'll help a bit anywhow..)
`Bullet-Demo
`Bullet-Demo.dba
`======================
randomize timer()
sync on
sync rate 60
screen_x = desktop width()
screen_y = desktop height()
set window on
set window layout 0 ,0, 4
window to back
set display mode screen_x , screen_y , 32 , 1
autocam off
position camera 0 , 300 , 0
point camera 0 , 0 , 0
color backdrop rgb(0,0,0)
rem define the characteristics that each individual enemy can have
type enemy
hp as integer rem how many hitpoints does each enemy have at the moment?
object_number as integer rem which object represents each enemy?
last_fired as float rem when did each enemy last shoot?
ai_change_heading as boolean
ai_heading as integer
ai_team as integer
ai_target as integer
ai_afterburner as integer
afterburner_charge as float
rate_of_fire as float
endtype
type explosion
active as boolean
scale as float
target_scale as float
object_number as integer
color_red as integer
endtype
rem define the characteristics that each bullet can have
type bullet
active as boolean rem is the bullet currently flying or "on standby"?
object_number as integer
fired_at as float rem the timer when each particular bullet was fired
owner as integer rem who shot the bullet?
endtype
rem specify how many enemies there are and how many bullets can fly around at the same time.
number_of_bullets = 2000
number_of_enemies = 40 rem 80
number_of_explosions = 50
rem set up player starting health
player_hp = 100
zoom = 700 rem 350
rem set up the arrays!
rem this means: CREATE 100 individuals of bullets how we defined them above!
rem ...and also CREATE 10 individual enemies as defined above!
dim bullets (number_of_bullets) as bullet
dim enemies (number_of_enemies) as enemy
dim explosions (number_of_explosions) as explosion
REM LET'S CREATE ALL THE OBJECTS!
rem define some variables for the object numbers:
player = 1 rem the player object number = 1
object_index_enemies = 10 rem so the OBJECT NUMBERS of the enemies will be 10, 11, 12, 13, ... 20 (see below)
object_index_bullets = 1000 rem the OBJECT numbers of the bullets will be 1001 , 1002, 1003 , ... , 1100
object_index_explosions = 3000
object_index_stardust = 15000
dimension_of_spawn = 1200
dimension_of_spawn = dimension_of_spawn * 0.5
number_of_stars = 10000
for s = 1 to number_of_stars
s_obj = s + object_index_stardust
make object plain s_obj , 4 , 4
xrotate object s_obj , 90
rem set shading off s_obj
color object s_obj , rgb (255 , 255 , 255)
size# = rnd(100) * 0.01
scale object s_obj , 100 * size#, 100 * size#, 100 * size#
position object s_obj , - dimension_of_spawn * 8 + rnd ( 16 * dimension_of_spawn ) , -300 + rnd(600) , - dimension_of_spawn * 8 + rnd ( 16 * dimension_of_spawn )
rem position object s_obj , -200 + s * 5 , 0 , 0
next s
rem helper object
helper_object = 7
make object cube helper_object , 1
hide object helper_object
set camera range 1, 50000
make object sphere 6 , 3000 , 32, 32
position object 6 , 2000 , - 4000 , 200
color object 6 , rgb(0 , 50 , 50)
rem make the player object
remstart
make object cone player , 10
xrotate object player , 90
fix object pivot player
color object player , rgb (0, 250, 0)
remend
rem create enemies!
for e = 1 to number_of_enemies rem this means: do the following ten times, advancing the index "e" by 1 in every loop. This creates enemy 1, enemy 2, etc automatically!
rem set up every enemy's stats:
enemies(e).hp = 500
enemies(e).object_number = object_index_enemies + e
enemies(e).rate_of_fire = 250 rem 500 rem 800
rem create the object that represents the enemy
make object cone enemies(e).object_number , 10
xrotate object enemies(e).object_number , 90
fix object pivot enemies(e).object_number
if e > number_of_enemies * 0.5
color object enemies(e).object_number , rgb(250, 0 , 0)
enemies(e).ai_team = 2
position object enemies(e).object_number , - dimension_of_spawn + rnd(dimension_of_spawn * 2) , 0 , -dimension_of_spawn + rnd(100)
yrotate object enemies(e).object_number , -30 + rnd(60)
else
color object enemies(e).object_number , rgb(0, 0 , 250)
position object enemies(e).object_number , - dimension_of_spawn + rnd(dimension_of_spawn * 2) , 0 , dimension_of_spawn - rnd(100)
yrotate object enemies(e).object_number , 180 + -30 + rnd(60)
enemies(e).ai_team = 1
endif
if e = 1
color object enemies(e).object_number , rgb(0, 250 , 250)
position object enemies(e).object_number , - dimension_of_spawn + rnd(dimension_of_spawn * 2) , 0 , dimension_of_spawn - rnd(100)
position object enemies(e).object_number , - dimension_of_spawn + rnd(dimension_of_spawn * 2) , 0 , dimension_of_spawn - rnd(100)
enemies(e).ai_team = 1
player = enemies(e).object_number
endif
next e
rem create bullets!
for b = 1 to number_of_bullets
bullets(b).object_number = object_index_bullets + b
bullets(b).active = 0 rem no bullets have been fired yet!
make object sphere bullets(b).object_number , 3
scale object bullets(b).object_number , 100 , 100 , 800
color object bullets(b).object_number , rgb (200 , 200 , 0)
set object ambient bullets(b).object_number , 0
hide object bullets(b).object_number rem no bullets have been fired yet! so let's hide them!
next b
for x = 1 to number_of_explosions
explosions(x).active = 0
explosions(x).scale = 0
explosions(x).object_number = x + object_index_explosions
make object sphere explosions(x).object_number , 15
set object ambient explosions(x).object_number , 0
hide object explosions(x).object_number
next x
do
rem control the player movement
if enemies(1).hp > 0
rem if upkey() = 1
afterburner# = 0
if shiftkey() = 1 then afterburner# = 0.6
move object player , 0.9 + afterburner#
rem endif
if leftkey() = 1
yrotate object player , object angle y (player) - 3
endif
if rightkey() = 1
yrotate object player , object angle y (player) + 3
endif
if spacekey() = 1
rem check if enough time has passed since the last time the player fired a bullet
if timer() - player_last_fired_at > enemies(1).rate_of_fire
rem execute the "fire_bullet" subroutine with the player object as the "shooter" (see sub routine at bottom of code)
shooter_object = player
gosub fire_bullet
rem remember when the player last fired a bullet:
player_last_fired_at = timer()
endif
endif
else rem if the player has < 0 hp
center text screen width() *0.5 , screen height() * 0.5 , "YOU'RE DEAD!"
endif
rem position the camera above the player
position camera object position x(player) , zoom , object position z(player)
point camera object position x(player) , object position y(player) , object position z(player)
rem handle the enemies:
for e = 2 to number_of_enemies
rem only do the following if the current enemy is alive:
if enemies(e).hp > 0
chance = rnd (10000)
if chance > 9990
enemies(e).ai_afterburner = 1
rem enemies(e).afterburner_charge = 100
endif
afterburner# = 0
if enemies(e).ai_afterburner = 1
rem center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) + 10 , "!!!"
afterburner# = 0.6
enemies(e).afterburner_charge = enemies(e).afterburner_charge - 0.5
endif
if enemies(e).afterburner_charge <= 0
enemies(e).ai_afterburner = 0
afterburner# = 0
enemies(e).afterburner_charge = 100
endif
move object enemies(e).object_number , 0.9 + afterburner#
rem occasionally change the fighter's flight path to make it a bit more unpredictable
chance# = 990000
if enemies(e).ai_target = 0
rem if the fighter has a target, it's less likely to change course
chance# = 990000
endif
if enemies(e).ai_heading = 0
random# = rnd(1000000)
if random# > chance#
rem determine whether to turn left or right
new_heading = 1 + rnd (1)
enemies(e).ai_heading = new_heading
rem determine by how many degrees the flightpath should change
enemies(e).ai_change_heading = rnd(45)
endif
endif
if enemies(e).ai_heading = 1
yrotate object enemies(e).object_number , object angle y (enemies(e).object_number) - 3
enemies(e).ai_change_heading = enemies(e).ai_change_heading - 3
endif
if enemies(e).ai_heading = 2
yrotate object enemies(e).object_number , object angle y (enemies(e).object_number) + 3
enemies(e).ai_change_heading = enemies(e).ai_change_heading - 3
endif
if enemies(e).ai_change_heading <= 0
enemies(e).ai_heading = 0
endif
rem if the fighter flies too far away, turn it around to head for the center of the map
distance# = sqrt( ( 0 - object position x(enemies(e).object_number) )^2 + ( 0 - object position y(enemies(e).object_number) )^2 + ( 0 - object position z(enemies(e).object_number) )^2 )
if distance# >= 700
point object enemies(e).object_number , 0 , 0 , 0
endif
rem find target
smallest_distance# = 100000
closest_enemy = 0
for target = 1 to number_of_enemies
current_target = enemies(e).ai_target
current_target_obj = enemies(current_target).object_number
target_obj = enemies(target).object_number
if target <> e
if enemies(target).hp > 0
if enemies(target).ai_team <> enemies(e).ai_team
distance# = sqrt( ( object position x (target_obj) - object position x(enemies(e).object_number) )^2 + ( object position y (target_obj) - object position y(enemies(e).object_number) )^2 + ( object position z (target_obj) - object position z(enemies(e).object_number) )^2 )
rem remember which enemy is closest
if distance# < smallest_distance#
smallest_distance# = distance#
closest_enemy = target
endif
if distance# <= 400
position object helper_object , object position x(enemies(e).object_number) , object position y(enemies(e).object_number) , object position z(enemies(e).object_number)
point object helper_object , object position x(target_obj) , object position y(target_obj) , object position z(target_obj)
y_diff_to_target# = abs(object angle y(helper_object) - object angle y(enemies(e).object_number))
if y_diff_to_target# <= 60
if enemies(e).ai_target > 0
point object helper_object , object position x(current_target_obj) , object position y(current_target_obj) , object position z(current_target_obj)
y_diff_to_current_target# = abs(object angle y(helper_object) - object angle y(enemies(e).object_number))
else
y_diff_to_current_target# = 9999
endif
if y_diff_to_target# < y_diff_to_current_target#
enemies(e).ai_target = target
endif
endif
endif
endif
endif
endif
next target
current_target = enemies(e).ai_target
if enemies(current_target).hp < 0 then enemies(e).ai_target = 0
current_target = enemies(e).ai_target
rem if no target gained through above routine, just pick the closest enemy as a target (but only with a certain probability)
if enemies(e).ai_target = 0
chance = rnd (10000)
if chance > 9950
enemies(e).ai_target = closest_enemy
current_target = enemies(e).ai_target
endif
endif
if current_target > 0
current_target_obj = enemies(current_target).object_number
position object helper_object , object position x(enemies(e).object_number) , object position y(enemies(e).object_number) , object position z(enemies(e).object_number)
point object helper_object , object position x(current_target_obj) , object position y(current_target_obj) , object position z(current_target_obj)
yrotate object enemies(e).object_number , curveangle (object angle y (helper_object) , object angle y (enemies(e).object_number) , 2)
rem check if the last time this enemy fired was more than 1000 milli seconds (=1 second) ago
if timer() - enemies(e).last_fired >= enemies(e).rate_of_fire
distance# = sqrt( ( object position x (current_target_obj) - object position x(enemies(e).object_number) )^2 + ( object position y (current_target_obj) - object position y(enemies(e).object_number) )^2 + ( object position z (current_target_obj) - object position z(enemies(e).object_number) )^2 )
if distance# <= 300 + rnd(300)
rem FIRE!
rem remember when this enemy fired his last bullet
enemies(e).last_fired = timer()
rem EXECUTE THE "FIRE_BULLET" SUBROUTINE WITH THE CURRENTLY FIRING ENEMY AS THE SHOOTER (i.e. who the bullet is being shot by)
shooter_object = enemies(e).object_number
gosub fire_bullet
endif
endif
endif
endif
remstart
if enemies(e).hp > 0
center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) , "ID: " + str$(e)
center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) + 15 , "Target: " + str$(current_target)
endif
remend
next e
rem handle bullets, i.e. let them fly around and check if they hit anything
for b = 1 to number_of_bullets
rem by default, a bullet stays active (unless it hits something or has been flying for too long, see below)
deactivate_bullet = 0
if bullets(b).active = 1
move object bullets(b).object_number , 15
rem check collision FOR ALL enemies
for e = 1 to number_of_enemies
rem check if the enemy is even alive
if enemies(e).hp > 0
if object collision (bullets(b).object_number , enemies(e).object_number) = 1
enemies(e).hp = enemies(e).hp - 30
deactivate_bullet = 1
emitter_object = bullets(b).object_number
explosion_size# = 1
gosub create_explosion
rem if this bullet kills the enemy, then hide the enemy object
if enemies(e).hp < 0
hide object enemies(e).object_number
emitter_object = enemies(e).object_number
explosion_size# = 4
gosub create_explosion
endif
endif
endif
next e
rem if the bullet has been flying for more than 5 seconds, kill it off
if timer() - bullets(b).fired_at >= 5000
deactivate_bullet = 1
endif
if deactivate_bullet = 1
bullets(b).active = 0
hide object bullets(b).object_number
endif
endif
next b REM DO THE ABOVE FOR ALL BULLETS
rem handle explosions
for x = 1 to number_of_explosions
if explosions(x).active = 1
explosions(x).scale = explosions(x).scale + 0.1
s# = explosions(x).scale
scale object explosions(x).object_number , 100 * s# , 100 * s# , 100 * s#
explosions(x).color_red = explosions(x).color_red + 5
r = explosions(x).color_red
color object explosions(x).object_number , rgb (200 , 200 - r , 0)
if explosions(x).scale >= explosions(x).target_scale
explosions(x).active = 0
hide object explosions(x).object_number
endif
endif
next x
rem some info text:
rem display health for all enemies and count enemies alive
enemy_count = 0
team1_count = 0
team2_count = 0
for e = 1 to number_of_enemies
rem check if the enemy is even alive
if enemies(e).hp > 0
enemy_count = enemy_count + 1
if enemies(e).ai_team = 1 then team1_count = team1_count + 1
if enemies(e).ai_team = 2 then team2_count = team2_count + 1
rem center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) + 10 , "ID: " + str$(e)
rem center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) + 25 , "HP: " + str$(enemies(e).hp)
rem center text object screen x (enemies(e).object_number) , object screen y (enemies(e).object_number) + 40 , "Target: " + str$(enemies(e).ai_target)
endif
next e
rem display victory message
if team2_count = 0
center text screen width() *0.5 , screen height() * 0.5 + 20, "YOU WIN!"
endif
rem display player health in top left corner
text 50 , 50 , "YOUR HEALTH: " + str$(enemies(1).hp)
ink rgb(0,0,250) , rgb(0,0,0) : text 50 , 65 , "Friendlies: " + str$(team1_count)
ink rgb(250,0,0) , rgb(0,0,0) : text 50 , 80 , "Enemies : " + str$(team2_count)
ink rgb(255,255,255) , rgb(0,0,0)
rem text 50 , 60 , "ENEMIES LEFT: " + str$(enemy_count)
text screen width() - 60 , screen height() - 25 , "FPS: " + str$(screen fps())
sync
loop
create_explosion:
for x = 1 to number_of_explosions
if explosions(x).active = 0
explosions(x).active = 1
explosions(x).scale = 0
explosions(x).target_scale = explosion_size#
position object explosions(x).object_number , object position x (emitter_object) , object position y (emitter_object) , object position z (emitter_object)
show object explosions(x).object_number
explosions(x).color_red = 0
exit
endif
next x
return
fire_bullet:
rem this is a bit complex. basically, we check for a "free" bullet, that is, one that has not been fired yet and is "on standby"
gun = 1
for b = 1 to number_of_bullets
rem see if the current bullet is "unused"
if bullets(b).active = 0
rem if it is not currently active, USE THIS BULLET!
rem position the bullet where the enemy is
position object bullets(b).object_number , object position x (shooter_object) , object position y (shooter_object) , object position z (shooter_object)
rem aim the bullet in the right direction
rotate object bullets(b).object_number , object angle x (shooter_object) , object angle y (shooter_object) , object angle z (shooter_object)
rem move the bullet a bit forward so that it doesn't start INSIDE the enemy
move object bullets(b).object_number , 15
if gun = 1
yrotate object bullets(b).object_number , object angle y(bullets(b).object_number) + 90
move object bullets(b).object_number , -4
yrotate object bullets(b).object_number , object angle y(bullets(b).object_number) - 90
gun = 2
endif
rem set the bullet to active
bullets(b).active = 1
rem remember when this bullet was fired
bullets(b).fired_at = timer()
rem unhide the bullet object
show object bullets(b).object_number
rem since we have already found an unused bullet, we don't need to search any further. If bullet one (b=1) is already flying around, go on to check bullet two, and so on.
exit
endif
next b
for b = 1 to number_of_bullets
rem see if the current bullet is "unused"
if bullets(b).active = 0
rem if it is not currently active, USE THIS BULLET!
rem position the bullet where the enemy is
position object bullets(b).object_number , object position x (shooter_object) , object position y (shooter_object) , object position z (shooter_object)
rem aim the bullet in the right direction
rotate object bullets(b).object_number , object angle x (shooter_object) , object angle y (shooter_object) , object angle z (shooter_object)
rem move the bullet a bit forward so that it doesn't start INSIDE the enemy
move object bullets(b).object_number , 15
if gun = 2
yrotate object bullets(b).object_number , object angle y(bullets(b).object_number) + 90
move object bullets(b).object_number , 4
yrotate object bullets(b).object_number , object angle y(bullets(b).object_number) - 90
endif
rem set the bullet to active
bullets(b).active = 1
rem remember when this bullet was fired
bullets(b).fired_at = timer()
rem unhide the bullet object
show object bullets(b).object_number
rem since we have already found an unused bullet, we don't need to search any further. If bullet one (b=1) is already flying around, go on to check bullet two, and so on.
exit
endif
next b
return
hope this helped a bit.
[EDIT: Note, all of this can ofcourse also be done completely in 2d. I just like to use 3d.. it's all personal preference I guess..]