From c93d5990b230175597557978d0bc2c094bee3bdb Mon Sep 17 00:00:00 2001 From: Ian C Date: Tue, 25 Apr 2006 23:45:01 +0000 Subject: Initial working version --- GFX/asteroid.c4d | Bin 0 -> 46205 bytes GFX/asteroid.png | Bin 0 -> 1706 bytes GFX/sprites.bms | Bin 4231 -> 3187 bytes gametypes.bmx | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- global.bmx | 85 ++++++++++----- missile_lock.bmx | 174 ++++++++++++++++++++++++++---- particle.bmx | 53 +++++---- 7 files changed, 552 insertions(+), 83 deletions(-) create mode 100644 GFX/asteroid.c4d create mode 100644 GFX/asteroid.png diff --git a/GFX/asteroid.c4d b/GFX/asteroid.c4d new file mode 100644 index 0000000..d619e3d Binary files /dev/null and b/GFX/asteroid.c4d differ diff --git a/GFX/asteroid.png b/GFX/asteroid.png new file mode 100644 index 0000000..c36dce7 Binary files /dev/null and b/GFX/asteroid.png differ diff --git a/GFX/sprites.bms b/GFX/sprites.bms index 3673e52..8e5ba6f 100644 Binary files a/GFX/sprites.bms and b/GFX/sprites.bms differ diff --git a/gametypes.bmx b/gametypes.bmx index 4b0875a..caf9a24 100644 --- a/gametypes.bmx +++ b/gametypes.bmx @@ -23,51 +23,122 @@ Strict Import noddybox.algorithm Import "global.bmx" +Import "particle.bmx" + +Const SHIP_TURN:Double=2 +Const SHIP_MAX_SPEED:Double=2.5 +Const SHIP_SPEED:Double=0.05 +Const SHIP_MIN_SPEED:Double=1 + +Const MIN_TURN:Double=1 +Const MAX_TURN:Double=5.0 +Const MIN_SPEED:Double=1 +Const MAX_SPEED:Double=1.99 Type GameState - Global score:Int=0 - Global x:Double=0 - Global y:Double=0 - Global ang:Int=0 - Global lives:Int=0 + Global score:Int=0 + Global x:Double=0 + Global y:Double=0 + Global ang:Double=0 + Global speed:Double=SHIP_MIN_SPEED + Global lives:Int=3 + Global level:Int=1 + Global max_missile:Int=1 + Global missile_turn:Double=0.5 + Global missile_speed:Double=1 + Global shield:Int=5*HERTZ + Global game_over:Int=False + Global hit:Int=False Function Reset() score=0 x=400 y=300 ang=0 + speed=SHIP_MIN_SPEED lives=3 + SetLevel(1) + ShieldShip() + game_over=False + End Function + + Function ShieldShip() + shield=5*HERTZ + End Function + + Function ShieldDown() + lives:-1 + hit=True + ShieldShip() + If lives<0 Then game_over=True + End Function + + Function AddScore(s:Int) + score:+s + If score>GameConfig.hiscore + GameConfig.hiscore=score + EndIf + End Function + + Function LevelUp() + SetLevel(level+1) + End Function + + Function SetLevel(l:Int) + level=l + hit=False + max_missile=Min(50,l*2) + missile_turn=Min(MAX_TURN,MIN_TURN+Double(level)/4) + missile_speed=Min(MAX_SPEED,MIN_SPEED+Double(level)/4) End Function Function Control() If KeyDown(GameConfig.kleft) - ang:-2 - If ang<0 Then ang:+360 + ang:-SHIP_TURN End If + If KeyDown(GameConfig.kright) - ang=(ang+2) Mod 360 + ang:+SHIP_TURN End If + + If KeyDown(GameConfig.kthrust) And speed<=SHIP_MAX_SPEED + speed=Min(SHIP_MAX_SPEED,speed+SHIP_SPEED) + Else + speed=Max(SHIP_MIN_SPEED,speed-SHIP_SPEED/2) + End If + + If KeyDown(GameConfig.kpause) + End If + + If KeyHit(KEY_ESCAPE) + game_over=True + EndIf End Function Function Move() - x=(x+Lookup.si[ang]*2) Mod 800 - y=(y-Lookup.co[ang]*2) Mod 600 + x=(x+Sin(ang)*speed) Mod 800 + y=(y-Cos(ang)*speed) Mod 600 If x<0 Then x:+800 If y<0 Then y:+600 Trail.Add() + If shield Then shield:-1 End Function Function Display() - Local s:String="LIVES " + Local s:String="" For Local f:Int=1 To lives s:+"~~" Next - GFX.font.Draw("SCORE",0,-0) + GFX.font.Draw("SCORE",0,0) GFX.font.Draw(Number.Format(score),0,16,255,255,0) - GFX.font.Centre(s,0) + GFX.font.Centre("SHIELDS",0) + GFX.font.Centre(s,16) + + GFX.font.Draw("LEVEL " + level,0,584) + GFX.font.Draw("MISSILES " + MissileSet.Count(),623,584) GFX.font.DrawRight("HISCORE",799,0) GFX.font.DrawRight(Number.Format(GameConfig.hiscore),799,16,255,255,0) @@ -93,18 +164,19 @@ End Type Type Backdrop + Const NUM:Int=100 Global s:BackdropStar[] Function Init() - s=New BackdropStar[400] + s=New BackdropStar[NUM] - For Local f:Int=0 To 399 + For Local f:Int=0 Until NUM s[f]=New BackdropStar Next End Function Function Draw() - For Local f:Int=0 To 399 + For Local f:Int=0 Until NUM SetColor(s[f].r,s[f].g,s[f].b) DrawImage(GFX.star,s[f].x,s[f].y) Next @@ -167,3 +239,222 @@ Type Trail SetScale(1,1) End Function End Type + +Type Missile + Field x:Double + Field y:Double + Field ang:Double + Field onscreen:Int + Field turn:Double + Field speed:Double + + Method New() + Select Rand(1,4) + Case 1 + x=Rand(0,800) + y=Rand(-100,0) + ang=180 + Case 2 + x=Rand(0,800) + y=Rand(600,700) + ang=0 + Case 3 + y=Rand(0,600) + x=Rand(-100,0) + ang=90 + Case 4 + y=Rand(0,600) + x=Rand(800,900) + ang=270 + End Select + speed=Rnd(Max(MIN_SPEED,GameState.missile_speed-0.1),GameState.missile_speed) + turn=Rnd(Max(MIN_TURN,GameState.missile_turn-0.1),GameState.missile_turn) + onscreen=False + End Method + + Method Update() + If onscreen + Local a:Double=ATan2(GameState.x-x,y-GameState.y) + + If a<0 Then a:+360 + + a:-ang + + If a<0 + If a>-180 + ang:-turn + Else + ang:+turn + EndIf + ElseIf a>0 + If a>180 + ang:-turn + Else + ang:+turn + EndIf + EndIf + + ang=ang Mod 360 + If ang<0 Then ang:+360 + EndIf + + SetRotation(ang) + x:+Sin(ang)*speed + y:-Cos(ang)*speed + DrawImage(GFX.missile,x,y) + CollideImage(GFX.missile,x,y,0,0,MISSILE_LAYER,Self) + + If onscreen + x=x Mod 800 + y=y Mod 600 + If x<0 Then x:+800 + If y<0 Then y:+600 + Else + onscreen=(x>=0 And x<800 And y>=0 And y<600) + EndIf + End Method +End Type + +Type MissileSet + Global plist:TList + Global create:Int + Global wait:Int + + Function Init() + plist=CreateList() + create=0 + End Function + + Function StartLevel() + plist.Clear() + create=GameState.max_missile + wait=HERTZ + End Function + + Function Count:Int() + Return plist.Count() + End Function + + Function Update() + If wait=0 + If create + plist.AddLast(New Missile) + create:-1 + EndIf + wait=HERTZ + Else + wait:-1 + EndIf + + SetColor(255,255,255) + + For Local m:Missile=EachIn plist + m.Update() + Next + + SetRotation(0) + End Function + + Function Nuke:Int() + Local c:Int=plist.Count() + For Local m:Missile=EachIn plist + Particles.AddExplosion(m.x,m.y) + Next + plist.Clear() + Return c + End Function + + Function RemoveMissile(m:Missile) + plist.Remove(m) + End Function + + Function AllDestroyed:Int() + Return (create=0 And plist.Count()=0) + End Function +End Type + + +Type Asteroid + Field x:Double + Field y:Double + Field dx:Double + Field dy:Double + Field ang:Double + Field angi:Double + + Method New() + x=Rand(20,780) + y=Rand(20,580) + Repeat + dx=Rnd(-1,1) + dy=Rnd(-1,1) + Until dx<>0 And dy<>0 + + ang=Rand(360) + + If Abs(dx)>Abs(dy) + angi=dx/2 + Else + angi=dy/2 + EndIf + End Method + + Method Update() + ang:+angi + x=(x+dx) Mod 800 + y=(y+dy) Mod 600 + If x<0 Then x:+800 + If y<0 Then y:+600 + SetRotation(ang) + DrawImage(GFX.asteroid,x,y) + Local o:Object[]=CollideImage(GFX.asteroid,x,y,0,MISSILE_LAYER,ASTEROID_LAYER,Self) + + If o + Particles.AddBigExplosion(x,y) + GameState.AddScore(10*GameState.level) + MissileSet.RemoveMissile(Missile(o[0])) + Return False + Else + Return True + EndIf + End Method +End Type + +Type AsteroidSet + Global plist:TList + + Function Init() + plist=CreateList() + End Function + + Function StartLevel() + plist.Clear() + For Local f:Int=0 Until Max(5,GameState.max_missile) + plist.AddLast(New Asteroid) + Next + End Function + + Function Update() + Local l:TEasyLink=TEasyLink.Create(plist) + + While l.Value() + Local a:Asteroid=Asteroid(l.Value()) + + If (a.Update()) + l.MoveNext() + Else + l.Remove() + EndIf + Wend + SetRotation(0) + End Function + + Function Nuke() + Local c:Int=plist.Count() + For Local a:Asteroid=EachIn plist + Particles.AddExplosion(a.x,a.y) + Next + plist.Clear() + Return c + End Function +End Type diff --git a/global.bmx b/global.bmx index 1d078fa..dedad10 100644 --- a/global.bmx +++ b/global.bmx @@ -37,24 +37,13 @@ Incbin "GFX/missile.png" Incbin "GFX/exhaust.png" Incbin "GFX/flame.png" Incbin "GFX/star.png" +Incbin "GFX/asteroid.png" Const HERTZ:Int=70 -Type Lookup - Global si:Double[] - Global co:Double[] - - Function Init() - si=New Double[360] - co=New Double[360] - - For Local a:Double=0 To 359 - si[a]=Sin(a) - co[a]=Cos(a) - Next - End Function -End Type - +Const MISSILE_LAYER:Int=1 +Const ASTEROID_LAYER:Int=2 +Const ALL_LAYERS:Int=3 Type GFX Global font:TBitmapFont @@ -66,7 +55,9 @@ Type GFX Global exhaust:TImage Global flame:TImage Global star:TImage - + Global asteroid:TImage + Global explosion:TImage + Function SafeLoadImage:TImage(p:String, mode:Int) Local i:TImage=LoadImage(p,mode) Assert i,"Failed to load " + p @@ -98,6 +89,9 @@ Type GFX star=SafeLoadImage("incbin::GFX/star.png",0) SetImageHandle(star,1,1) + + asteroid=SafeLoadImage("incbin::GFX/asteroid.png",FILTEREDIMAGE) + MidHandleImage(asteroid) End Function End Type @@ -105,7 +99,7 @@ Type GameConfig Global kleft:Int Global kright:Int Global kpause:Int - Global kfire:Int + Global kthrust:Int Global hiscore:Int Function Load() @@ -114,7 +108,7 @@ Type GameConfig If s=Null kleft=KEY_LEFT kright=KEY_RIGHT - kfire=KEY_SPACE + kthrust=KEY_SPACE kpause=KEY_P hiscore=0 Return @@ -124,7 +118,7 @@ Type GameConfig kleft=s.ReadInt() kright=s.ReadInt() - kfire=s.ReadInt() + kthrust=s.ReadInt() kpause=s.ReadInt() hiscore=s.ReadInt() @@ -142,7 +136,7 @@ Type GameConfig s.WriteInt(kleft) s.WriteInt(kright) - s.WriteInt(kfire) + s.WriteInt(kthrust) s.WriteInt(kpause) s.WriteInt(hiscore) @@ -185,25 +179,20 @@ Type Scroller Global msg:String Global msgp:Int Global msgx:Int - Global msgy:Int Function Init() msg=" " - msg:+"DURING A TEST-FLIGHT OF THE STAR-FIGHTER OX-9 YOU ARE AMBUSHED IN THE ASTEROID FIELD... " - msg:+"THE EVIL EMPIRE CANNOT BE ALLOWED TO DESTROY THE PROTOTYPE SO YOU MUST PILOT THE WEAPONLESS OX-9 " + msg:+"DURING A TEST-FLIGHT OF THE STAR-FIGHTER XY-9 YOU ARE AMBUSHED IN THE ASTEROID FIELD OUTSIDE OF MARS... " + msg:+"THE EVIL EMPIRE CANNOT BE ALLOWED TO DESTROY THE PROTOTYPE SO YOU MUST PILOT THE WEAPONLESS CRAFT, " msg:+"AVOIDING THE DEADLY MISSILES UNTIL HELP ARRIVES... " msg:+"SHOW HEART YOUNG PILOT, STAR-FLEET IS DEPENDING UPON YOU!" - 'msg:+"TAKE THE LAST REMAINING STAR-FIGHTER AND USE SKILL AND JUDGEMENT TO AVOID THE DEADLY MISSILES THE EVIL ALIENS ARE FIRING AT YOU WHILE " - 'msg:+"DESTROYING THEIR ADVANCING FLEET... " - 'msg:+"SHOW HEART YOUNG PILOT, THE EARTH IS DEPENDING UPON YOU!" msgx=0 msgp=0 - msgy=560 End Function - Function Draw() - GFX.font.Draw(msg[..70],msgx,msgy) + Function Draw(y:Int) + GFX.font.Draw(msg[..70],msgx,y) msgx:-2 If msgx<-GFX.font.TextWidth(msg[0..1]) @@ -213,6 +202,44 @@ Type Scroller End Function End Type +Type Thanks + Global item:String[] + Global i:Int + Global wait:Int + Global a:Double + Global ai:Double + + Function Init() + item=["HTTP://WWW.SLAYRADIO.ORG/", .. + "HTTP://WWW.BLITZBASIC.COM/"] + i=0 + a=0 + ai=0.05 + End Function + + Function Draw(y:Int) + SetAlpha(a) + GFX.font.Centre(item[i],y) + SetAlpha(1) + + If wait + wait:-1 + Else + a:+ai + + If a>1 + wait=HERTZ*5 + ai=-0.05 + a=1 + ElseIf a<0 + i=(i+1) Mod item.length + ai=0.05 + a=0 + EndIf + EndIf + End Function +End Type + Type TFadeScreen Field a:Double Field ai:Double diff --git a/missile_lock.bmx b/missile_lock.bmx index f4a4652..ebd5017 100644 --- a/missile_lock.bmx +++ b/missile_lock.bmx @@ -64,12 +64,14 @@ SetAlpha(1.0) ' GFX.Init() ' MUST be first -Lookup.Init() GameConfig.Load() Scroller.Init() +Thanks.Init() Particles.Init() Backdrop.Init() Trail.Init() +MissileSet.Init() +AsteroidSet.Init() Global quit:Int=False @@ -82,23 +84,147 @@ Menu() While Not quit GameState.Reset() + MissileSet.StartLevel() + AsteroidSet.StartLevel() - While Not KeyHit(KEY_ESCAPE) - Cls + While Not GameState.game_over + + While Not GameState.game_over And Not MissileSet.AllDestroyed() + Cls() + ResetCollisions() + + Backdrop.Draw() + Particles.Draw() + Trail.Draw() + + GameState.Display() + GameState.Control() + GameState.Move() + + SetRotation(GameState.ang) + + If GameState.shield + SetColor(Rand(0,255),Rand(0,255),Rand(0,255)) + Else + SetColor(255,255,255) + EndIf + + DrawImage(GFX.ship,GameState.x,GameState.y) + SetRotation(0) + + MissileSet.Update() + AsteroidSet.Update() + + Local col:Object[]=CollideImage(GFX.ship,GameState.x,GameState.y,0,ALL_LAYERS,0) + + If Not GameState.shield Then + If col + GameState.ShieldDown() + Particles.AddExplosion(GameState.x,GameState.y) + For Local m:Missile=EachIn col + If m + MissileSet.RemoveMissile(m) + GameState.AddScore(1*GameState.level) + Exit + EndIf + Next + EndIf + EndIf + + Flip(1) + Wend + + If Not GameState.game_over + AsteroidSet.Nuke() + + Local bonus=100*GameState.level + Local added:Int=0 + Local timer:Int=Max(HERTZ*5,bonus/10+HERTZ*3) + + If Not GameState.hit + GameState.AddScore(500*GameState.level) + EndIf + + While timer And Not KeyHit(KEY_ESCAPE) + Cls() + ResetCollisions() + + GameState.ShieldShip() + + Backdrop.Draw() + Particles.Draw() + Trail.Draw() + + GameState.Display() + GameState.Control() + GameState.Move() + + SetRotation(GameState.ang) + + If GameState.shield + SetColor(Rand(0,255),Rand(0,255),Rand(0,255)) + Else + SetColor(255,255,255) + EndIf + + DrawImage(GFX.ship,GameState.x,GameState.y) + SetRotation(0) + + GFX.font.Centre("LEVEL " + GameState.level + " COMPLETED!",200,255,255,0) + + GFX.font.Centre("BONUS " + Number.Format(added) + "!!!",400,255,255,0) + + If Not GameState.hit + GFX.font.Centre("PERFECT BONUS " + (500*GameState.level) + "!!!",420,255,255,0) + EndIf + + If added0 - If defkey=4 + If defkey=5 GFX.font.Centre("PRESS A KEY TO GO BACK TO THE MENU",380) Else GFX.font.Centre("DEFINE KEYS",350) @@ -162,13 +287,16 @@ Function Menu() Local c1:Int=128+128*(defkey=1) Local c2:Int=128+128*(defkey=2) Local c3:Int=128+128*(defkey=3) + Local c4:Int=128+128*(defkey=4) GFX.font.Draw("LEFT",250,200,c1,c1,c1) GFX.font.Draw("RIGHT",250,220,c2,c2,c2) - GFX.font.Draw("PAUSE",250,240,c3,c3,c3) + GFX.font.Draw("THRUST",250,240,c3,c3,c3) + GFX.font.Draw("PAUSE",250,260,c4,c4,c4) GFX.font.Draw(KeySym(GameConfig.kleft),500,200,c1,c1,0) GFX.font.Draw(KeySym(GameConfig.kright),500,220,c2,c2,0) - GFX.font.Draw(KeySym(GameConfig.kpause),500,240,c3,c3,0) + GFX.font.Draw(KeySym(GameConfig.kthrust),500,240,c3,c3,0) + GFX.font.Draw(KeySym(GameConfig.kpause),500,260,c4,c4,0) Local k:Int=-1 @@ -190,12 +318,14 @@ Function Menu() Case 2 GameConfig.kright=k Case 3 + GameConfig.kthrust=k + Case 4 GameConfig.kpause=k End Select defkey:+1 - If defkey=5 + If defkey=6 GameConfig.Save() defkey=0 FlushKeys() @@ -207,7 +337,7 @@ Function Menu() quit=True EndIf - If KeyHit(KEY_SPACE) + If KeyHit(GameConfig.kthrust) done=True EndIf @@ -217,11 +347,15 @@ Function Menu() EndIf GFX.font.Centre("COPYRIGHT (C) NODDYBOX 2006",200) + GFX.font.Centre("HTTP://WWW.NODDYBOX.CO.UK/",226) + + GFX.font.Centre("THANKS TO",300) + Thanks.Draw(326) - GFX.font.Centre("PRESS SPACE TO PLAY",300) + GFX.font.Centre("PRESS THRUST TO PLAY",400) - GFX.font.Centre("PRESS R TO REDEFINE KEYS",380) - GFX.font.Centre("PRESS ESCAPE TO QUIT",400) + GFX.font.Centre("PRESS R TO REDEFINE KEYS",480) + GFX.font.Centre("PRESS ESCAPE TO QUIT",500) EndIf If fade diff --git a/particle.bmx b/particle.bmx index 4098598..e511ace 100644 --- a/particle.bmx +++ b/particle.bmx @@ -21,9 +21,7 @@ ' $Id$ ' Strict -Import noddybox.algorithm Import "global.bmx" -Import "gametypes.bmx" Type TParticle Field life:Int @@ -36,40 +34,50 @@ Type TParticle Field ai:Double Field s:Double Field si:Double + Field r:Int + Field g:Int + Field b:Int - Function Image:TParticle(i:TImage, x:Int, y:Int) + Function Image:TParticle(i:TImage, x:Double, y:Double, dx:Double, dy:Double, r:Int, g:Int, b:Int) Local o:TParticle=New TParticle o.life=120 o.x=x o.y=y o.a=1 o.ai=-0.01 - o.dx=0 - o.dy=0 + o.dx=dx + o.dy=dy o.s=1 o.si=0 o.i=i + o.r=r + o.g=g + o.b=b Return o End Function - Function ScaleImage:TParticle(i:TImage, x:Int, y:Int,si:Double) + Function ScaleImage:TParticle(i:TImage, x:Double, y:Double, dx:Double, dy:Double, si:Double, r:Int, g:Int, b:Int) Local o:TParticle=New TParticle o.life=120 o.x=x o.y=y o.a=1 o.ai=-0.01 - o.dx=0 - o.dy=0 + o.dx=dx + o.dy=dy o.s=1 o.si=si o.i=i + o.r=r + o.g=g + o.b=b Return o End Function Method Update:Int() SetAlpha(a) SetScale(s,s) + SetColor(r,g,b) DrawImage(i,x,y) x:+dx y:+dy @@ -91,20 +99,28 @@ Type Particles plist.Clear() End Function - Function AddImage(i:TImage, x:Int, y:Int) - If plist.Count()<1000 - plist.AddLast(TParticle.Image(i,x,y)) - EndIf + Function AddImage(i:TImage, x:Double, y:Double, dx:Double=0, dy:Double=0) + plist.AddLast(TParticle.Image(i,x,y,dx,dy,255,255,255)) End Function - Function AddScaledImage(i:TImage, x:Int, y:Int, si:Double=0.1) - If plist.Count()<1000 - plist.AddLast(TParticle.ScaleImage(i,x,y,si)) - EndIf + Function AddScaledImage(i:TImage, x:Double, y:Double, si:Double=0.1, dx:Double=0, dy:Double=0) + plist.AddLast(TParticle.ScaleImage(i,x,y,dx,dy,si,255,255,255)) + End Function + + Function AddExplosion(x:Double, y:Double) + For Local f:Int=0 To 20 + plist.AddLast(TParticle.Image(GFX.star,x,y,Rnd(-2,2),Rnd(-2,2),Rand(100,255),Rand(100,255),Rand(100,255))) + Next + End Function + + Function AddBigExplosion(x:Double, y:Double) + plist.AddLast(TParticle.ScaleImage(GFX.exhaust,x,y,0,0,0.3,255,0,0)) + For Local f:Int=0 To 50 + plist.AddLast(TParticle.Image(GFX.star,x,y,Rnd(-2,2),Rnd(-2,2),Rand(100,255),Rand(100,255),Rand(100,255))) + Next End Function Function Draw() - SetColor(255,255,255) Local l:TEasyLink=TEasyLink.Create(plist) While l.Value() @@ -118,5 +134,6 @@ Type Particles Wend SetAlpha(1) SetScale(1,1) + SetColor(255,255,255) End Function -End Type +End Type \ No newline at end of file -- cgit v1.2.3