' Vectoroids ' ' Copyright 2005 Ian Cowburn ' ' $Id$ ' Strict Import noddybox.vectorgfx Import noddybox.vector Import noddybox.bitmapfont Import "sounds.bmx" Incbin "GFX/font.bmf" Incbin "2D/ship.2d" Incbin "2D/large.2d" Incbin "2D/medium.2d" Incbin "2D/small.2d" Incbin "2D/ssaucer.2d" Incbin "2D/lsaucer.2d" Incbin "2D/debris.2d" Type Lookup Global si:Double[] Global co:Double[] Function Init() si=New Double[3600] co=New Double[3600] For Local a:Int=0 To 3599 si[a]=Sin(180-Double(a)/10) co[a]=Cos(180-Double(a)/10) Next End Function End Type Type GameGFX Global font:TBitmapFont Global ship:TVectorGfxObject Global large:TVectorGfxObject Global medium:TVectorGfxObject Global small:TVectorGfxObject Global debris:TVectorGfxObject Global lsaucer:TVectorGfxObject Global ssaucer:TVectorGfxObject Function Init() font=TBitmapFont.Load("incbin::GFX/font.bmf",0) ship=TVectorGfxObject.Load("incbin::2D/ship.2d") large=TVectorGfxObject.Load("incbin::2D/large.2d") medium=TVectorGfxObject.Load("incbin::2D/medium.2d") small=TVectorGfxObject.Load("incbin::2D/small.2d") debris=TVectorGfxObject.Load("incbin::2D/debris.2d") lsaucer=TVectorGfxObject.Load("incbin::2D/lsaucer.2d") ssaucer=TVectorGfxObject.Load("incbin::2D/ssaucer.2d") large.scale=1.5 medium.scale=1.5 small.scale=1.5 lsaucer.scale=1.5 ssaucer.scale=2 End Function End Type Type GameConfig Global kleft:Int Global kright:Int Global kfire:Int Global kthrust:Int Global khyper:Int Global kpause:Int Function Load() Local s:TStream=ReadStream("vectoroids.config") If s=Null kleft=KEY_O kright=KEY_P kfire=KEY_Q kthrust=KEY_S khyper=KEY_SPACE kpause=KEY_P Return EndIf s=LittleEndianStream(s) kleft=s.ReadInt() kright=s.ReadInt() kfire=s.ReadInt() kthrust=s.ReadInt() khyper=s.ReadInt() kpause=s.ReadInt() s.Close() End Function Function Save() Local s:TStream=WriteStream("vectoroids.config") If s=Null Return EndIf s=LittleEndianStream(s) s.WriteInt(kleft) s.WriteInt(kright) s.WriteInt(kfire) s.WriteInt(kthrust) s.WriteInt(khyper) s.WriteInt(kpause) s.Close() End Function EndType Type TAsteroid Global minspeed:Double Global maxspeed:Double Field x:Double Field y:Double Field dx:Double Field dy:Double Field obj:TVectorGfxObject Field size:Int Function RndSpeed:Double() Local r:Double=Rnd(minspeed,maxspeed) If Rand(100)<50 Return r Else Return -r EndIf End Function Function Create:TAsteroid() Local no:TAsteroid=New TAsteroid no.obj=GameGFX.large.Clone() no.obj.ang=Rand(3600) If Rand(10)<5 no.x=Rnd(0,GraphicsWidth()/3.0) Else no.x=Rnd(GraphicsWidth()/3.0*2.0,GraphicsWidth()) EndIf no.y=Rnd(0,GraphicsHeight()) no.dx=RndSpeed()/2 no.dy=RndSpeed() no.size=2 Return no End Function Method CreateShard:TAsteroid() Local no:TAsteroid=New TAsteroid no.x=x no.y=y no.size=size-1 If no.size=1 no.obj=GameGFX.medium.Clone() Else no.obj=GameGFX.small.Clone() EndIf no.dx=RndSpeed() no.dy=RndSpeed() no.x:+no.dx*8 no.y:+no.dy*8 no.obj.ang=Rand(3600) Return no End Method Method Update() x:+dx y:+dy If x<-obj.width x:+GraphicsWidth()+obj.width*2 ElseIf x>GraphicsWidth()+obj.width x:-GraphicsWidth()+obj.width*2 EndIf If y<-obj.height y:+GraphicsHeight()+obj.height*2 ElseIf y>GraphicsHeight()+obj.height y:-GraphicsHeight()+obj.height*2 EndIf obj.x=x obj.y=y obj.Draw() End Method Method Blowup:Int(astlist:TList) Local sc:Int=100-size*20 If size>0 astlist.AddLast(CreateShard()) astlist.AddLast(CreateShard()) EndIf astlist.Remove(Self) Return sc End Method EndType Type TShot Field x:Double Field y:Double Field dx:Double Field dy:Double Field life:Int Function Create:TShot(ship:TVectorGfxObject) Local o:TShot=New TShot o.dx=Lookup.si[ship.ang]*2 o.dy=Lookup.co[ship.ang]*2 o.x=ship.x+o.dx*4 o.y=ship.y+o.dy*4 o.life=200 Return o End Function Method Update:Int(shotlist:TList, astlist:TList, saucer:TSaucer) life:-1 If life=0 shotlist.Remove(Self) Return 0 EndIf x:+dx y:+dy If x<0 x:+GraphicsWidth() EndIf If x>=GraphicsWidth() x:-GraphicsWidth() EndIf If y<0 y:+GraphicsHeight() EndIf If y>=GraphicsHeight() x:-GraphicsHeight() EndIf If saucer And Not saucer.dead And saucer.obj.IsInside(x,y) TParticleMachine.ShipExplosion(saucer.x,saucer.y) Sounds.ShipExplosion() Sounds.NoSaucer() shotlist.Remove(Self) saucer.dead=True If saucer.big Return 500 Else Return 1000 EndIf EndIf For Local o:TAsteroid=EachIn astlist If o.obj.IsInside(x,y) TParticleMachine.AsteroidExplosion(o.x,o.y) Sounds.AsteroidExplosion(o.size) shotlist.Remove(Self) Return o.Blowup(astlist) EndIf Next SetColor(255,255,255) Plot(x,y) Return 0 End Method End Type Type TEnemyShot Field x:Double Field y:Double Field dx:Double Field dy:Double Field life:Int Function Create:TEnemyShot(ship:TVectorGfxObject, v:TVector) Local o:TEnemyShot=New TEnemyShot o.dx=v.x o.dy=v.y o.x=ship.x o.y=ship.y o.life=250 Return o End Function Method Update:Int(shotlist:TList, ship:TVectorGfxObject) life:-1 If life=0 shotlist.Remove(Self) Return False EndIf x:+dx y:+dy If x<0 x:+GraphicsWidth() EndIf If x>=GraphicsWidth() x:-GraphicsWidth() EndIf If y<0 y:+GraphicsHeight() EndIf If y>=GraphicsHeight() x:-GraphicsHeight() EndIf If ship And ship.IsInside(x,y) Sounds.ShipExplosion() shotlist.Remove(Self) Return True EndIf SetColor(255,255,255) Plot(x,y) Return False End Method End Type Type TSaucer Field x:Double Field y:Double Field dx:Double Field dy:Double Field dirx:Int Field dirchange:Int Field shotdel:Int Field shotwait:Int Field shotlist:TList Field big:Int Field obj:TVectorGfxObject Field dead:Int Function Create:TSaucer(big:Int, shotdel:Int) Local o:TSaucer=New TSaucer o.dead=False o.dirx=Rand(100)<50 If o.dirx If Rand(100)<50 o.x=0 o.dx=Rnd(1,2) Else o.x=GraphicsWidth()-1 o.dx=Rnd(-2,-1) EndIf o.y=Rand(10,GraphicsHeight()-10) Else If Rand(100)<50 o.y=0 o.dy=Rnd(1,2) Else o.y=GraphicsHeight()-1 o.dy=Rnd(-2,-1) EndIf o.x=Rand(10,GraphicsWidth()-10) EndIf o.Turn() o.shotlist=New TList o.big=big o.shotdel=shotdel o.shotwait=Rand(shotdel) If big Sounds.LargeSaucer() o.obj=GameGFX.lsaucer.Clone() Else Sounds.SmallSaucer() o.obj=GameGFX.ssaucer.Clone() EndIf Return o End Function Method Turn() dirchange=Rand(10,100) If dirx dy=Rnd(-2,2) Else dx=Rnd(-2,2) EndIf End Method Method Fire(ship:TVectorGfxObject) shotwait=0 Local v:TVector If big v=TVector.Create(ship.x-x+Rnd(-40,40),ship.y-y+Rnd(-40,40)) Else v=TVector.Create(ship.x-x+Rnd(-10,10),ship.y-y+Rnd(-10,10)) EndIf v.SetLength(2) Sounds.SaucerFire() shotlist.AddLast(TEnemyShot.Create(obj,v)) End Method Method OffScreen:Int() If dirx Return x<0 Or x>GraphicsWidth() Else Return y<0 Or y>GraphicsHeight() EndIf End Method Method Finished:Int() Return shotlist.Count()=0 And (dead Or OffScreen()) End Method ' Returns True if ship hit by saucer's bullets ' Method Update:Int(ship:TVectorGfxObject) If Not dead x:+dx y:+dy If dirx If y<0 y:+GraphicsHeight() ElseIf y>GraphicsHeight() y:-GraphicsHeight() EndIf Else If x<0 x:+GraphicsWidth() ElseIf x>GraphicsWidth() x:-GraphicsWidth() EndIf EndIf dirchange:-1 If dirchange=0 Turn() EndIf obj.x=x obj.y=y obj.Draw() If ship And Not OffScreen() shotwait:+1 If shotwait>shotdel Fire(ship) EndIf EndIf EndIf Local ret:Int=False For Local s:TEnemyShot=EachIn shotlist ret=s.Update(shotlist,ship) Or ret Next Return ret End Method End Type Type TParticle Field obj:TVectorGfxObject Field x:Double Field y:Double Field a:Double Field dx:Double Field dy:Double Field ai:Double Function CreatePoint:TParticle(x:Int, y:Int, v:TVector, ai:Double=-0.05) Local o:TParticle=New TParticle o.obj=Null o.x=x o.y=y o.dx=v.x+Rnd(-0.1,0.1) o.dy=v.y+Rnd(-0.1,0.1) o.a=1 o.ai=ai Return o End Function Function CreateDebris:TParticle(x:Int, y:Int, v:TVector, ai:Double=-0.01) Local o:TParticle=New TParticle o.obj=GameGFX.debris.Clone() o.obj.ang=Rand(0,3599) o.x=x o.y=y o.dx=v.x+Rnd(-0.1,0.1) o.dy=v.y+Rnd(-0.1,0.1) o.a=1 o.ai=-0.02 Return o End Function Method Update() x:+dx y:+dy a:+ai If a>0 SetAlpha(a) If obj obj.x=x obj.y=y obj.ang=(obj.ang+30) Mod 3600 obj.Draw() Else Plot(x,y) EndIf EndIf End Method End Type Type TParticleMachine Global list:TList Function Init() list=CreateList() End Function Function Clear() list.Clear() End Function Function AsteroidExplosion(x:Int,y:Int) For Local f:Int=0 To 20 list.AddLast(TParticle.CreatePoint(x+Rand(-3,3),y+Rand(-3,3),TVector.Create(Rnd(-2,2),Rnd(-2,2)))) Next End Function Function ShipExplosion(x:Int,y:Int) For Local f:Int=0 To 30 list.AddLast(TParticle.CreatePoint(x+Rand(-1,1),y+Rand(-1,1),TVector.Create(Rnd(-2,2),Rnd(-2,2)),-0.02)) Next For Local f:Int=0 To 3 list.AddLast(TParticle.CreateDebris(x+Rand(-1,1),y+Rand(-1,1),TVector.Create(Rnd(-2,2),Rnd(-2,2)),-0.01)) Next End Function Function Process() Local l:TLink=list.FirstLink() Local t:TLink SetColor(255,255,255) While l<>Null Local p:TParticle=TParticle(l.Value()) p.Update() If p.a<0.01 t=l.NextLink() l.Remove() l=t Else l=l.NextLink() EndIf Wend SetAlpha(1) End Function End Type