I've integrated HL's Doodad code (query: what the hell is a Doodad?) with my level code so they now work together. Doodads' positions are set in the level.txt file, and are denoted by any two characters that start with 'd' - I've added the current red Doodad as 'd1' which potentially gives us 9 more types to play with. As before, they are only drawn just before they come onto the screen to maintain the frame rate.
Heights are still random - but I was wondering if it might be better to have just two heights - high and low, rather than any random height within the range, as it seems quite difficult to gauge how high an object is from a top down perspective like this??
I've reverted back to having the tiles and Doodads scrolling slightly faster than the background, which gives a parallax effect, making it look like the level is floating slightly higher than the ground - I think it looks good anyway!
Also wondered if, given the amount of enemy fire that might be coming from all those doodads, perhaps we should increase the firing rate of the ship to allow for more destruction??
Downloads:
One tile to download - this is the 'd1' tile which acts as the 'Doodad holder'.
New level, which needs to be pasted over the text in level.txt:
t0,t1,t2,d1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t1,t0,t0,t0,t2,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
d1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,d1,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t1,t2,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t1,t1,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,t0,d1,t0,t0,t1,t2,t1,t0,t0,d1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,d1,d1,d1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t2,t2,t2,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,d1,t0,t0,t0,t0,t0,t0,t0,d1,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
New source code:
sync on:sync rate 0:hide mouse
`set display mode 800,600,32
set image colorkey 255,0,255
disect("player ship.bmp",4,2,1)
disect("player weapons.bmp",5,4,10)
disect("explosion32.png",16,1,50)
disect("numbers.bmp",10,1,30)
load image "uibar.bmp",5001
load image "building1.bmp",6000
load music "ng1975.mp3",1
for a = 8 to 15
sprite a,-100,-100,19
next a
type ship
xpos as integer
ypos as integer
height as integer
animation_time as integer
animation_step as integer
animation_frame as integer
start_frame as integer
end_frame as integer
next_move as integer
shadow as integer
next_fire as integer
fire_speed as integer
sprite_number as integer
shadow_number as integer
gun_strength as integer
vulnerable as integer
endtype
type tile
spritenumber as integer
imagetype as integer
imagename as string
y as float
occupied as integer
endtype
type tileimage
imagenumber as integer
imagetype as string
spriteID as integer
endtype
type doodad
xpos as integer
image as integer
ypos as float
height as integer
sprite_number as integer
shadow as integer
points as integer
endtype
type effect
xpos as integer
ypos as integer
frame as integer
start_frame as integer
end_frame as integer
next_frame as integer
sprite_number as integer
endtype
dim explosion(-1) as effect
dim object_tile(-1) as doodad
dim perm_object_tile(-1) as doodad
global player as ship
dim player_missile(-1) as ship
#CONSTANT BACKGROUND_IMAGE=5000
#CONSTANT CLOUD_IMAGE=5002
#CONSTANT TREES_IMAGE=5003
global background_scroll as float
global background_scroll_rate as float
background_scroll_rate=0.6
global cloud_scroll as float
global cloud_scroll_rate as float
cloud_scroll_rate=1.22
global tree_scroll as float
global tree_scroll_rate as float
tree_scroll_rate=0.6
level=1
global spriteseed
spriteseed=10
global numberofrows
global tilespeed#
global SCORE
tilespeed#=1 `best to keep this as an integer, as it represents the number of pixels to scroll each loop
set_player()
make_temp_background()
load_level(level)
player.vulnerable=timer()+2000
loop music 1
do
`display fps - update once every 10 loops to reduce hit
fps=screen fps()
inc textcounter
if textcounter=10 then textcounter=0
if textcounter=0 then text_sprite(2000,0,0,str$(fps))
cls
draw_background()
scroll_tiles()
player_state()
if array count(object_tile())>=0 then scroll_doodads()
if array count(perm_object_tile())>=0 then scroll_perm_doodads()
if array count(explosion())>=0 then draw_explosions()
animate_player()
draw_player()
test_features()
if array count(player_missile())>=0 then draw_missiles()
`if timer()>player.next_move
controls()
player.next_move=timer()+3
`endif
sync
loop
function text_sprite(entity,x,y,text$)
if text$="" then text$=" "
If Bitmap Exist(2)=0
create bitmap 2,screen width()/2,screen height()/8
Else
Set Current Bitmap 2
cls
Endif
ink rgb(1,250,1),0
set text size 14
set text font "Arial"
text 0,0,text$
if image exist(entity) then delete image entity
if sprite exist(entity) then delete sprite entity
get image entity,0,0,text width(text$),text height(text$),1
sprite entity,x,y,entity
set sprite entity,0,0
set sprite priority entity,300
Set Current Bitmap 0
`endif
endfunction
function load_level(level)
`The level is made up of tiles. Each tile is a 64x64 sprite, and has a sprite number
`which links to the array 'tile(column,row).spritenumber'.
`Each sprite also has an image identifier, which is made of two characters, stored
`in 'tile(column,row).imagetype'.
`for example, if it has the tile image "t2.png", then the identifier is tile(column,row)="t2"
`The level file "level1.txt", where the '1' can be any level number is a text file with the following format:
`1st line is a header, and contains the names of all the images it need to load
`All other lines represent the tiles' column, row and image. If it is 't0' it is an empty space.
`A comma is used to separate tiles - including a comma at the end of each row.
open to read 1,"level"+str$(level)+".txt"
`Read header. The header contains the image types used in the level
read string 1,header$
numberoftileimages=len(header$)/3
dim tileimage(numberoftileimages) as tileimage
for n=1 to numberoftileimages
chunk=n*3
image$=left$(right$(left$(header$,chunk),3),2) `parse the string: this takes the left 2 characters (to get rid of the comma) of the right 3 (ie. the end bit) of the left 'chunk' (the chunk is increased in steps of 3)
if image$<>"" and image$<>"t0"
tileimage(n).imagenumber=free_image()
tileimage(n).spriteID=free_sprite()
tileimage(n).imagetype=image$
load image image$+".png",tileimage(n).imagenumber,1
sprite tileimage(n).spriteID,-100,-100,tileimage(n).imagenumber
endif
next n
row=0
repeat
`scan through each subsequent row of the text file to get tile type and position
inc row
numberofrows=row
dim tile(13,row) as tile
read string 1,string$
`scan through each column of the text file
for column=1 to 13 `there are 13 columns, made up of 3 characters each (2 letters and a comma)
chunk=column*3
image$=left$(right$(left$(string$,chunk),3),2) `Parse the string: this takes the left 2 characters (to get rid of the comma) of the right 3 (ie. the end bit) of the left 'chunk' (the chunk is increased in steps of 3)
if image$<>"" and image$<>"t0"
tile(column,row).spritenumber=free_sprite()
image=0
for n=1 to numberoftileimages
if image$=tileimage(n).imagetype
imagenumber=tileimage(n).imagenumber
image=n
Exit
Endif
next n
`as we don't know how big the level is until this loop has finished, we don't know where to position the tiles yet,
`so we'll put them at 0,0 for the time being
`sprite tile(column,row).spritenumber,0,0,imagenumber
tile(column,row).imagetype=image
tile(column,row).imagename=image$
endif
next column$
until file end(1)=1
`go through tiles again. This time, now that we know the total number of rows, we can position the tiles correctly
for column=1 to 13
for row=1 to numberofrows
`if there is a tile at that coordinate
if (tile(column,row).spritenumber)>0
tile(column,row).y=(row-1)*64-(numberofrows*64)+(9*64)
`sprite tile(column,row).spritenumber,(column-1)*64-13,tile(column,row).y,sprite image(tile(column,row).spritenumber)
`set sprite tile(column,row).spritenumber,1,0
endif
next row
next column
endfunction
function scroll_tiles()
for row=1 to numberofrows
for column=1 to 13
spriteID=tileimage(tile(column,row).imagetype).spriteID
if spriteID>0
`imageID=tileimage(tile(column,row).imagetype).imagenumber
tile(column,row).y=tile(column,row).y+tilespeed#
if tile(column,row).y>-64 and tile(column,row).y<screen height()-64
Paste sprite SpriteID,(column-1)*64-32,tile(column,row).y
if left$(tile(column,row).imagename,1)="d" and tile(column,row).occupied=0
tile(column,row).occupied=1
make_new_object((column-1)*64-16,tile(column,row).y+16,rnd(24)+6,100,6000)
endif
endif
endif
next column
next row
endfunction
function set_player()
player.xpos=(screen width()-32)/2
player.ypos= screen height()-115
player.height =10
player.animation_step=50
player.animation_time=timer()+player.animation_step
player.animation_frame=1
player.start_frame=1
player.end_frame=4
player.next_move=timer()+3
player.shadow=5
player.next_fire=timer()
player.fire_speed=500
endfunction
function animate_player()
if timer()>player.animation_time
inc player.animation_frame
if player.animation_frame>player.end_frame then player.animation_frame=player.start_frame
player.animation_time=timer()+player.animation_step
endif
endfunction
function draw_player()
sprite 1,player.xpos,player.ypos,player.animation_frame
sprite 2,player.xpos+(player.height/2)+2,player.ypos+player.height+2,player.shadow
set sprite priority 1,5+player.height
set sprite priority 2,4+player.height
set sprite alpha 2,80-player.height
scale sprite 1,85+player.height/2
scale sprite 2,85+player.height/1.5
if sprite collision(1,0)>2 then check_player_collision()
endfunction
function disect(filename as string,across,down,imagestart)
load bitmap filename,1
x=bitmap width(1)/across
y=bitmap height(1)/down
for a = 0 to down-1
for b = 0 to across-1
get image imagestart+a*across+b,x*b,y*a,x*b+x,y*a+y
next b:next a
delete bitmap 1
endfunction
function controls()
if upkey()=1 then dec player.ypos,2
if downkey()=1 then inc player.ypos,2
if leftkey()=1 then dec player.xpos,2
if rightkey()=1 then inc player.xpos,2
if keystate(31)=1 then inc player.height,1
if keystate(17)=1 then dec player.height,1
if spacekey()=1 and timer()>player.next_fire then add_missile(8)
if player.height<6 then player.height=6
if player.height>30 then player.height=30
if player.xpos<5 then player.xpos=5
if player.xpos>screen width()-37 then player.xpos=screen width()-37
if player.ypos>screen height()-115 then player.ypos=screen height()-115
if player.ypos<128 then player.ypos=128
endfunction
function make_temp_background()
load image "BackGround.png",BACKGROUND_IMAGE,1
load image "Clouds.png",CLOUD_IMAGE,1
load image "Trees.png",TREES_IMAGE,1
endfunction
function draw_background()
paste image BACKGROUND_IMAGE,0,background_scroll
paste image BACKGROUND_IMAGE,0,background_scroll+screen height()*2
inc background_scroll,background_scroll_rate
if background_scroll>screen_height*2 then dec background_scroll,screen height()*2
paste image TREES_IMAGE,0,tree_scroll,1
paste image TREES_IMAGE,0,tree_scroll+screen height()*1.5,1
inc tree_scroll,tree_scroll_rate
if tree_scroll>screen_height*1.5 then dec tree_scroll,screen height()*1.5
sprite CLOUD_IMAGE,0,cloud_scroll,CLOUD_IMAGE
sprite CLOUD_IMAGE+1,0,cloud_scroll+screen height()*1.5,CLOUD_IMAGE
set sprite priority CLOUD_IMAGE,30
set sprite priority CLOUD_IMAGE+1,30
inc cloud_scroll,cloud_scroll_rate
if cloud_scroll>screen_height*1.5 then dec cloud_scroll,screen height()*1.5
sprite 3,0,522,5001
set sprite 3,0,1
set sprite priority 3,100
score$=str$(score)
for a = len(score$) to 1 step -1
value=val(mid$(score$,a))
if value=0 then value=10
sprite 8+a,751-((len(score$)-a)*16),554,29+value
set sprite priority 8+a,110
next a
endfunction
function add_missile(offset)
array insert at top player_missile()
player_missile(0).xpos=player.xpos+offset
player_missile(0).ypos=player.ypos-16
player_missile(0).height=player.height
player_missile(0).start_frame=10
player_missile(0).end_frame=13
player_missile(0).animation_step=50
player_missile(0).animation_time=timer()+50
player_missile(0).animation_frame=10
player_missile(0).shadow=14
player_missile(0).sprite_number=free_sprite()
sprite player_missile(0).sprite_number,player_missile(0).xpos,player_missile(0).ypos,player_missile(0).animation_frame
player_missile(0).shadow_number=free_sprite()
sprite player_missile(0).shadow_number,player_missile(0).xpos+(player_missile(0).height/2),player_missile(0).ypos+player_missile(0).height,player_missile(0).shadow
set sprite alpha player_missile(0).shadow_number,80-player_missile(0).height
set sprite priority player_missile(0).sprite_number,50
set sprite priority player_missile(0).shadow_number,40
player.next_fire=timer()+player.fire_speed
endfunction
function draw_missiles()
for a = array count(player_missile()) to 0 step -1
dec player_missile(a).ypos,3
if timer()>player_missile(a).animation_time
inc player_missile(a).animation_frame
if player_missile(a).animation_frame>player_missile(a).end_frame then player_missile(a).animation_frame=player_missile(a).start_frame
player_missile(a).animation_time=timer()+player_missile(a).animation_step
endif
sprite player_missile(a).sprite_number,player_missile(a).xpos,player_missile(a).ypos,player_missile(a).animation_frame
sprite player_missile(a).shadow_number,player_missile(a).xpos+(player_missile(a).height/2),player_missile(a).ypos+player_missile(a).height,player_missile(a).shadow
set sprite alpha player_missile(a).shadow_number,80-player_missile(a).height
set sprite priority player_missile(a).sprite_number,player_missile(a).height+5
set sprite priority player_missile(a).shadow_number,player_missile(a).height+4
if player_missile(a).ypos<-16
kill_missile(a)
else
if array count(perm_object_tile())>=0 then check_shot_object_collision(a)
endif
next a
endfunction
function check_shot_object_collision(count)
hit=sprite collision(player_missile(count).sprite_number,0)
if hit=0 then exitfunction
for a = array count(perm_object_tile()) to 0 step -1
if sprite collision(player_missile(count).sprite_number,perm_object_tile(a).sprite_number)=1 and player_missile(count).height<=perm_object_tile(a).height
add_explosion(player_missile(count).xpos-8,player_missile(count).ypos-8)
kill_missile(count)
inc score,perm_object_tile(a).points
kill_doodad(a)
exitfunction
endif
next a
endfunction
function kill_missile(count)
delete sprite player_missile(count).sprite_number
delete sprite player_missile(count).shadow_number
array delete element player_missile(),count
endfunction
`temporary function to test added features
function test_features()
if inkey$()="1" then player.gun_strength=1
if inkey$()="2" then player.gun_strength=2
if inkey$()="3" then player.gun_strength=3
if inkey$()="=" then add_explosion(rnd(screen width()),rnd(screen height())):add_explosion(rnd(screen width()),rnd(screen height()))
endfunction
function add_doodad(xpos,ypos,image)
array insert at bottom object_tile()
count=array count(object_tile())
object_tile(count).xpos=xpos
object_tile(count).ypos=ypos
object_tile(count).image=image
endfunction
function scroll_doodads()
for a = array count(object_tile()) to 0 step -1
if object_tile(a).ypos<=DISTANCE_TRAVELLED-32
make_new_object(object_tile(a).xpos,object_tile(a).ypos-DISTANCE_TRAVELLED-32,object_tile(a).height,object_tile(a).points,object_tile(a).image)
array delete element object_tile(),a
endif
next a
endfunction
function make_new_object(xpos,ypos,height,points,image)
array insert at bottom perm_object_tile()
count=array count(perm_object_tile())
perm_object_tile(count).xpos=xpos
perm_object_tile(count).ypos=ypos
perm_object_tile(count).image=image
perm_object_tile(count).height=height
perm_object_tile(count).points=points
perm_object_tile(count).sprite_number=free_sprite()
sprite perm_object_tile(count).sprite_number,perm_object_tile(count).xpos,perm_object_tile(count).ypos,perm_object_tile(count).image
Set Sprite Priority perm_object_tile(count).sprite_number,perm_object_tile(count).height
perm_object_tile(count).shadow=free_sprite()
Sprite perm_object_tile(count).shadow,perm_object_tile(count).xpos,perm_object_tile(count).ypos,perm_object_tile(count).image
Set Sprite Diffuse perm_object_tile(count).shadow,0,0,0
Set Sprite Alpha perm_object_tile(count).shadow,50
Set Sprite Priority perm_object_tile(count).shadow,perm_object_tile(count).height-1
endfunction
function scroll_perm_doodads()
for a = array count(perm_object_tile()) to 0 step -1
h=perm_object_tile(a).height
sprite perm_object_tile(a).sprite_number,perm_object_tile(a).xpos,perm_object_tile(a).ypos,perm_object_tile(a).image
Scale Sprite perm_object_tile(a).sprite_number,85+h
sprite perm_object_tile(a).shadow,perm_object_tile(a).xpos+4,perm_object_tile(a).ypos+4,perm_object_tile(a).image
Scale Sprite perm_object_tile(a).shadow,85+h*2
inc perm_object_tile(a).ypos,tilespeed#
if perm_object_tile(a).ypos>screen height() then kill_doodad(a)
next a
endfunction
function kill_doodad(count)
if sprite exist(perm_object_tile(count).sprite_number)=1 then delete sprite perm_object_tile(count).sprite_number
if sprite exist(perm_object_tile(count).shadow)=1 then delete sprite perm_object_tile(count).shadow
array delete element perm_object_tile(),count
endfunction
function free_sprite()
count=spriteseed
repeat
inc count
until sprite exist(count)=0
endfunction count
function free_image()
repeat
inc count
until image exist(count)=0
endfunction count
function add_explosion(xpos,ypos)
array insert at bottom explosion()
count=array count(explosion())
explosion(count).xpos=xpos
explosion(count).ypos=ypos
explosion(count).frame=50
explosion(count).start_frame=50
explosion(count).end_frame=65
explosion(count).next_frame=timer()+50
explosion(count).sprite_number=free_sprite()
sprite explosion(count).sprite_number,explosion(count).xpos,explosion(count).ypos,explosion(count).frame
endfunction
function draw_explosions()
for a = array count(explosion()) to 0 step -1
if timer()>explosion(a).next_frame
inc explosion(a).frame
explosion(a).next_frame=timer()+50
endif
sprite explosion(a).sprite_number,explosion(a).xpos,explosion(a).ypos,explosion(a).frame
if explosion(a).frame>=explosion(a).end_frame then kill_explosion(a)
next a
endfunction
function kill_explosion(count)
if sprite exist(explosion(count).sprite_number) then delete sprite explosion(count).sprite_number
array delete element explosion(),count
endfunction
function check_player_collision()
if player.vulnerable<=timer()
if array count(perm_object_tile())>=0
for a = array count(perm_object_tile()) to 0 step -1
if player.height<=perm_object_tile(a).height
if sprite collision(1,perm_object_tile(a).sprite_number)=1
kill_doodad(a)
add_explosion(player.xpos,player.ypos)
kill_player()
exitfunction
endif
endif
next a
endif
endif
endfunction
function player_state()
if player.vulnerable>timer()
player.start_frame=6:player.end_frame=8
else
player.start_frame=1:player.end_frame=4
endif
endfunction
function kill_player()
player.xpos=(screen width()-32)/2
player.ypos= screen height()-115
player.vulnerable=timer()+3000
endfunction
