| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- Namespace asteroids
- #Import "<std>"
- #Import "<mojo>"
- Using std..
- Using mojo..
- Const SCREEN_WIDTH:Int = 640
- Const SCREEN_HEIGHT:Int = 480
- Const PI:Float = 3.14159265358979323846
- Class MyWindow Extends Window
- Const STATE_TITLE:Int= 1
- Const STATE_GAME:Int = 2
- Const STATE_GAME_OVER:Int = 3
- Global GameState:Int = STATE_TITLE
-
- Field player:Player
- Field score:Int
- Field level:Int
- Field bestScore:Int
- Field asteroidsNum:Int
- Field asteroidsSize:Int
-
- Method New(title:String, width:Int, height:Int)
- Super.New(title, width, height)
- ClearColor = Color.Black
- SwapInterval = 1
- SeedRnd(Millisecs())
- Reset()
- End
-
- Method OnWindowEvent(event:WindowEvent) Override
- Select event.Type
- Case EventType.WindowMoved
- Case EventType.WindowResized
- App.RequestRender()
- Case EventType.WindowGainedFocus
- Case EventType.WindowLostFocus
- Default
- Super.OnWindowEvent(event)
- End
- End
-
- Method OnRender(canvas:Canvas) Override
- App.RequestRender()
-
- Select GameState
- Case STATE_TITLE
- Asteroid.UpdateAll()
- If Keyboard.KeyHit(Key.Space)
- SetState(STATE_GAME)
- End
- Case STATE_GAME
- player.Update()
- Bullet.UpdateAll()
- Asteroid.UpdateAll()
- CheckCollisions()
- Case STATE_GAME_OVER
- Asteroid.UpdateAll()
- If Keyboard.KeyHit(Key.Space)
- SetState(STATE_TITLE)
- Reset()
- End
- End
-
- Select GameState
- Case STATE_TITLE
- DrawTitleScreen(canvas)
- Case STATE_GAME
- DrawGame(canvas)
- Case STATE_GAME_OVER
- DrawGameOver(canvas)
- End
- End
-
- Method SetState(state:Int)
- GameState = state
- End
-
- Method DrawTitleScreen(canvas:Canvas)
- Asteroid.RenderAll(canvas)
- canvas.DrawText("MONKEYROIDS: RETURN OF THE CHIMP!", SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) - 20, 0.5, 0.5)
- canvas.DrawText("BEST SCORE: " + bestScore, (SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2), 0.5, 0.5)
- canvas.DrawText("PRESS <SPACE> TO PLAY", SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) + 20, 0.5, 0.5)
- End
-
- Method DrawHUD:Void(canvas:Canvas)
- canvas.DrawText("LEVEL: " + level, 0, 0)
- canvas.DrawText("SCORE: " + score, SCREEN_WIDTH, 0, 1, 0)
- canvas.DrawText("BULLETS#: " + Bullet.list.Count(), SCREEN_WIDTH/2, 0, 0.5, 0)
- canvas.DrawText("ASTEROIDS#: " + Asteroid.list.Count(), SCREEN_WIDTH/2, 20, 0.5, 0)
- End
-
- Method DrawGame(canvas:Canvas)
- player.Render(canvas)
- Bullet.RenderAll(canvas)
- Asteroid.RenderAll(canvas)
- DrawHUD(canvas)
- End
-
- Method DrawGameOver(canvas:Canvas)
- Asteroid.RenderAll(canvas)
- canvas.DrawText("GAME OVER!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 20, 0.5, 0.5)
- canvas.DrawText("SCORE: " + score, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0.5, 0.5)
- canvas.DrawText("BEST SCORE: " + Self.bestScore, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 + 20, 0.5, 0.5)
- canvas.DrawText("PRESS <SPACE> TO RETURN TO THE TITLE SCREEN", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 + 40, 0.5, 0.5)
- End
- Method CheckCollisions()
- Local asteroidToRemove:Asteroid
-
- Local ait := Asteroid.list.All()
- While Not ait.AtEnd
- Local a:Asteroid = ait.Current
- If Not a.dead And Dist(player.x, player.y, a.x, a.y) <= a.avgrad
- player.shield -= 10
- a.dead = True
- End
- For Local b:Bullet = Eachin Bullet.list
- If a <> Null And Not a.dead
- If Dist(b.x, b.y, a.x, a.y) <= a.avgrad
- a.life -= 1
- b.life = 0
- End
- If a.life <= 0
- a.dead = True
- End
- End
- Next
- If a.dead
- ait.Erase()
- asteroidToRemove = a
- Else
- ait.Bump()
- End
- End
-
- If asteroidToRemove <> Null
- If asteroidToRemove.size > 1
- score += 5
- For Local t:Int = 1 To 2
- New Asteroid(asteroidToRemove.x, asteroidToRemove.y, Rnd(-5, 5), Rnd(-5, 5), asteroidToRemove.size - 1)
- Next
- End
- End
-
- If Asteroid.list.Count() = 0
- level += 1
- asteroidsNum += 1
- asteroidsSize += 1
- CreateAsteroids(asteroidsNum, asteroidsSize)
- End
- End
-
- Method Reset()
- Bullet.list.Clear()
- Asteroid.list.Clear()
- level = 1
- asteroidsNum = 2
- asteroidsSize = 3
- score = 0
- player = New Player(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)
- CreateAsteroids(asteroidsNum, asteroidsSize)
- End
-
- Method CreateAsteroids:Void(num:Int, size:Int)
- Asteroid.list.Clear()
- Bullet.list.Clear()
- Local tx:Float
- Local ty:Float
- For Local t:Int = 1 To num
- Repeat
- tx = Rnd(640)
- ty = Rnd(480)
- Until (tx < 280 Or tx > 360) And (ty < 200 Or ty > 280)
- New Asteroid(tx, ty, Rnd(-2, 2), Rnd(-2, 2), size + Rnd(1))
- Next
- End
- End
- Class Sprite
- Field dead:Bool
- Field xv:Float, yv:Float
- Field x:Float, y:Float
- Field rotation:Float
- Field canvas:Canvas
- End
- Class Asteroid Extends Sprite
- Global list:List<Asteroid> = New List<Asteroid>
- Field ang:Float, angvel:Float
- Field rad:Float[] = New Float[9]
- Field avgrad:Float
- Field size:Int
- Field life:Int
- Field cr:Float, cg:Float, cb:Float
-
- Method New(x:Float, y:Float, xv:Float, yv:Float ,size:Int)
- Self.x = x
- Self.y = y
- Self.xv = xv
- Self.yv = yv
- Self.ang = Rnd(360)
- Self.angvel = Rnd(-6, 6)
- Self.size = size
- Self.life = size
- Self.cr = 1
- Self.cg = 1
- Self.cb = 1
- ' Create "Rockiness"
- Self.avgrad = 0
- For Local t:Int = 0 To 7
- Self.rad[t] = size * 8.0 + Rnd(-size * 4.0, size * 4.0)
- Self.avgrad = Self.avgrad + Self.rad[t]
- Next
- Self.avgrad = Self.avgrad /6.0
- Self.rad[8] = Self.rad[0]
- Self.dead = False
-
- list.AddLast(self)
- End
-
- Function RenderAll:Void(canvas:Canvas)
- If Not list Return
- For Local a:Asteroid = Eachin list
- a.Render(canvas)
- Next
- End
-
- Function UpdateAll:Void()
- If Not list Return
- For Local a:Asteroid = Eachin list
- a.Update()
- Next
- End
-
- Method Update:Void()
- 'If dead Return
- Self.x += Self.xv * Delta.delta
- Self.y += Self.yv * Delta.delta
- Self.rotation += Self.angvel * Delta.delta
-
- If Self.x < -Self.avgrad Then Self.x = Self.x + SCREEN_WIDTH + Self.avgrad *2
- If Self.x > SCREEN_WIDTH + Self.avgrad Then Self.x = Self.x - SCREEN_WIDTH - Self.avgrad *2
- If Self.y < -Self.avgrad Then Self.y = Self.y + SCREEN_HEIGHT + Self.avgrad *2
- If Self.y > SCREEN_HEIGHT + Self.avgrad Then Self.y = Self.y - SCREEN_HEIGHT - Self.avgrad *2
- End
-
- Method Render:Void(canvas:Canvas)
- 'If dead Return
- Local tmul:Float = 360.0 / 8.0
- canvas.Color = New Color( cr, cg, cb)
- For Local t:Int = 0 To 7
- local x1:Float = x - (Sin(ToRadians(rotation + (t) * tmul)) * rad[t])
- Local y1:Float = y - (Cos(ToRadians(rotation + (t) * tmul)) * rad[t])
- Local x2:Float = x - (Sin(ToRadians(rotation + (t + 1) * tmul))* rad[t + 1])
- Local y2:Float = y - (Cos(ToRadians(rotation + (t + 1) * tmul)) * rad[t + 1])
- canvas.DrawLine(x1, y1, x2, y2)
- Next
- End
- End
- Class Bullet Extends Sprite
- Global list:List<Bullet> = New List<Bullet>
- Field life:Float
- Field cr:Float, cg:Float, cb:Float
-
- Method New(x:Float, y:Float, xv:Float, yv:Float, life:Float, cr:Float, cg:Float, cb:Float)
- Self.x = x
- Self.y = y
- Self.xv = xv
- Self.yv = yv
- Self.life = life
- Self.cr = cr
- Self.cg = cg
- Self.cb = cb
-
- list.AddLast(Self)
- End
-
- Function UpdateAll:Void()
- If Not list Return
-
- Local it := list.All()
- While Not it.AtEnd
- Local b:Bullet = it.Current
- b.Update()
- If b.life <= 0
- it.Erase()
- Else
- it.Bump()
- End
- End
- End
-
- Method Update:Void()
- If dead Return
- x += xv * Delta.delta
- y += yv * Delta.delta
-
- life -= Delta.delta
- If x < 0 x = SCREEN_WIDTH
- If x > SCREEN_WIDTH x = 0
- If y < 0 y = SCREEN_HEIGHT
- If y > SCREEN_HEIGHT y = 0
- End
-
- Function RenderAll:Void(canvas:Canvas)
- If Not list Return
- For Local b:Bullet = Eachin list
- b.Render(canvas)
- Next
- End
-
- Method Render:Void(canvas:Canvas)
- If dead Return
- Local tmul:Float
- If life <= 25.0
- tmul = life / 25.0
- Else
- tmul = 1.0
- End
- canvas.Color = New Color( cr * tmul, cg * tmul, cb * tmul )
- canvas.DrawLine(x, y, x + xv, y + yv)
- End
- End
- Class Player Extends Sprite
- Field angVel:Float
- Field velmul:Float
- Field vel:Float
- Field acc:Float
- Field drag:Float
- Field xv:Float, yv:Float
- Field xa:Float, ya:Float
- Field firedel:Float
-
- Field shipAngvel:Float
- Field shipAcc:Float
- Field shipVelmul:Float
- Field shipFiredel:Float
-
- Field shield:Float
-
- Method New(x:Float, y:Float)
- Self.x = x
- Self.y = y
- Self.shipAngvel = 6
- Self.shipAcc = 0.16
- Self.shipVelmul = -0.0005
- Self.shipFiredel = 5
- Self.shield = 100
- End
-
- Method Controls()
- If Keyboard.KeyDown(Key.Up) Or Keyboard.KeyDown(Key.W)
- acc = shipAcc
- drag = vel * shipVelmul
- Elseif Keyboard.KeyDown(Key.Down) Or Keyboard.KeyDown(Key.S)
- drag = vel * shipVelmul * 50
- Else
- acc = 0
- drag = 0
- End
-
- If Keyboard.KeyDown(Key.Left) Or Keyboard.KeyDown(Key.A)
- rotation += shipAngvel * Delta.delta
- Elseif Keyboard.KeyDown(Key.Right) Or Keyboard.KeyDown(Key.D)
- rotation -= shipAngvel * Delta.delta
- End
-
- If Keyboard.KeyDown(Key.Space) And Self.firedel <= 0
- Local tang:Float = Rnd(-.01, .01)
- Local x1:Float = x - (Sin(ToRadians(rotation)) * 8)
- Local y1:Float = y - (Cos(ToRadians(rotation)) * 8)
- Local xv1:Float = xv - (Sin(ToRadians(rotation) + tang ) * 12)
- Local yv1:Float = yv - (Cos(ToRadians(rotation) + tang ) * 12)
- Local life:Int = 45
- New Bullet(x1, y1, xv1, yv1, life, 1, 1, 0)
- firedel = shipFiredel
- End
- firedel -= Delta.delta
-
- End
-
- Method Update()
- Controls()
- xa = (drag * xv) - (Sin(ToRadians(rotation)) * acc)
- ya = (drag * yv) - (Cos(ToRadians(rotation)) * acc)
- xv += xa * Delta.delta
- yv += ya * Delta.delta
- x += xv * Delta.delta
- y += yv * Delta.delta
- vel = Dist(0, 0, xv, yv)
-
- If x < 0 x = SCREEN_WIDTH
- If x > SCREEN_WIDTH x = 0
- If y < 0 y = SCREEN_HEIGHT
- If y > SCREEN_HEIGHT y = 0
-
- If shield <= 0
- If Game.score > Game.bestScore
- Game.bestScore = Game.score
- End
- Game.SetState(Game.STATE_GAME_OVER)
- End
- End
-
- Method Render(canvas:Canvas)
- Local x1:Float = x - (Sin(ToRadians(rotation)) * 10)
- Local y1:Float = y - (Cos(ToRadians(rotation)) * 10)
-
- Local x2:Float = x - (Sin(ToRadians(rotation + 140)) * 8)
- Local y2:Float = y - (Cos(ToRadians(rotation + 140)) * 8)
-
- Local x3:Float = x - (Sin(ToRadians(rotation - 140)) * 8)
- Local y3:Float = y - (Cos(ToRadians(rotation - 140)) * 8)
-
- canvas.Color = Color.White
- canvas.DrawLine(x1, y1, x2, y2)
- canvas.DrawLine(x2, y2, x3, y3)
- canvas.DrawLine(x3, y3, x1, y1)
-
- canvas.Alpha = .5
- If shield < 50 Then canvas.Color = New Color(1, 0, 0)
- canvas.DrawRect(10, SCREEN_HEIGHT - 15, Self.shield, 10)
- canvas.Alpha = 1
- End
- End
- 'TODO: Delta timing class
- Class Delta
- Global delta:Float = 0.5
- End
- Global Game:MyWindow
- Function Main()
- New AppInstance
- Game = New MyWindow("Monkeyroids: Return of the Chimp!", SCREEN_WIDTH, SCREEN_HEIGHT)
- App.Run()
- End
- Function Dist:Float(x1:Float, y1:Float, x2:Float, y2:Float)
- Return Sqrt(Pow((x1 - x2), 2) + Pow((y1 - y2), 2))
- End
- Function ToDegrees:Float(rad:Float)
- Return rad * 180.0 / PI
- End
- Function ToRadians:Float(degree:Float)
- Return degree * PI / 180.0
- End
|