Yavin,
see what you think to this now ...
The code has been tightened up to try and make things easy to drop in. For instance, the alien sprites now live in an array and a loop loads them in. Very easy to add new aliens now.
Rem
Pocket Space Invaders
By Paul Grayston aka Yavin (Team Rebellion Software)
The Aim of this project is to create a small
Space Invaders game using some of the new
features found in blitz Max.
This is to help me and others like me in the
process of moving from blitz 3d to blitz max.
I will do what I can to make sure as much of
this source is commented as possible to make
things as clear as possible.
Project Start Date [2nd Jan 2005 - 1Am]
History
* apr05 (jb)
ADD - sounds
ADD - background image
MOD - particles now reflect the colour of the alien they hit
* 21may05 (yavin)
ADD - New Player Sprite, with 2 frames of animation
ADD - Re Added the alien on block collision
ADD - Added Alien Disc sprite
FIX - Aliens now start bellow the gui text at the top
FIX - Aliens now collide with blocks as intended
ADD - Put the GUI menu back in and created better GFX for it
ADD - Put the High Score table back in
FIX - recoded alien on block collisions into the aliens update method
ADD - Alien Ships now collide with player ship
FIX - Fixed some other little code sections and cleaned a few things up
* 21may05 (jb)
MOD - restructed into game state modes (see MAINLOOP)
ADD - bonus ufo now up and running
FIX - animation for ship sorted (bullet fired)
FIX - keyhit bug where spacebar was being ignored
ADD - gameover screen
* 22may05 (jb)
MOD - code tightend up in places
MOD - DestroyAlien added to alien type
MOD - alien sprites live in an array. easy to add more now
Todo List.
* Add Online Score ? (This is being worked on....)
* Frame limiter (Game Timing)
* Enter Name and Game Over ( function in place GameOver() )
* Collisons are buggy, Might need to go back to using images collide.
* Powerups, a small block that drops and when colected it repairs your block defense.
* More levels.
End Rem
Framework BRL.glmax2d
Import BRL.basic
Import BRL.audio
Import BRL.freeaudioaudio
Import BRL.bmpLoader
Import BRL.wavloader
Strict ' Force variable declaration.
' graphics window size
Const GFX_Width :Int = 260
Const GFX_Height :Int = 300
Global SpeedIncrease:Float
Global GAMESTATE:Byte=0 ' what state the game is in (see MAINLOOP)
'Create the Window (width,height,bit-depth(0=windowmode in beta) )
Graphics GFX_Width,GFX_Height,0
SetMaskColor 255,0,255
Type mediatype
Field bkg:TImage = LoadImage("img/galaxy.bmp")
Field menu:Timage = LoadImage ("img/Menu.bmp")
Field gameover:TImage = LoadImage("img/gameover.bmp")
Field blockimage:Timage = LoadImage("img/block.bmp")
Field bulletImage:Timage = LoadImage("img/bullet.bmp")
Field AlienBullet1:TImage = LoadImage("img/alienbullet.bmp")
Field alienshoot:TSound = LoadSound("sfx/alienshoot.wav")
Field changedirection:TSound = LoadSound("sfx/changedirection.wav")
Field killalien:TSound = LoadSound("sfx/killalien.wav")
Field hitblock:TSound = LoadSound("sfx/hitblock.wav")
Field ab_hitblock:TSound = LoadSound("sfx/ab_hitblock.wav")
Field AlienImage:TImage[6]
Method New()
For Local s:Int=0 To 5
AlienImage[s] = LoadImage("img/alien"+String(s+1)+".bmp")
Next
End Method
End Type
Global media:mediatype=New mediatype
Global Hscore$[5+1,2+1]
For Local looper:Int=1 To 5
Hscore$[looper,1]="Name-"+String(looper)
Hscore$[looper,2]=String(600-(looper*100))
Next
'********************************************************************
'
' Fields common to all game items.
'
'********************************************************************
Type CommonFields
Field X :Float
Field Y :Float
Field speed :Float
Field life :Int
Field Sprite :TImage
End Type
'********************************************************************
'
' PARTICLE CODE
'
'********************************************************************
Global partlist:TList = CreateList()
Type part
Field x :Float
Field y :Float
Field velx :Float
Field vely :Float
Field speed :Float
Field life :Int
Field r,g,b :Int
Method New()
Local angle:Int
angle=Rand(1,360)
speed=2
life=50
velx=Cos(angle)*(speed+Rand(-1,1))
vely=Sin(angle)*(speed+Rand(-1,1))
ListAddLast partlist,Self
End Method
Function position(x:Float,y:Float,rad:Int=5)
For parts = EachIn partlist
If parts.x=0 And parts.y=0
parts.x=x+Rand(-rad,rad)
parts.y=y+Rand(-rad,rad)
End If
Next
End Function
Method update()
x:+velx ; y:+vely
r:-5 ; g:-5 ; b:-5
If r<0 r=0
If g<0 g=0
If b<0 b=0
life:-1
If life=<0
ListRemove partlist,Self
FlushMem
EndIf
End Method
Method draw()
SetColor r,g,b
DrawRect x,y,2,2
End Method
End Type
Global Parts:Part
'********************************************************************
'
' PLAYER CODE
'
'********************************************************************
Type player Extends CommonFields
Field Score:Int
Field level:Int
Field GunTimer:Int
Field GunInterval:Int
Field playmode:Byte
Field timeout:Int
Field sfxShoot:TSound
Field sfxDie:TSound
Field frame:Int
Method New ()
guntimer=MilliSecs()
guninterval=150
level=1
score=0
Sprite=LoadAnimImage("img/ship.bmp",20,20,0,2)
sfxShoot=LoadSound("sfx/shoot.wav")
sfxDie=LoadSound("sfx/killplayer.wav")
x=GFX_Width/2
y=GFX_Height-(Sprite.Height) ' ImageHeight
life=3
speed=3
End Method
Method MoveLeft()
x:-Speed
If x<1 Then x=1
End Method
Method MoveRight()
x:+Speed
If x>GFX_Width-(sprite.width) Then x=GFX_Width-(sprite.width)
End Method
Method Draw()
If life=0
SetColor timeout,0,0
Else
If timeout>0 And playmode=0
SetColor 128+Sin(MilliSecs())*90,0,0
Else
SetColor 255,255,255
EndIf
EndIf
DrawImage Sprite,x,y,Sgn(frame)
frame=frame-(frame>0)
SetAlpha 1.0
End Method
Method Shoot()
If timeout=0 And BulletCount<=3
If MilliSecs()-guntimer=>guninterval
PlayerBullets = New PlayerBullet
guntimer=MilliSecs()
PlaySound sfxShoot
frame=5
EndIf
EndIf
End Method
End Type
Global Player1:player = New player
'********************************************************************
'
' ALIEN CODE
'
'********************************************************************
Global AlienList:TList = CreateList()
Global AlienCount:Int=0
Type alien Extends CommonFields
Global movespeed:Float
Global guntimer
Global guninterval
Field value:Int
Field level:Int
Method New()
guntimer=MilliSecs()
guninterval=800-(player1.level*10)
life=1
ListAddLast Alienlist,Self
alienCount:+1
End Method
Method Draw()
DrawImage Sprite,x,y
End Method
Function CheckDirection()
For Local a:alien = EachIn alienlist
If a.movespeed<0 ' left
If (a.x+a.movespeed)<=0
Return True
EndIf
Else
If (a.x+a.movespeed)>=GFX_Width ' right
Return True
EndIf
EndIf
Next
End Function
Function ShuntDown()
movespeed=-movespeed
PlaySound media.changedirection
For Local a:alien = EachIn alienlist
a.x:+a.movespeed
a.y:+10
Next
End Function
Method DestroyAlien()
life:-1
If life=0
Select level
Case 1 ; Explode x,y,4,255,255,255
Case 2 ; Explode x,y,4,255,255,0
Case 3 ; Explode x,y,4,255,0,0
Case 4 ; Explode x,y,4,0,255,255
Case 5 ; Explode x,y,4,0,0,255
Case 6 ; Explode x,y,4,255,0,255
End Select
player1.score:+value
PlaySound media.killalien
If movespeed<0 Then movespeed:-.15 Else movespeed:+.15
AlienCount:-1
ListRemove alienlist,Self
FlushMem
EndIf
End Method
Method update()
x:+movespeed
If y>GFX_Height Or life=<0
DestroyAlien
EndIf
' check aliens collide with blocks
For blocks = EachIn blocklist
If ImagesOverlap(Self,blocks)
DestroyAlien
blocks.y:+5
blocks.life:-2
End If
Next
' check if player gets hit by alien
If ImagesOverlap(Self,player1)
DestroyAlien
Explode player1.x,player1.y,3,255,40,255
Explode player1.x,player1.y,4,160,140,30
Explode player1.x,player1.y,5,16,140,230
player1.timeout=200
PlaySound player1.sfxDie
player1.life:-1
If player1.life=0
player1.playmode=2 ; player1.timeout=200
EndIf
End If
End Method
End Type
Global Aliens:alien
'********************************************************************
'
' UFO CODE
'
'********************************************************************
Type ufotype Extends CommonFields
Field sfx:TSound
Field sfxDie:TSound
Method New()
sprite=LoadImage("img/ufo.bmp")
sfx=LoadSound("sfx/ufo.wav")
sfxDie=LoadSound("sfx/killufo.wav")
y=24
End Method
Method init()
life=1 ; PlaySound sfx
speed=2 ; x=-20
If Rnd(1)>.5
speed=-2 ; x=GFX_Width+20
EndIf
End Method
Method update()
If life<>0
x:+speed
If x<-24 Or x>GFX_Width+24
life=0
EndIf
EndIf
End Method
Method draw()
SetColor $ff,$ff,$ff
If life<>0 DrawImage sprite,x,y
End Method
End Type
Global ufo:ufotype=New ufotype
'********************************************************************
'
' DEFENCE BLOCKS CODE
'
'********************************************************************
Global Blocklist:TList
Blocklist = CreateList()
Type block Extends CommonFields
Field Origin:Int
Method New()
Origin = GFX_Height-10-(player1.sprite.height) 'ImageHeight
Sprite=media.BlockImage
MidHandleImage sprite
life=250
ListAddLast Blocklist,Self
End Method
Method Draw()
If life>0
SetColor 255,life,life
DrawImage Sprite,x,y
EndIf
End Method
End Type
Global Blocks:Block
For Local b:Int =1 To 3
blocks:Block = New Block
blocks.x= b*(GFX_Width/3)-blocks.sprite.width*2
blocks.y=GFX_Height-10-player1.sprite.height
Next
'********************************************************************
'
' PLAYER BULLET CODE
'
'********************************************************************
Global Bulletlist:TList = CreateList()
Global BulletCount:Int
Type PlayerBullet Extends CommonFields
Method New()
speed=2.8
sprite=media.BulletImage
x=player1.x+(player1.sprite.width/2)-2
y=player1.y-2
life=1
ListAddLast bulletlist,Self
BulletCount:+1
End Method
' check player bullets against blocks and aliens
Method collisionCheck()
' check player bullets collide with defence blocks
For blocks= EachIn blocklist
If blocks.life>0
If ImagesOverlap(Self,blocks)
life=0
blocks.life:-10
If blocks.life=<0 Then blocks.life=0
If blocks.y>blocks.Origin
blocks.y:-2
If blocks.y<blocks.origin Then blocks.y=blocks.origin
End If
PlaySound media.hitblock
Explode blocks.x,blocks.y,1,100,100,100
End If
EndIf
Next
' check player bullets collide with aliens
For aliens=EachIn alienlist
If ImagesOverlap(Self,aliens)
life=0
aliens.DestroyAlien
Exit
End If
Next
' check bullets collide with ufo
If ufo.life<>0
If ImagesOverlap(Self,ufo)
player1.score:+50
ufo.life=0
Explode ufo.x,ufo.y,3,$ff,$ff,$ff
PlaySound ufo.sfxDie
EndIf
EndIf
End Method
Method update()
y:-speed
If y<0 Or life=0
ListRemove bulletlist,Self
BulletCount:-1
FlushMem
EndIf
End Method
Method Draw()
DrawImage sprite,x,y
End Method
End Type
'********************************************************************
'
' ALIENBULLET CODE
'
'********************************************************************
Type AlienBullet Extends CommonFields
Method New()
speed=0.5
sprite=media.AlienBullet1
life=1
ListAddLast bulletlist,Self
End Method
' check alien bullet against blocks and player
Method collisionCheck()
' check 'alien bullets' against blocks
If player1.timeout>0 Return
For blocks=EachIn blocklist
If blocks.life>0
If ImagesOverlap(Self,blocks)
life=0
blocks.life:-30
If blocks.life=<0 Then blocks.life=0
PlaySound media.ab_hitblock
Explode blocks.x,blocks.y,1,100,100,100
End If
EndIf
' check if player gets hit by alien bullet
If ImagesOverlap(Self,player1)
Explode player1.x,player1.y,3,255,40,255
Explode player1.x,player1.y,4,160,140,30
Explode player1.x,player1.y,5,16,140,230
player1.timeout=200
PlaySound player1.sfxDie
player1.life:-1
If player1.life=0
player1.playmode=2 ; player1.timeout=200
EndIf
Exit
End If
Next
End Method
Method Update()
y:+speed
If y>GFX_Height Or life=0
ListRemove bulletlist,Self
FlushMem
EndIf
End Method
Method Draw()
DrawImage sprite,x,y
End Method
End Type
Global PlayerBullets:PlayerBullet
Global AlienBullets:AlienBullet
'********************************************************************
#MAINLOOP
Repeat
Select GAMESTATE
Case 0 ; GUIScreen
Case 4 ; InitGame
Case 1 ; PlayGame
Case 3 ; GameOverScreen
Case 9 ; Exit
End Select
Forever
End
'********************************************************************
'
' Functions
'
'********************************************************************
Function GUIScreen()
Cls
SetColor $ff,$ff,$ff
DrawImage media.menu,0,0
SetColor 0,$ff,0
DrawText "PRESS SPACE",84,250
DrawText "HighScore",84,145
For Local looper:Int=1 To 5
DrawText Hscore$[looper,1],84,163+looper*12
DrawText Hscore$[looper,2],139,163+looper*12
Next
FlushMem
Flip
If KeyHit(KEY_SPACE)
GAMESTATE=4 ; FlushKeys
EndIf
If KeyHit(KEY_ESCAPE) GAMESTATE=9
End Function
Function InitGame()
SpeedIncrease=0.4
LoadWave player1.level
GAMESTATE=1
End Function
Function ResetGame()
ClearList alienlist
ClearList bulletlist
ClearList partlist
AlienCount=0
player1.level=1
player1.score=0
player1.x=GFX_Width/2
player1.y=GFX_Height-(player1.Sprite.Height)
player1.life=3
player1.playmode=0
player1.timeout=0
ufo.life=0
bulletcount=0
For blocks=EachIn blocklist
blocks.life=250
blocks.y=GFX_Height-10-player1.sprite.height
Next
End Function
Function PlayGame()
Cls
UpdateGame
RenderGame
If KeyHit(KEY_ESCAPE)
GAMESTATE=0 ; FlushKeys
ResetGame
EndIf
FlushMem
Flip
End Function
Function GameOverScreen()
Cls
SetColor $ff,$ff,$ff
DrawImage media.gameover,0,0
SetColor 0,$ff,0
DrawText "PRESS SPACE",84,250
FlushMem
Flip
ResetGame
If KeyHit(KEY_SPACE)
GAMESTATE=0
FlushKeys
EndIf
End Function
Function UpdateGame()
Global thisalien,alientoshoot
If player1.life>0
'Call the player move left and right methods.
If KeyDown(KEY_LEFT) player1.moveleft
If KeyDown(KEY_RIGHT) player1.moveright
If KeyDown(KEY_UP) Or KeyDown(KEY_SPACE)
If player1.playmode=0 player1.shoot
EndIf
' bring on the ufo
If ufo.life=0
If Rand(1000)=8 ufo.init
EndIf
EndIf
ufo.update
' which alien will shoot a bullet?
alientoshoot=Rand(1,AlienCount)
thisalien=0
For aliens = EachIn alienlist
aliens.update
thisalien:+1
If player1.life>0
If thisalien=alientoshoot
If MilliSecs()-aliens.guntimer>aliens.guninterval
If Rand(5)=Rand(5)
aliens.guntimer=MilliSecs()
AlienBullets=New alienBullet
AlienBullets.x=aliens.x
AlienBullets.y=aliens.y
AlienBullets.speed:+SpeedIncrease+(player1.level/5)+Rnd(1)
PlaySound media.alienshoot
EndIf
EndIf
EndIf
EndIf
Next
If aliens.CheckDirection() Then aliens.ShuntDown
For PlayerBullets = EachIn bulletlist
PlayerBullets.collisioncheck
PlayerBullets.update
Next
For AlienBullets = EachIn bulletlist
AlienBullets.collisioncheck
AlienBullets.update
Next
For parts=EachIn partlist
parts.update
Next
' load next level when no aliens are left
If AlienCount=0
If player1.playmode=0
player1.playmode=1 ; player1.timeout=150 ' disable shooting etc ..
EndIf
player1.timeout:-(player1.timeout>0)
If player1.timeout=1
player1.level:+1
If player1.level=>11 Then player1.level=1
LoadWave player1.level
player1.playmode=0 ; player1.timeout=0
EndIf
End If
' if player got hit ship will be out of action until timeout is zero
player1.timeout:-(player1.timeout>0)
' if player has lost last life
If player1.life=0
player1.timeout:-(player1.timeout>0)
If player1.timeout=0
GAMESTATE=3 ' gameover
ResetGame
FlushKeys
EndIf
EndIf
End Function
Function RenderGame()
SetColor 255,255,255
DrawImage media.bkg,0,0
DrawText "Scr: "+Player1.score,1,3
DrawText "Lvl: "+player1.level,GFX_Width-58,3
SetScale 0.4,0.4
For Local d=0 Until Player1.life
DrawImage Player1.sprite,10+d*12,GFX_Height-12
Next
SetScale 1.0,1.0
Player1.Draw
For blocks = EachIn BlockList
blocks.draw
Next
ufo.draw
For aliens = EachIn alienList
Select Aliens.level
Case 1 ; SetColor 255,255,255
Case 2 ; SetColor 255,255,0
Case 3 ; SetColor 255,0,0
Case 4 ; SetColor 0,255,255
Case 5 ; SetColor 0,0,255
Case 6 ; SetColor 255,0,255
End Select
aliens.draw
Next
SetColor 255,255,255
For PlayerBullets = EachIn BulletList
PlayerBullets.draw
Next
For AlienBullets=EachIn bulletlist
AlienBullets.draw
Next
For parts = EachIn partlist
parts.draw
Next
If player1.playmode=1 ' show "next wave" message
SetColor 250-player1.timeout,250-player1.timeout,250-player1.timeout
DrawText "Next Wave ...",GFX_Width/8*3,GFX_Height/2
EndIf
End Function
Function ImagesOverlap:Int(i1:CommonFields,i2:CommonFields)
' sprite 1 rect area
Local x0 = i1.x - i1.sprite.handle_x
Local y0 = i1.y - i1.sprite.handle_y
Local x1 = x0 + i1.sprite.width
Local y1 = y0 + i1.sprite.height
' sprite 2 rect area
Local x2 = i2.x - i2.sprite.handle_x
Local y2 = i2.y - i2.sprite.handle_y
Local x3 = x2 + i2.sprite.width
Local y3 = y2 + i2.sprite.height
' check overlapping
If x0 > x3 Or x1 < x2 Then Return False
If y0 > y3 Or y1 < y2 Then Return False
Return True
End Function
Function LoadWave(id:Int)
SpeedIncrease:+0.2
Local px:Int,py:Int,w:String
If id=11 Or id=1 Then RestoreData level
For py = 1 To 6
ReadData w
For px =0 Until Len(w)
Local temp:Int
If w[px]=120 ' character 'x'
aliens = New alien
aliens.movespeed=SpeedIncrease
aliens.x=px*10 ; aliens.y=24+(py*10)
aliens.value=6-py
aliens.level=py
Select py
Case 1 ; aliens.sprite=media.AlienImage[5]
Case 2 ; aliens.sprite=media.AlienImage[4]
Case 3 ; aliens.sprite=media.AlienImage[3]
Case 4 ; aliens.sprite=media.AlienImage[2]
Case 5 ; aliens.sprite=media.AlienImage[1]
Case 6 ; aliens.sprite=media.AlienImage[0]
End Select
MidHandleImage aliens.sprite
End If
Next
Next
End Function
Function Explode(x:Float,y:Float,rad:Int,r:Int,g:Int,b:Int)
For Local looper:Int= 1 To 30
parts = New part
parts.position x,y,rad
parts.r=r
parts.g=g
parts.b=b
Next
End Function
#Level
'level 1
DefData "..x..x.."
DefData ".xxxxxx."
DefData "xx.xx.xx"
DefData "xx.xx.xx"
DefData "..x..x.."
DefData ".x.xx.x."
'level 2
DefData "...xx..."
DefData "...xx..."
DefData "...xx..."
DefData "..xxxx.."
DefData ".xxxxxx."
DefData "xxxxxxxx"
'level 3
DefData "xxxx.x.x"
DefData "x....x.x"
DefData "x....x.x"
DefData "xxx..x.x"
DefData "x....x.x"
DefData "x..x..x."
'level 4
DefData "xx....xx"
DefData ".xx..xx."
DefData "..x..x.."
DefData "........"
DefData ".xxxxxx."
DefData "...xxx.."
'level 5
DefData "..xxxx.."
DefData ".xxxxxx."
DefData ".x....x."
DefData ".xxxxxx."
DefData ".xxxxxx."
DefData "..xxxx.."
'level 6
DefData "..x.x.x.x.."
DefData "x.x.x.x.x.x"
DefData "..x.x.x.x.."
DefData "x.x.x.x.x.x"
DefData "..x.x.x.x.."
DefData "..x.x.x.x.."
'level 7
DefData "xxxxxxxxx"
DefData "........"
DefData "xxxxxxxxx"
DefData "........"
DefData "xxxxxxxxx"
DefData "..xxxxx.."
'level 8
DefData "x.....xx."
DefData "x....x..x"
DefData "x.....xx."
DefData "x....x..x"
DefData "x....x..x"
DefData "xxx...xx."
'level 9
DefData "..xxxxx.."
DefData ".xx...xx."
DefData ".xx...xx."
DefData "..xxxxxx."
DefData "......xx."
DefData ".xxxxxx.."
'level 10
DefData ".x...xxxx."
DefData "xx..x....x"
DefData ".x..x....x"
DefData ".x..x....x"
DefData ".x..x....x"
DefData "xxx..xxxx."
Lastest media for game here:
Pocket Invaders - MEDIA