rockout_gui.bmx 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. ' Hacked-into-GUI version! It's not pretty, but still, it's only meant to
  2. ' demonstrate a windowed game with GUI!
  3. ' -----------------------------------------------------------------------------
  4. ' RockOut -- Rocket BlockOut
  5. ' -----------------------------------------------------------------------------
  6. ' Public domain source code by James L Boyd (support @ blitzbasic . com)
  7. ' -----------------------------------------------------------------------------
  8. ' Rocket image © 2004 James L Boyd, with permission granted for freeware/PD use,
  9. ' not that anyone'd really want it anyway...!
  10. ' -----------------------------------------------------------------------------
  11. ' -----------------------------------------------------------------------------
  12. ' Constants...
  13. ' -----------------------------------------------------------------------------
  14. ' Sizes used for blocks...
  15. Import MaxGUI.Drivers
  16. Const BLOCKWIDTH = 32
  17. Const BLOCKHEIGHT = 16
  18. ' -----------------------------------------------------------------------------
  19. ' Include media...
  20. ' -----------------------------------------------------------------------------
  21. ' Sounds (all from Yamaha RM1X!)...
  22. Incbin "sounds/shot.ogg" ' Player shot
  23. Incbin "sounds/fall.ogg" ' Block fall
  24. Incbin "sounds/hit.ogg" ' Block/player hit
  25. Incbin "sounds/beep.ogg" ' 'Press space' sound
  26. Incbin "sounds/gameover.ogg" ' Guess...
  27. ' Graphics...
  28. Incbin "gfx/boing.png" ' Rocket
  29. Incbin "gfx/land.png" ' Background (used to be land, now a grid)
  30. Incbin "gfx/shot.png" ' Player's shot
  31. Incbin "gfx/block.png" ' Guess...
  32. ' -----------------------------------------------------------------------------
  33. ' Types (object definitions)...
  34. ' -----------------------------------------------------------------------------
  35. ' GravityItem: all objects affected by gravity are based upon this...
  36. Type GravityItem
  37. ' ------------------------------------------------------------------------
  38. ' Type-specific globals...
  39. ' ------------------------------------------------------------------------
  40. ' Why not make these truly global? It's cleaner -- you can just copy and
  41. ' paste the type definition into a completely different program without
  42. ' having to remember which globals are related...
  43. Global GCount ' Count of all GravityItems (for debugging)
  44. Global GravityItemList:TList ' List used for all GravityItem objects
  45. Global Gravity# = 0.05 ' Gravity applied to all GravityItems
  46. ' ------------------------------------------------------------------------
  47. ' Type fields...
  48. ' ------------------------------------------------------------------------
  49. Field x# ' x position of object
  50. Field y# ' y position of object
  51. Field xs# ' x speed of object
  52. Field ys# ' y speed of object
  53. Field width ' Width of object
  54. Field height ' Height of object
  55. Field damage ' Damage caused by this item if it hits player
  56. Field fixed = False ' Is object fixed in place? Blocks are, at first...
  57. Field r, g, b
  58. ' ------------------------------------------------------------------------
  59. ' Type functions...
  60. ' ------------------------------------------------------------------------
  61. Function UpdateAll ()
  62. If GravityItemList = Null Then Return
  63. If Shadows_On Then Block.DrawShadows ' Shadows_On is a global...
  64. For g:GravityItem = EachIn GravityItemList
  65. g.Update
  66. g.Draw
  67. Next
  68. End Function
  69. ' Function DrawAll ()
  70. ' If Shadows_On Then Block.DrawShadows ' Shadows_On is a global...
  71. ' For g:GravityItem = EachIn GravityItemList
  72. ' g.Draw
  73. ' Next
  74. ' End Function
  75. ' ------------------------------------------------------------------------
  76. ' Type methods...
  77. ' ------------------------------------------------------------------------
  78. ' The New method is special -- Blitz calls it whenever a new object is
  79. ' created...
  80. ' Every time a new GravityItem is created -- including objects that extend
  81. ' GravityItem -- this is called. In this case, it creates the type-global
  82. ' list if it doesn't yet exist (only happens once), and adds the item to it...
  83. Method New ()
  84. If GravityItemList = Null Then GravityItemList = New TList
  85. GravityItemList.AddLast Self
  86. GCount = GCount + 1
  87. End Method
  88. ' Destroy current object and remove from list
  89. Method Destroy ()
  90. GravityItemList.Remove Self
  91. GCount = GCount - 1
  92. End Method
  93. ' Rectangle-based collision test of current object and player.
  94. ' 'The multiplier' parameter controls how much of an object's
  95. ' 'damage' field applies to the player -- in the case of Block
  96. ' objects, the more they're faded out, the less damage they do...
  97. ' The 'posyonly' parameter is a hack to stop Shot objects damaging
  98. ' the player while going up...
  99. Method PlayerCollide (multiplier# = 1, posyonly = 0)
  100. ' Offset x/y position of shots (all images' handles are centered)...
  101. ox = x - width / 2
  102. oy = y - height / 2
  103. ' Offset x/y position of player...
  104. opx = PlayerOne.x - PlayerOne.width / 2
  105. opy = PlayerOne.y - PlayerOne.height / 2
  106. ' Hack to stop Shot objects damaging player while going up...
  107. check = 1
  108. If posyonly
  109. If ys < 0
  110. check = 0
  111. EndIf
  112. EndIf
  113. ' Test for collision, apply damage and make explosion...
  114. If check
  115. If OverLap (ox, oy, ox + width, oy + height, opx, opy, opx + PlayerOne.width, opy + PlayerOne.height)
  116. PlayerOne.shields = PlayerOne.shields - damage * multiplier
  117. ExplosionParticle.Explode x, y, damage * 5 * multiplier
  118. PlayerOne.damaged = MilliSecs ()
  119. Return True
  120. EndIf
  121. EndIf
  122. End Method
  123. ' There is no default Draw method here, as it's different for each extended type
  124. ' of GravityItem, so I've defined it as Abstract...
  125. ' Abstract forces every type that extends GravityItem to have a Draw () method defined
  126. ' or the code simply won't compile...
  127. ' One practical use for this is that you can call Draw from any random GravityItem,
  128. ' regardless of which extended type it is, and this will call the correct Draw ()
  129. ' for the type of object in question...
  130. Method Draw () Abstract
  131. ' Abstract Update method for GravityItems. See Draw () explanation...
  132. Method Update () Abstract
  133. End Type
  134. ' Particles created in an explosion. This type extends GravityItem, meaning all
  135. ' properties of GravityItem apply, except where methods are over-ridden
  136. ' (ie. re-defined) here...
  137. Type ExplosionParticle Extends GravityItem
  138. ' ------------------------------------------------------------------------
  139. ' Type fields...
  140. ' ------------------------------------------------------------------------
  141. ' No need to define, x, y, xs, ys, etc as they're part of the GravityItem definition...
  142. Field alph# = 1.0 ' Alpha level of particle (translucency)
  143. ' ------------------------------------------------------------------------
  144. ' Type functions...
  145. ' ------------------------------------------------------------------------
  146. ' Create explosion of particles, and play sound...
  147. Function Explode (x#, y#, particles)
  148. ' NB. GW2 is a global set to half of GraphicsWidth ()...
  149. If Sounds_On
  150. pan# = x / GW2 - 1.0
  151. play = CueSound (hit)
  152. SetChannelPan play, pan
  153. ResumeChannel play
  154. EndIf
  155. For loop = 1 To particles
  156. ExplosionParticle.Create (x, y)
  157. Next
  158. End Function
  159. ' Create single explosion particle. Note that any items extending GravityItem
  160. ' will call the New () method from GravityItem upon creation, so these will
  161. ' be added to the GravityItem list automatically...
  162. Function Create:ExplosionParticle (x, y)
  163. e:ExplosionParticle = New ExplosionParticle
  164. e.x = x
  165. e.y = y
  166. e.xs = Rnd (-8, 8)
  167. e.ys = Rnd (-8, 8)
  168. ' Random colour...
  169. Select Rand (0, 3)
  170. Case 0
  171. e.r = 255
  172. e.g = 255
  173. e.b = 255
  174. Case 1
  175. e.r = 255
  176. e.g = 127
  177. e.b = 0
  178. Case 2
  179. e.r = 255
  180. e.g = 255
  181. e.b = 0
  182. Case 3
  183. e.r = 255
  184. e.g = 0
  185. e.b = 0
  186. End Select
  187. ' Random size...
  188. size = Rand (1, 8)
  189. e.width = size
  190. e.height = size
  191. End Function
  192. ' ------------------------------------------------------------------------
  193. ' Type methods...
  194. ' ------------------------------------------------------------------------
  195. ' Update () over-rides the GravityItem Update () method...
  196. Method Update ()
  197. ' Reduce alpha level of particle...
  198. alph = alph - 0.01
  199. ' Apply Gravity global (see GravityItem) to y speed...
  200. ys = ys + Gravity
  201. ' Move particle by current speed...
  202. x = x + xs
  203. y = y + ys
  204. ' If off-screen or reduced to invisible, remove from list by
  205. ' calling the Destroy method (inherited from GravityItem)...
  206. If y > GraphicsHeight () Or alph = 0 Then Destroy
  207. End Method
  208. ' Draw particle...
  209. Method Draw ()
  210. SetScale 1, 1
  211. SetBlend ALPHABLEND
  212. SetAlpha alph
  213. SetColor r, g, b
  214. DrawRect x, y, width, height
  215. End Method
  216. End Type
  217. ' Block definition. Again, Block is a kind of GravityItem...
  218. Type Block Extends GravityItem
  219. ' ------------------------------------------------------------------------
  220. ' Type-specific globals...
  221. ' ------------------------------------------------------------------------
  222. Global BCount ' Number of blocks
  223. ' ------------------------------------------------------------------------
  224. ' Type-specific fields...
  225. ' ------------------------------------------------------------------------
  226. Field alph# = 1.0 ' Alpha level of block
  227. Field ang# ' Rotation of block
  228. Field angspeed# ' Rotation speed of block
  229. Field desty#
  230. ' ------------------------------------------------------------------------
  231. ' Type-specific function...
  232. ' ------------------------------------------------------------------------
  233. ' Create a Block object (added to GravityItem list automatically)...
  234. Function Create:Block (x, y)
  235. blk:Block = New Block
  236. blk.x = x
  237. blk.y = y
  238. blk.desty = y
  239. blk.width = BLOCKWIDTH
  240. blk.height = BLOCKHEIGHT
  241. blk.fixed = True
  242. blk.damage = 20
  243. BCount = BCount + 1
  244. Return blk
  245. End Function
  246. ' ------------------------------------------------------------------------
  247. ' Type-specific methods...
  248. ' ------------------------------------------------------------------------
  249. ' Update () method for Block objects...
  250. Method Update ()
  251. ' Check for collision (passing alpha level of block to apply
  252. ' appropriate damage), and remove from GravityItem list if hit...
  253. If PlayerCollide (alph) Then BCount = BCount - 1; Destroy; Return
  254. ' If the block has been freed (by being hit), make it fall...
  255. If Not fixed
  256. alph = alph - 0.0075; If alph < 0 Then alph = 0
  257. ang = ang + angspeed; If ang > 359 Then ang = 0
  258. ys = ys + Gravity
  259. x = x + xs
  260. y = y + ys
  261. If y > GraphicsHeight () Or alph = 0 Destroy; BCount = BCount - 1
  262. Else
  263. ' When blocks are lowered in main loop, they are just set to 'desty',
  264. ' their new y-position destination. This moves them towards that...
  265. ydist# = desty - y
  266. ys = ydist / 12.0
  267. y = y + ys
  268. EndIf
  269. End Method
  270. ' Block-specific Draw () method...
  271. Method Draw ()
  272. SetBlend ALPHABLEND
  273. SetRotation ang
  274. SetColor r, g, b
  275. SetAlpha alph
  276. DrawImage BlockImage, x, y
  277. SetRotation 0
  278. End Method
  279. Function DrawShadows ()
  280. SetBlend ALPHABLEND
  281. For blk:Block = EachIn GravityItemList
  282. SetRotation blk.ang
  283. SetColor 0, 0, 0
  284. SetAlpha blk.alph * 0.25
  285. DrawImage BlockImage, blk.x + 8, blk.y + 8
  286. Next
  287. End Function
  288. End Type
  289. ' Player object. Only one player possible right now, but this keeps everything
  290. ' together for easy reference...
  291. Type Player
  292. Field damaged ' Set to MilliSecs () when hit (used for flashing effect)
  293. ' ------------------------------------------------------------------------
  294. ' Type-specific fields...
  295. ' ------------------------------------------------------------------------
  296. ' The shields field is a float so I can reduce by small amounts, but I use
  297. ' Int (PlayerOne.shields) to display/evaluate it...
  298. Field shields# = 100
  299. Field x#
  300. Field y#
  301. Field xs#
  302. Field ys#
  303. Field image ' Player image...
  304. Field width
  305. Field height
  306. ' ------------------------------------------------------------------------
  307. ' Type-specific functions...
  308. ' ------------------------------------------------------------------------
  309. ' Create () is a function that creates & returns a :Player type object...
  310. Function Create:Player (x, y, image)
  311. PlayerOne:Player = New Player
  312. PlayerOne.image = image
  313. PlayerOne.x = x
  314. PlayerOne.y = y
  315. PlayerOne.width = ImageWidth (PlayerOne.image) * 0.2 ' Image is scaled in Draw ()
  316. PlayerOne.height = ImageHeight (PlayerOne.image) * 0.2
  317. Return PlayerOne
  318. End Function
  319. ' ------------------------------------------------------------------------
  320. ' Type-specific methods...
  321. ' ------------------------------------------------------------------------
  322. ' This is passed the MouseX () and MouseY () positions in the main game
  323. ' loop, and hence moves the player toward the mouse cursor...
  324. Method Move (destx#, desty#, div#)
  325. xdist# = destx - x
  326. ydist# = desty - y
  327. xs = xdist / div
  328. ys = ydist / div
  329. x = x + xs
  330. y = y + ys
  331. End Method
  332. Method Draw (alpha# = 1, r = 255, g = 255, b = 255)
  333. SetBlend ALPHABLEND
  334. SetScale 0.2, 0.2
  335. If Shadows_On
  336. SetColor 0, 0, 0
  337. SetAlpha alpha * 0.4
  338. DrawImage image, x + 8, y + 8
  339. EndIf
  340. SetAlpha alpha
  341. ' If player is damaged, rgb will be RED...
  342. SetColor r, g, b
  343. DrawImage image, x, y
  344. SetScale 1, 1
  345. End Method
  346. End Type
  347. Type Shot Extends GravityItem
  348. ' ------------------------------------------------------------------------
  349. ' Type-specific functions...
  350. ' ------------------------------------------------------------------------
  351. Function Create:Shot (x#, y#, ys#, xs#, soundpan#)
  352. If Sounds_On
  353. play = CueSound (shoot)
  354. SetChannelPan play, soundpan
  355. ResumeChannel play
  356. EndIf
  357. s:Shot = New Shot
  358. s.x = x
  359. s.y = y
  360. s.xs = xs
  361. s.ys = ys
  362. s.width = 6
  363. s.height = 6
  364. s.damage = 2
  365. Return s
  366. End Function
  367. ' ------------------------------------------------------------------------
  368. ' Type-specific methods...
  369. ' ------------------------------------------------------------------------
  370. ' Over-ride standard GravityItem Update () method...
  371. Method Update ()
  372. ' Hit the player (note 'posyonly', 2nd parameter, of PlayerCollide)...
  373. If PlayerCollide (1, 1) Then Destroy; Return
  374. ys = ys + Gravity
  375. x = x + xs
  376. y = y + ys
  377. ' Remove if below bottom of screen...
  378. If y > GraphicsHeight ()
  379. Destroy
  380. Else
  381. ' Check current Shot against all Blocks...
  382. ' (Notice that this only checks Block objects in the list!)
  383. For blk:Block = EachIn GravityItemList
  384. ' Get x offset (rectangles are mid-handled)...
  385. ox = x - width / 2
  386. oy = y - height / 2
  387. ogx = blk.x - blk.width / 2
  388. ogy = blk.y - blk.width / 2
  389. ' Check collision...
  390. If OverLap (ox, oy, ox + width, oy + height, ogx, ogy, ogx + blk.width, ogy + blk.height)
  391. ' If Block is already dead (ie. falling), reflect Shot, otherwise
  392. ' un-fix block and create explosion...
  393. ' Note: ys is current Shot object's y speed...
  394. If blk.fixed = False
  395. ys = -ys
  396. Else
  397. blk.fixed = False
  398. blk.ys = ys / Rnd (1, 4)
  399. blk.angspeed = Rnd (-4, 4)
  400. ExplosionParticle.Explode ogx, ogy, 4
  401. EndIf
  402. EndIf
  403. Next
  404. EndIf
  405. End Method
  406. Method Draw ()
  407. SetBlend MASKBLEND
  408. SetAlpha 1
  409. SetColor 255, 255, 255
  410. DrawImage ShotImage, x, y
  411. End Method
  412. End Type
  413. ' The random debris that falls 'down' the screen...
  414. Type DebrisItem
  415. ' ------------------------------------------------------------------------
  416. ' Type-specific fields...
  417. ' ------------------------------------------------------------------------
  418. Field x# = Rand (0, GraphicsWidth () - 1)
  419. Field y# = Rand (0, GraphicsHeight () - 1)
  420. Field ys# = Rnd (0.01, 8)
  421. Field size = Rand (1, 2)
  422. ' ------------------------------------------------------------------------
  423. ' Type-specific methods...
  424. ' ------------------------------------------------------------------------
  425. Method Update ()
  426. If y > GraphicsHeight () y = 0
  427. y = y + ys
  428. End Method
  429. Method Draw ()
  430. SetColor Rnd (127, 255), Rnd (127, 255), 255
  431. SetBlend SOLIDBLEND
  432. DrawRect x, y, size, size
  433. End Method
  434. End Type
  435. ' -----------------------------------------------------------------------------
  436. ' Functions...
  437. ' -----------------------------------------------------------------------------
  438. ' Draw simple text with shadow...
  439. Function DrawShadowText (t$, x, y)
  440. SetColor 0, 0, 0
  441. DrawText t$, x + 1, y + 1
  442. SetColor 255, 255, 255
  443. DrawText t$, x, y
  444. End Function
  445. ' Returns "Off" if 'status' is 0, otherwise "On"...
  446. Function OnOff$ (status)
  447. If status Then Return "On" Else Return "Off"
  448. End Function
  449. ' Phew! Thanks, Birdie! Rectangular overlap function. Should have been so easy...
  450. Function OverLap (x0, y0, x1, y1, x2, y2, x3, y3)
  451. If x0 > x3 Or x1 < x2 Then Return False
  452. If y0 > y3 Or y1 < y2 Then Return False
  453. Return True
  454. End Function
  455. ' Distance between two points...
  456. Function Dist# (x0#, y0#, x1#, y1#)
  457. Return Sqr (((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0)))
  458. End Function
  459. ' -----------------------------------------------------------------------------
  460. ' Main game. This is where it all goes pear-shaped!
  461. ' -----------------------------------------------------------------------------
  462. ' Open display...
  463. 'Graphics 640, 480, 32
  464. x = GadgetWidth (Desktop ()) / 2 - 320
  465. y = GadgetHeight (Desktop ()) / 2 - 240
  466. window = CreateWindow ("RockOut GUI", x, y, 640, 480, Null, WINDOW_TITLEBAR)
  467. If Not window Notify "Couldn't open window!"; End
  468. canvas:TGadget = CreateCanvas (0, 0, ClientWidth (window), ClientHeight (window) - 48, window)
  469. If Not canvas Notify "Couldn't create canvas!"; End
  470. SetGraphics CanvasGraphics (canvas)
  471. ' Buttons...
  472. y = ClientHeight (window) - 24
  473. width = ClientWidth (window) / 4
  474. tbackground:TGadget = CreateButton ("Toggle background", 0, y, width, 24, window)
  475. tdebris:TGadget = CreateButton ("Toggle debris", width, y, width, 24, window)
  476. tshadows:TGadget = CreateButton ("Toggle shadows", width * 2, y, width, 24, window)
  477. tsounds:TGadget = CreateButton ("Toggle sounds", width * 3, y, width + 2, 24, window)
  478. tslabel:TGadget = CreateLabel ("Shields:", 20, y - 22, 60, 20, window, LABEL_CENTER)' | LABEL_FRAME)
  479. tshields:TGadget = CreateProgBar (100, y - 24, ClientWidth (window) - 100, 20, window)
  480. ' Pre-calc half of graphics width...
  481. Global GW2 = GraphicsWidth () / 2
  482. Global GH2 = GraphicsHeight () / 2
  483. ' Set Cls colour (used when background turned off)...
  484. SetClsColor 64, 96, 128
  485. ' All images' and rectangles' handles should be set to the centre...
  486. AutoMidHandle True
  487. SetHandle 0.5, 0.5
  488. ' All images unfiltered...
  489. 'AutoImageFlags MASKEDIMAGE
  490. ' Mask colour for loaded images (will be transparent)...
  491. SetMaskColor 255, 0, 255
  492. ' Mouse position -- used in some type methods and functions, hence global...
  493. Global mx, my
  494. ' Player object...
  495. Global PlayerOne:Player
  496. ' Draw shadows?
  497. Global Shadows_On = True
  498. ' Turn off sound?
  499. Global Sounds_On = True
  500. ' Load media -- sounds, from included binaries (see start of code)...
  501. Global shoot = LoadSound ("incbin::sounds/shot.ogg")
  502. Global hit = LoadSound ("incbin::sounds/hit.ogg")
  503. Global beep = LoadSound ("incbin::sounds/beep.ogg")
  504. Global over = LoadSound ("incbin::sounds/gameover.ogg")
  505. ' Load media -- images, from included binaries...
  506. ' Shots...
  507. Global ShotImage = LoadImage ("incbin::gfx/shot.png")
  508. ' Blocks...
  509. ' Note there is only one image for all blocks -- they are altered by SetColorRGB before
  510. ' drawing (WHITE gives normal image)...
  511. Global BlockImage = LoadImage ("incbin::gfx/block.png")
  512. ' Player...
  513. pimage = LoadImage ("incbin::gfx/boing.png",MASKEDIMAGE|MIPMAPPEDIMAGE)
  514. ' Background...
  515. ' Note that bgscale stores the length of the screen diagonal, and this value is used
  516. ' for the image height, so it doesn't get chopped when it rotates...
  517. bg = LoadImage ("incbin::gfx/land.png")
  518. bgscale# = Dist (0, 0, GraphicsWidth () - 1, GraphicsHeight () - 1) / ImageHeight (bg)
  519. ' Background angle/speed of rotation...
  520. bgang# = 0
  521. bgangspeed# = 0
  522. ' Create an array of 100 debris particles...
  523. Local debris:DebrisItem [100]
  524. For loop = 0 Until 100
  525. debris [loop] = New DebrisItem
  526. Next
  527. ' This should probably read 'rows' -- the number of rows of blocks at startup...
  528. layers = 5
  529. ' Toggle variables for drawing background, debris and wireframe mode...
  530. bgtoggle = 1
  531. debristoggle = 1
  532. wftoggle = 0
  533. ' Delay before adding another row of blocks (this is decreased as the game progresses)...
  534. rowdelay = 10000 ' 10 seconds (10000 milliseconds)...
  535. ' Background colour and first target colour...
  536. backr# = 64
  537. backg# = 96
  538. backb# = 180
  539. backtr# = 128
  540. backtg# = 32
  541. backtb# = 48
  542. ' Delay between colour increments...
  543. backstep# = 5000
  544. ' Colour increments...
  545. backstepr# = (backtr - backr) / backstep
  546. backstepg# = (backtg - backg) / backstep
  547. backstepb# = (backtb - backb) / backstep
  548. ' Direction of increment to target colour...
  549. backsgn = Sgn (backtr - backr)
  550. mx = GraphicsWidth () / 2
  551. my = GraphicsHeight () / 2
  552. MoveMouse mx, my
  553. timer = CreateTimer (60)
  554. ' This is the point where the game is re-started from, whenever a level is completed or game ended...
  555. #ResetLevel ' $name signifies a label now...
  556. ' Increase level number (level is 0 on startup, so becomes 1 for first level)...
  557. level = level + 1
  558. ' Reset the 'new row' delay timer to the current time...
  559. rowtimer = MilliSecs ()
  560. ' Set fire rate limiter to current time...
  561. firetimer = MilliSecs ()
  562. ' Create rows of blocks...
  563. For y = 0 To layers - 1
  564. For x = 0 Until GraphicsWidth () Step BLOCKWIDTH
  565. b:Block = Block.Create (x + BLOCKWIDTH / 2, (y * BLOCKHEIGHT) + BLOCKHEIGHT / 2)
  566. b.r = Rnd (127, 255)
  567. b.g = Rnd (127, 255)
  568. b.b = Rnd (127, 255)
  569. Next
  570. Next
  571. ' Minimum number of blocks left before we *stop* dropping them down (equivalent of 2 rows)...
  572. lowblocks = 2 * (GraphicsWidth () / BLOCKWIDTH)
  573. ' When a level is completed, we delete the player object for simplicity of resetting
  574. ' all its values. This creates it (same for game startup)...
  575. If PlayerOne = Null Then PlayerOne = Player.Create (mx, my, pimage)
  576. ' Game text and precalculated x offsets...
  577. go$ = "G A M E O V E R -- H I T S P A C E O R R M B"
  578. wd$ = "W E L L D O N E -- H I T S P A C E O R R M B"
  579. gox = (GraphicsWidth () / 2) - (TextWidth (go$) / 2)
  580. wdx = (GraphicsWidth () / 2) - (TextWidth (wd$) / 2)
  581. ActivateGadget canvas
  582. firing = 0
  583. HideMouse
  584. firstgo = 1
  585. Repeat
  586. ' Mac compatibility fix...
  587. ' SetGraphics CanvasGraphics (canvas)
  588. WaitEvent
  589. ' Clear the screen...
  590. Cls
  591. ' Store mouse position in these global variables...
  592. Select EventID ()
  593. Case EVENT_MOUSEENTER
  594. If EventSource () = canvas Then HideMouse
  595. Case EVENT_MOUSELEAVE
  596. If EventSource () = canvas Then ShowMouse
  597. Case EVENT_TIMERTICK
  598. 'Print "Tick!"
  599. RedrawGadget canvas
  600. Case EVENT_GADGETPAINT
  601. draw = 1
  602. Case EVENT_MOUSEDOWN
  603. If EventData () = 1
  604. firing = 1
  605. EndIf
  606. Case EVENT_MOUSEUP
  607. firing = 0
  608. If EventData () = 2
  609. spacehit = 1
  610. EndIf
  611. Case EVENT_MOUSEMOVE
  612. mx = EventX ()
  613. my = EventY ()
  614. Case EVENT_KEYUP
  615. ' -----------------------------------------------------------------------
  616. ' Toggles...
  617. ' -----------------------------------------------------------------------
  618. Select EventData ()
  619. Case KEY_ESCAPE
  620. End
  621. Case KEY_SPACE
  622. spacehit = 1
  623. End Select
  624. Case EVENT_GADGETACTION
  625. Select EventSource ()
  626. Case tbackground:TGadget
  627. bgtoggle = 1 - bgtoggle
  628. Case tdebris:TGadget
  629. debristoggle = 1 - debristoggle
  630. Case tshadows:TGadget
  631. Shadows_On = 1 - Shadows_On
  632. Case tsounds:TGadget
  633. Sounds_On = 1 - Sounds_On
  634. End Select
  635. ActivateGadget canvas ' Get event focus back!
  636. End Select
  637. ' -----------------------------------------------------------------------
  638. ' Background...
  639. ' -----------------------------------------------------------------------
  640. If draw ' EVENT_GADGETPAINT received...
  641. ' Update background rotation...
  642. bgang = bgang + bgangspeed; If bgang > 359 - bgangspeed Then bgang = 0
  643. bgangspeed = bgangspeed + 0.0001
  644. ' The bgtoggle variable controls whether the background should be drawn or not...
  645. If bgtoggle
  646. ' Change colour by pre-calculated increment...
  647. backr = backr + backstepr
  648. backg = backg + backstepg
  649. backb = backb + backstepb
  650. ' Reached target colour? Set a new target/increments/increment-direction...
  651. If backr => backtr * backsgn
  652. backtr = Rnd (255)
  653. backtg = Rnd (255)
  654. backtb = Rnd (255)
  655. backstepr# = (backtr - backr) / backstep
  656. backstepg# = (backtg - backg) / backstep
  657. backstepb# = (backtb - backb) / backstep
  658. backsgn = Sgn (backtr - backr)
  659. EndIf
  660. EndIf
  661. ' When the player is hit, the 'damaged' field is set to the current time.
  662. ' This code checks if a second has passed since 'damaged'. If so, it draws
  663. ' the player normally; if not, the player is drawn in red, with varying
  664. ' transparency...
  665. If MilliSecs () > PlayerOne.damaged + 1000 ' Damage timeout has passed...
  666. ' Draw normally...
  667. PlayerOne.damaged = 0 ' Resetting damage time...
  668. alpha# = 1
  669. rcol = 255; gcol = 255; bcol = 255
  670. Else
  671. ' Flash player for 1 second if hit...
  672. alpha# = Sin (MilliSecs ())
  673. rcol = 255; gcol = 0; bcol = 0
  674. EndIf
  675. ' -----------------------------------------------------------------------
  676. ' If player is alive, do stuff...
  677. ' -----------------------------------------------------------------------
  678. If Int (PlayerOne.shields) > 0 ' Shields is a float, so gotta round it...
  679. ' Player is alive...
  680. ' If more than 'lowblocks' left on screen, add a row and lower all
  681. ' blocks. Reset drop-down timer and reduce delay for next drop-down...
  682. If Block.BCount > lowblocks And MilliSecs () > rowtimer + rowdelay
  683. ' Add a row of blocks, above top of screen...
  684. For x = 0 Until GraphicsWidth () Step BLOCKWIDTH
  685. b:Block = Block.Create (x + BLOCKWIDTH / 2, -BLOCKHEIGHT / 2)
  686. b.r = Rnd (127, 255)
  687. b.g = Rnd (127, 255)
  688. b.b = Rnd (127, 255)
  689. Next
  690. ' Set all blocks' target y position down by block height. When blocks
  691. ' are updated, they get moved towards this new position...
  692. For b:Block = EachIn GravityItem.GravityItemList
  693. b.desty = b.desty + BLOCKHEIGHT
  694. Next
  695. ' Reset timeout until a new row is added...
  696. rowtimer = MilliSecs ()
  697. ' Reduce row-down timeout a bit...
  698. If rowdelay => 1100 Then rowdelay = rowdelay - 100 ' Minimum 1 sec interval!
  699. EndIf
  700. ' --------------------------------------------------------------------
  701. ' Fire shot (maximum fire rate 75 milliseconds)...
  702. ' --------------------------------------------------------------------
  703. If firing 'MouseDown (1)
  704. If MilliSecs () > firetimer + 75
  705. pan# = PlayerOne.x / GW2 - 1.0
  706. s:Shot = Shot.Create (PlayerOne.x, PlayerOne.y - (PlayerOne.height / 2 + 5), -5, PlayerOne.xs / 5.0, pan)
  707. firetimer = MilliSecs ()
  708. EndIf
  709. EndIf
  710. ' --------------------------------------------------------------------
  711. ' No blocks left?
  712. ' --------------------------------------------------------------------
  713. ' Set 'welldone' flag (text shows "Well done" below if True);
  714. ' If there are no blocks and Space is hit, delete all GravityItems,
  715. ' reduce block count, increase number of block rows and reset level...
  716. If Block.BCount = 0
  717. ' Will display 'well done' message further down...
  718. welldone = True
  719. ' Remove all items (and reduce block count)...
  720. For g:GravityItem = EachIn GravityItem.GravityItemList
  721. If Block (g) Then Block.BCount = Block.BCount - 1
  722. g.Destroy
  723. Next
  724. ' If space is hit, add some layers and reset everything (new level)...
  725. If spacehit'KeyHit (KEY_SPACE) Or MouseHit (2)
  726. If Sounds_On Then PlaySound beep
  727. layers = layers + 3
  728. Goto ResetLevel
  729. EndIf
  730. EndIf
  731. Else
  732. If gameoverplayed = 0
  733. If Sounds_On Then PlaySound over
  734. gameoverplayed = 1
  735. EndIf
  736. ' Player is dead...
  737. PlayerOne.shields = 0 ' Force to zero as can be reduced after game is over...
  738. gameover = True
  739. ' Remove all blocks...
  740. For b:Block = EachIn GravityItem.GravityItemList
  741. b.Destroy
  742. Block.BCount = Block.BCount - 1
  743. Next
  744. ' -------------------------------------------------------------------
  745. ' If player is dead and Space hit...
  746. ' -------------------------------------------------------------------
  747. ' Space hit... remove everything else and reset to initial settings...
  748. If spacehit'KeyHit (KEY_SPACE) Or MouseHit (2)
  749. If Sounds_On Then PlaySound beep
  750. For g:GravityItem = EachIn GravityItem.GravityItemList
  751. g.Destroy
  752. Next
  753. ' Delete player (recreated when level is reset)...
  754. PlayerOne = Null
  755. layers = 5
  756. bgang = 0
  757. bgangspeed = 0
  758. level = 0
  759. rowdelay = 10000
  760. gameoverplayed = 0
  761. Goto ResetLevel
  762. EndIf
  763. EndIf
  764. If debristoggle
  765. For loop = 0 Until 100
  766. debris [loop].Update
  767. Next
  768. EndIf
  769. If bgtoggle
  770. ' Set colour of background image (applied to the greyscale default)...
  771. SetColor backr, backg, backb
  772. ' Set the background's pre-calculated scale...
  773. SetScale bgscale, bgscale
  774. SetRotation bgang
  775. SetAlpha 1
  776. DrawImage bg, GW2, GH2
  777. ' Reset this stuff so next drawn items don't have to...
  778. SetRotation 0
  779. SetScale 1, 1
  780. ' Put back to wireframe/non-wireframe mode, depending on value of 'wftoggle'...
  781. ' WireFrame wftoggle
  782. EndIf
  783. ' -----------------------------------------------------------------------
  784. ' Debris...
  785. ' -----------------------------------------------------------------------
  786. ' Draw debris particles if 'debristoggle' is True...
  787. If debristoggle
  788. For loop = 0 Until 100
  789. ' debris [loop].Update
  790. debris [loop].Draw
  791. Next
  792. EndIf
  793. ' -----------------------------------------------------------------------
  794. ' Cursor...
  795. ' -----------------------------------------------------------------------
  796. SetColor 255, 255, 255
  797. DrawLine mx - 8, my, mx + 8, my
  798. DrawLine mx, my - 8, mx, my + 8
  799. ' -----------------------------------------------------------------------
  800. ' Move and draw player...
  801. ' -----------------------------------------------------------------------
  802. ' Move the player object based on mouse position (the '20' controls the
  803. ' speed at which the player moves toward the mouse -- play with it;
  804. ' lower is faster)...
  805. PlayerOne.Move (mx, my, 12)
  806. ' Draw the player using the above values...
  807. PlayerOne.Draw (alpha, rcol, gcol, bcol)
  808. ' -----------------------------------------------------------------------
  809. ' Update everything...
  810. ' -----------------------------------------------------------------------
  811. GravityItem.UpdateAll
  812. ' -----------------------------------------------------------------------
  813. ' Draw text on top of everything...
  814. ' -----------------------------------------------------------------------
  815. SetAlpha 1
  816. DrawShadowText "Level: " + level, 20, GraphicsHeight () - 40
  817. ' + " | Shields: " + Int (PlayerOne.shields) + "%"
  818. UpdateProgBar tshields, Int (PlayerOne.Shields) / 100.0
  819. ' Draw extra text if appropriate...
  820. If gameover
  821. DrawShadowText go$, gox, GraphicsHeight () / 2
  822. gameover = False
  823. Else
  824. If welldone
  825. DrawShadowText wd$, wdx, GraphicsHeight () / 2
  826. welldone = False
  827. EndIf
  828. EndIf
  829. ' Display everything that's been drawn to the hidden back buffer...
  830. Flip
  831. spacehit = 0
  832. draw = 0
  833. EndIf
  834. Until EventID () = EVENT_WINDOWCLOSE
  835. End