2
0

monkeyroids.monkey2 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. Namespace asteroids
  2. #Import "<std>"
  3. #Import "<mojo>"
  4. Using std..
  5. Using mojo..
  6. Const SCREEN_WIDTH:Int = 640
  7. Const SCREEN_HEIGHT:Int = 480
  8. Const PI:Float = 3.14159265358979323846
  9. Class MyWindow Extends Window
  10. Const STATE_TITLE:Int= 1
  11. Const STATE_GAME:Int = 2
  12. Const STATE_GAME_OVER:Int = 3
  13. Global GameState:Int = STATE_TITLE
  14. Field player:Player
  15. Field score:Int
  16. Field level:Int
  17. Field bestScore:Int
  18. Field asteroidsNum:Int
  19. Field asteroidsSize:Int
  20. Method New(title:String, width:Int, height:Int)
  21. Super.New(title, width, height)
  22. ClearColor = Color.Black
  23. SwapInterval = 1
  24. SeedRnd(Millisecs())
  25. Reset()
  26. End
  27. Method OnWindowEvent(event:WindowEvent) Override
  28. Select event.Type
  29. Case EventType.WindowMoved
  30. Case EventType.WindowResized
  31. App.RequestRender()
  32. Case EventType.WindowGainedFocus
  33. Case EventType.WindowLostFocus
  34. Default
  35. Super.OnWindowEvent(event)
  36. End
  37. End
  38. Method OnRender(canvas:Canvas) Override
  39. App.RequestRender()
  40. Select GameState
  41. Case STATE_TITLE
  42. Asteroid.UpdateAll()
  43. If Keyboard.KeyHit(Key.Space)
  44. SetState(STATE_GAME)
  45. End
  46. Case STATE_GAME
  47. player.Update()
  48. Bullet.UpdateAll()
  49. Asteroid.UpdateAll()
  50. CheckCollisions()
  51. Case STATE_GAME_OVER
  52. Asteroid.UpdateAll()
  53. If Keyboard.KeyHit(Key.Space)
  54. SetState(STATE_TITLE)
  55. Reset()
  56. End
  57. End
  58. Select GameState
  59. Case STATE_TITLE
  60. DrawTitleScreen(canvas)
  61. Case STATE_GAME
  62. DrawGame(canvas)
  63. Case STATE_GAME_OVER
  64. DrawGameOver(canvas)
  65. End
  66. End
  67. Method SetState(state:Int)
  68. GameState = state
  69. End
  70. Method DrawTitleScreen(canvas:Canvas)
  71. Asteroid.RenderAll(canvas)
  72. canvas.DrawText("MONKEYROIDS: RETURN OF THE CHIMP!", SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) - 20, 0.5, 0.5)
  73. canvas.DrawText("BEST SCORE: " + bestScore, (SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2), 0.5, 0.5)
  74. canvas.DrawText("PRESS <SPACE> TO PLAY", SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) + 20, 0.5, 0.5)
  75. End
  76. Method DrawHUD:Void(canvas:Canvas)
  77. canvas.DrawText("LEVEL: " + level, 0, 0)
  78. canvas.DrawText("SCORE: " + score, SCREEN_WIDTH, 0, 1, 0)
  79. canvas.DrawText("BULLETS#: " + Bullet.list.Count(), SCREEN_WIDTH/2, 0, 0.5, 0)
  80. canvas.DrawText("ASTEROIDS#: " + Asteroid.list.Count(), SCREEN_WIDTH/2, 20, 0.5, 0)
  81. End
  82. Method DrawGame(canvas:Canvas)
  83. player.Render(canvas)
  84. Bullet.RenderAll(canvas)
  85. Asteroid.RenderAll(canvas)
  86. DrawHUD(canvas)
  87. End
  88. Method DrawGameOver(canvas:Canvas)
  89. Asteroid.RenderAll(canvas)
  90. canvas.DrawText("GAME OVER!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 20, 0.5, 0.5)
  91. canvas.DrawText("SCORE: " + score, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0.5, 0.5)
  92. canvas.DrawText("BEST SCORE: " + Self.bestScore, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 + 20, 0.5, 0.5)
  93. canvas.DrawText("PRESS <SPACE> TO RETURN TO THE TITLE SCREEN", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 + 40, 0.5, 0.5)
  94. End
  95. Method CheckCollisions()
  96. Local asteroidToRemove:Asteroid
  97. Local ait := Asteroid.list.All()
  98. While Not ait.AtEnd
  99. Local a:Asteroid = ait.Current
  100. If Not a.dead And Dist(player.x, player.y, a.x, a.y) <= a.avgrad
  101. player.shield -= 10
  102. a.dead = True
  103. End
  104. For Local b:Bullet = Eachin Bullet.list
  105. If a <> Null And Not a.dead
  106. If Dist(b.x, b.y, a.x, a.y) <= a.avgrad
  107. a.life -= 1
  108. b.life = 0
  109. End
  110. If a.life <= 0
  111. a.dead = True
  112. End
  113. End
  114. Next
  115. If a.dead
  116. ait.Erase()
  117. asteroidToRemove = a
  118. Else
  119. ait.Bump()
  120. End
  121. End
  122. If asteroidToRemove <> Null
  123. If asteroidToRemove.size > 1
  124. score += 5
  125. For Local t:Int = 1 To 2
  126. New Asteroid(asteroidToRemove.x, asteroidToRemove.y, Rnd(-5, 5), Rnd(-5, 5), asteroidToRemove.size - 1)
  127. Next
  128. End
  129. End
  130. If Asteroid.list.Count() = 0
  131. level += 1
  132. asteroidsNum += 1
  133. asteroidsSize += 1
  134. CreateAsteroids(asteroidsNum, asteroidsSize)
  135. End
  136. End
  137. Method Reset()
  138. Bullet.list.Clear()
  139. Asteroid.list.Clear()
  140. level = 1
  141. asteroidsNum = 2
  142. asteroidsSize = 3
  143. score = 0
  144. player = New Player(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)
  145. CreateAsteroids(asteroidsNum, asteroidsSize)
  146. End
  147. Method CreateAsteroids:Void(num:Int, size:Int)
  148. Asteroid.list.Clear()
  149. Bullet.list.Clear()
  150. Local tx:Float
  151. Local ty:Float
  152. For Local t:Int = 1 To num
  153. Repeat
  154. tx = Rnd(640)
  155. ty = Rnd(480)
  156. Until (tx < 280 Or tx > 360) And (ty < 200 Or ty > 280)
  157. New Asteroid(tx, ty, Rnd(-2, 2), Rnd(-2, 2), size + Rnd(1))
  158. Next
  159. End
  160. End
  161. Class Sprite
  162. Field dead:Bool
  163. Field xv:Float, yv:Float
  164. Field x:Float, y:Float
  165. Field rotation:Float
  166. Field canvas:Canvas
  167. End
  168. Class Asteroid Extends Sprite
  169. Global list:List<Asteroid> = New List<Asteroid>
  170. Field ang:Float, angvel:Float
  171. Field rad:Float[] = New Float[9]
  172. Field avgrad:Float
  173. Field size:Int
  174. Field life:Int
  175. Field cr:Float, cg:Float, cb:Float
  176. Method New(x:Float, y:Float, xv:Float, yv:Float ,size:Int)
  177. Self.x = x
  178. Self.y = y
  179. Self.xv = xv
  180. Self.yv = yv
  181. Self.ang = Rnd(360)
  182. Self.angvel = Rnd(-6, 6)
  183. Self.size = size
  184. Self.life = size
  185. Self.cr = 1
  186. Self.cg = 1
  187. Self.cb = 1
  188. ' Create "Rockiness"
  189. Self.avgrad = 0
  190. For Local t:Int = 0 To 7
  191. Self.rad[t] = size * 8.0 + Rnd(-size * 4.0, size * 4.0)
  192. Self.avgrad = Self.avgrad + Self.rad[t]
  193. Next
  194. Self.avgrad = Self.avgrad /6.0
  195. Self.rad[8] = Self.rad[0]
  196. Self.dead = False
  197. list.AddLast(self)
  198. End
  199. Function RenderAll:Void(canvas:Canvas)
  200. If Not list Return
  201. For Local a:Asteroid = Eachin list
  202. a.Render(canvas)
  203. Next
  204. End
  205. Function UpdateAll:Void()
  206. If Not list Return
  207. For Local a:Asteroid = Eachin list
  208. a.Update()
  209. Next
  210. End
  211. Method Update:Void()
  212. 'If dead Return
  213. Self.x += Self.xv * Delta.delta
  214. Self.y += Self.yv * Delta.delta
  215. Self.rotation += Self.angvel * Delta.delta
  216. If Self.x < -Self.avgrad Then Self.x = Self.x + SCREEN_WIDTH + Self.avgrad *2
  217. If Self.x > SCREEN_WIDTH + Self.avgrad Then Self.x = Self.x - SCREEN_WIDTH - Self.avgrad *2
  218. If Self.y < -Self.avgrad Then Self.y = Self.y + SCREEN_HEIGHT + Self.avgrad *2
  219. If Self.y > SCREEN_HEIGHT + Self.avgrad Then Self.y = Self.y - SCREEN_HEIGHT - Self.avgrad *2
  220. End
  221. Method Render:Void(canvas:Canvas)
  222. 'If dead Return
  223. Local tmul:Float = 360.0 / 8.0
  224. canvas.Color = New Color( cr, cg, cb)
  225. For Local t:Int = 0 To 7
  226. local x1:Float = x - (Sin(ToRadians(rotation + (t) * tmul)) * rad[t])
  227. Local y1:Float = y - (Cos(ToRadians(rotation + (t) * tmul)) * rad[t])
  228. Local x2:Float = x - (Sin(ToRadians(rotation + (t + 1) * tmul))* rad[t + 1])
  229. Local y2:Float = y - (Cos(ToRadians(rotation + (t + 1) * tmul)) * rad[t + 1])
  230. canvas.DrawLine(x1, y1, x2, y2)
  231. Next
  232. End
  233. End
  234. Class Bullet Extends Sprite
  235. Global list:List<Bullet> = New List<Bullet>
  236. Field life:Float
  237. Field cr:Float, cg:Float, cb:Float
  238. Method New(x:Float, y:Float, xv:Float, yv:Float, life:Float, cr:Float, cg:Float, cb:Float)
  239. Self.x = x
  240. Self.y = y
  241. Self.xv = xv
  242. Self.yv = yv
  243. Self.life = life
  244. Self.cr = cr
  245. Self.cg = cg
  246. Self.cb = cb
  247. list.AddLast(Self)
  248. End
  249. Function UpdateAll:Void()
  250. If Not list Return
  251. Local it := list.All()
  252. While Not it.AtEnd
  253. Local b:Bullet = it.Current
  254. b.Update()
  255. If b.life <= 0
  256. it.Erase()
  257. Else
  258. it.Bump()
  259. End
  260. End
  261. End
  262. Method Update:Void()
  263. If dead Return
  264. x += xv * Delta.delta
  265. y += yv * Delta.delta
  266. life -= Delta.delta
  267. If x < 0 x = SCREEN_WIDTH
  268. If x > SCREEN_WIDTH x = 0
  269. If y < 0 y = SCREEN_HEIGHT
  270. If y > SCREEN_HEIGHT y = 0
  271. End
  272. Function RenderAll:Void(canvas:Canvas)
  273. If Not list Return
  274. For Local b:Bullet = Eachin list
  275. b.Render(canvas)
  276. Next
  277. End
  278. Method Render:Void(canvas:Canvas)
  279. If dead Return
  280. Local tmul:Float
  281. If life <= 25.0
  282. tmul = life / 25.0
  283. Else
  284. tmul = 1.0
  285. End
  286. canvas.Color = New Color( cr * tmul, cg * tmul, cb * tmul )
  287. canvas.DrawLine(x, y, x + xv, y + yv)
  288. End
  289. End
  290. Class Player Extends Sprite
  291. Field angVel:Float
  292. Field velmul:Float
  293. Field vel:Float
  294. Field acc:Float
  295. Field drag:Float
  296. Field xv:Float, yv:Float
  297. Field xa:Float, ya:Float
  298. Field firedel:Float
  299. Field shipAngvel:Float
  300. Field shipAcc:Float
  301. Field shipVelmul:Float
  302. Field shipFiredel:Float
  303. Field shield:Float
  304. Method New(x:Float, y:Float)
  305. Self.x = x
  306. Self.y = y
  307. Self.shipAngvel = 6
  308. Self.shipAcc = 0.16
  309. Self.shipVelmul = -0.0005
  310. Self.shipFiredel = 5
  311. Self.shield = 100
  312. End
  313. Method Controls()
  314. If Keyboard.KeyDown(Key.Up) Or Keyboard.KeyDown(Key.W)
  315. acc = shipAcc
  316. drag = vel * shipVelmul
  317. Elseif Keyboard.KeyDown(Key.Down) Or Keyboard.KeyDown(Key.S)
  318. drag = vel * shipVelmul * 50
  319. Else
  320. acc = 0
  321. drag = 0
  322. End
  323. If Keyboard.KeyDown(Key.Left) Or Keyboard.KeyDown(Key.A)
  324. rotation += shipAngvel * Delta.delta
  325. Elseif Keyboard.KeyDown(Key.Right) Or Keyboard.KeyDown(Key.D)
  326. rotation -= shipAngvel * Delta.delta
  327. End
  328. If Keyboard.KeyDown(Key.Space) And Self.firedel <= 0
  329. Local tang:Float = Rnd(-.01, .01)
  330. Local x1:Float = x - (Sin(ToRadians(rotation)) * 8)
  331. Local y1:Float = y - (Cos(ToRadians(rotation)) * 8)
  332. Local xv1:Float = xv - (Sin(ToRadians(rotation) + tang ) * 12)
  333. Local yv1:Float = yv - (Cos(ToRadians(rotation) + tang ) * 12)
  334. Local life:Int = 45
  335. New Bullet(x1, y1, xv1, yv1, life, 1, 1, 0)
  336. firedel = shipFiredel
  337. End
  338. firedel -= Delta.delta
  339. End
  340. Method Update()
  341. Controls()
  342. xa = (drag * xv) - (Sin(ToRadians(rotation)) * acc)
  343. ya = (drag * yv) - (Cos(ToRadians(rotation)) * acc)
  344. xv += xa * Delta.delta
  345. yv += ya * Delta.delta
  346. x += xv * Delta.delta
  347. y += yv * Delta.delta
  348. vel = Dist(0, 0, xv, yv)
  349. If x < 0 x = SCREEN_WIDTH
  350. If x > SCREEN_WIDTH x = 0
  351. If y < 0 y = SCREEN_HEIGHT
  352. If y > SCREEN_HEIGHT y = 0
  353. If shield <= 0
  354. If Game.score > Game.bestScore
  355. Game.bestScore = Game.score
  356. End
  357. Game.SetState(Game.STATE_GAME_OVER)
  358. End
  359. End
  360. Method Render(canvas:Canvas)
  361. Local x1:Float = x - (Sin(ToRadians(rotation)) * 10)
  362. Local y1:Float = y - (Cos(ToRadians(rotation)) * 10)
  363. Local x2:Float = x - (Sin(ToRadians(rotation + 140)) * 8)
  364. Local y2:Float = y - (Cos(ToRadians(rotation + 140)) * 8)
  365. Local x3:Float = x - (Sin(ToRadians(rotation - 140)) * 8)
  366. Local y3:Float = y - (Cos(ToRadians(rotation - 140)) * 8)
  367. canvas.Color = Color.White
  368. canvas.DrawLine(x1, y1, x2, y2)
  369. canvas.DrawLine(x2, y2, x3, y3)
  370. canvas.DrawLine(x3, y3, x1, y1)
  371. canvas.Alpha = .5
  372. If shield < 50 Then canvas.Color = New Color(1, 0, 0)
  373. canvas.DrawRect(10, SCREEN_HEIGHT - 15, Self.shield, 10)
  374. canvas.Alpha = 1
  375. End
  376. End
  377. 'TODO: Delta timing class
  378. Class Delta
  379. Global delta:Float = 0.5
  380. End
  381. Global Game:MyWindow
  382. Function Main()
  383. New AppInstance
  384. Game = New MyWindow("Monkeyroids: Return of the Chimp!", SCREEN_WIDTH, SCREEN_HEIGHT)
  385. App.Run()
  386. End
  387. Function Dist:Float(x1:Float, y1:Float, x2:Float, y2:Float)
  388. Return Sqrt(Pow((x1 - x2), 2) + Pow((y1 - y2), 2))
  389. End
  390. Function ToDegrees:Float(rad:Float)
  391. Return rad * 180.0 / PI
  392. End
  393. Function ToRadians:Float(degree:Float)
  394. Return degree * PI / 180.0
  395. End