digesteroids.bmx 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496
  1. ' *******************************************************************
  2. ' Digesteroids - V1.0
  3. ' --------------------------------------------------------
  4. ' An evil biscuit corporation are using their army of
  5. ' sweet snack food to take over the world. Use your ship
  6. ' to take down the evil invading corporation before
  7. ' they infest the world with dunkables sweetmeal biscuits.
  8. ' REQUIRES 1024x768x32! @75Hz
  9. ' --------------------------------------------------------
  10. ' Author: Rob Hutchinson 2004
  11. ' Email: [email protected]
  12. ' Written entirely in Protean IDE:
  13. ' WWW: http://www.proteanide.co.uk/
  14. ' --------------------------------------------------------
  15. ' Yep, there's stuff in here, I didnt get time to implement
  16. ' Pickups, Weapons and Vortexes.
  17. ' *******************************************************************
  18. Strict
  19. ' Import various utilities.
  20. Import "simplephysics.bmx"
  21. Import "dynamicgame.bmx"
  22. Import "MathUtil.bmx"
  23. ' Screen settings.
  24. Const WIDTH = 1024 ' Width of the screen.
  25. Const HEIGHT = 768 ' Height of the screen.
  26. Const DEPTH = 32 ' Depth of the screen.
  27. Const REFRESHRATE = 75 ' How often to update the screen (Per second).
  28. ' Game Settings
  29. Const DYNAMICTIMING = True ' If true then the game will try to keep up with
  30. Const DESIREDFPS = 75 ' The Desired FPS of the game, can be independant of Refresh Rate.
  31. Function ScreenPan(OffsetX:Float, OffsetY:Float)
  32. Local Width,Height,Depth,Hz
  33. Width=GraphicsWidth()
  34. Height=GraphicsHeight()
  35. Depth=GraphicsDepth()
  36. Hz=GraphicsHertz()
  37. glMatrixMode GL_PROJECTION
  38. glLoadIdentity
  39. glOrtho 0,Width,Height,0,-1,1
  40. glTranslatef OffsetX, OffsetY,0
  41. glMatrixMode GL_MODELVIEW
  42. EndFunction
  43. Function QFlushKeys()
  44. ' Quick implementation of flushkeys as BMX doesnt have one at time of writing, sure it
  45. ' will be added though.
  46. For Local Key:Int = 0 To 255
  47. KeyHit(Key)
  48. KeyDown(Key)
  49. Next
  50. End Function
  51. '#Region Scene: MainMenu
  52. ' The main menu scene.
  53. Type MainMenuScene Extends T2DDynamicGameScene
  54. '#Region DrawTextCentered
  55. Function DrawTextCentered:Int(Text:String,Y:Int)
  56. Local Out:Int = (WIDTH / 2) - (TextWidth(Text) / 2)
  57. DrawText(Text, Out, Y)
  58. Return Out
  59. End Function
  60. '#End Region
  61. '#Region Declarations
  62. Const STARS_PER_SECOND = 6
  63. Field BackColor:Float
  64. Field Direction:Float = 0.01
  65. Field ExitGame:Int = False
  66. Field Music:TSound
  67. Field MusicChannel:TChannel
  68. Field Title:TImage
  69. Field LowerTitle:TImage
  70. Field Options:TImage
  71. Field Craft:TImage
  72. Field EnteredText:String = ""
  73. Field LastHighScore:Int
  74. Field ShowCredits:Int = False
  75. Field Viewing:Int = VIEW_MENU
  76. Field HoverOver:Int = VIEW_START
  77. Const VIEW_MENU = 0
  78. Const VIEW_START = 0
  79. Const VIEW_INSTRUCTIONS = 1
  80. Const VIEW_HIGHSCORES = 2
  81. Const VIEW_QUIT = 3
  82. Const VIEW_ENTERHIGH = 4
  83. Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
  84. Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.0, 0.0, 0.0, True)
  85. '#End Region
  86. '#Region Method: FinishScoreEntry
  87. Method FinishScoreEntry()
  88. Self.ViewMenu(VIEW_HIGHSCORES)
  89. Scores.Add(Self.LastHighScore, Self.EnteredText)
  90. ' Add this to the high scores..
  91. Self.LastHighScore = 0
  92. Self.EnteredText = ""
  93. End Method
  94. '#End Region
  95. '#Region Method: ViewMenu
  96. Method ViewMenu(Menu:Int)
  97. Self.Viewing = Menu
  98. Self.HoverOver = Menu
  99. QFlushKeys()
  100. End Method
  101. '#End Region
  102. '#Region Method: Update
  103. Method Update()
  104. Self.Stars.ApplyPhysics()
  105. ' Add new stars..
  106. For Local CountStars:Int = 0 To STARS_PER_SECOND
  107. Local Star:TMenuStar = TMenuStar.Create(World, Self, 10.0)
  108. Self.Stars.AddLast(Star)
  109. Next
  110. ' Do enter key checking..
  111. Select Self.Viewing
  112. Case VIEW_MENU
  113. If KeyHit(KEY_ENTER) Then
  114. Select Self.HoverOver
  115. Case VIEW_START
  116. Self.TerminateMainLoop = True
  117. Case VIEW_INSTRUCTIONS
  118. Self.ViewMenu(VIEW_INSTRUCTIONS)
  119. Case VIEW_HIGHSCORES
  120. Self.ViewMenu(VIEW_HIGHSCORES)
  121. Case VIEW_QUIT
  122. Self.TerminateMainLoop = True
  123. Self.ExitGame = True
  124. End Select
  125. EndIf
  126. If KeyHit(KEY_UP)
  127. Self.HoverOver :- 1
  128. If Self.HoverOver < VIEW_START Then Self.HoverOver = VIEW_START
  129. EndIf
  130. If KeyHit(KEY_DOWN)
  131. Self.HoverOver :+ 1
  132. If Self.HoverOver > VIEW_QUIT Then Self.HoverOver = VIEW_QUIT
  133. EndIf
  134. If KeyHit(KEY_ESCAPE) Then
  135. Self.TerminateMainLoop = True
  136. Self.ExitGame = True
  137. Else
  138. If KeyHit(KEY_C)
  139. Self.TerminateMainLoop = True
  140. Self.ShowCredits = True
  141. EndIf
  142. EndIf
  143. Case VIEW_INSTRUCTIONS, VIEW_HIGHSCORES
  144. If KeyHit(KEY_ENTER) Or KeyHit(KEY_ESCAPE)
  145. Self.Viewing = VIEW_MENU
  146. EndIf
  147. Case VIEW_ENTERHIGH
  148. ' Check for alpha keys.
  149. For Local Count:Int = KEY_A To KEY_Z
  150. If KeyHit(Count) Then Self.EnteredText = Self.EnteredText + Chr(Count)
  151. Next
  152. ' Check for number key hits
  153. For Local Count:Int = KEY_0 To KEY_9
  154. If KeyHit(Count) Then Self.EnteredText = Self.EnteredText + Chr(Count)
  155. Next
  156. ' Special case, check for space bar
  157. If KeyHit(KEY_SPACE)
  158. Self.EnteredText = Self.EnteredText + " "
  159. EndIf
  160. ' Remove a character when user hits backspace.
  161. If KeyHit(KEY_BACKSPACE)
  162. If Len(Self.EnteredText) > 0
  163. Self.EnteredText = Mid(Self.EnteredText,0,Len(Self.EnteredText))
  164. EndIf
  165. EndIf
  166. ' If 5 characters are entered, end high score entry.
  167. If Len(Self.EnteredText) = 5 Then Self.FinishScoreEntry()
  168. If KeyHit(KEY_ENTER)
  169. Self.FinishScoreEntry()
  170. EndIf
  171. End Select
  172. End Method
  173. '#End Region
  174. '#Region Method: Render
  175. Method Render()
  176. Cls
  177. ScreenPan(0,0)
  178. SetTransform
  179. SetAlpha 1.0
  180. SetBlend(SOLIDBLEND)
  181. Self.Stars.Draw()
  182. SetColor 255,255,255
  183. SetBlend(ALPHABLEND)
  184. DrawImage(Self.Title,0,40)
  185. DrawImage(Self.LowerTitle,0,660)
  186. Local StartPosX:Int = 150
  187. Local StartPosY:Int = 245
  188. Select Self.Viewing
  189. Case VIEW_MENU
  190. ' Showing main menu
  191. DrawImage(Self.Options,450,330)
  192. SetRotation -90
  193. Select Self.HoverOver
  194. Case VIEW_START
  195. DrawImage(Self.Craft,416,352)
  196. Case VIEW_INSTRUCTIONS
  197. DrawImage(Self.Craft,416,352 + 37)
  198. Case VIEW_HIGHSCORES
  199. DrawImage(Self.Craft,416,352 + 74)
  200. Case VIEW_QUIT
  201. DrawImage(Self.Craft,416,352 + 145)
  202. End Select
  203. Case VIEW_HIGHSCORES
  204. Scores.Render(385,310)
  205. Case VIEW_ENTERHIGH
  206. DrawTextCentered("CONGRATULATIONS!",StartPosY)
  207. DrawTextCentered("You have a new high score!",StartPosY+50)
  208. DrawTextCentered("Please enter your name (5 characters)",StartPosY+65)
  209. Local TextX:Int = DrawTextCentered(Self.EnteredText,StartPosY+250)
  210. DrawRect(TextX + TextWidth(Self.EnteredText), StartPosY+250, 12, 15)
  211. Case VIEW_INSTRUCTIONS
  212. DrawText("Welcome to Digesteroids!",StartPosX,StartPosY)
  213. DrawText("------------------------",StartPosX,StartPosY+20)
  214. DrawText("An evil biscuit corporation are using their army of sweet snack food to take over the world.",StartPosX,StartPosY+50)
  215. DrawText("Fortunately, the ingredients the evil corporation used are vulnerable to big sweaty laser",StartPosX,StartPosY+70)
  216. DrawText("blasts. Use your ship's cannon to take out the corporation before they infest the world with",StartPosX,StartPosY+90)
  217. DrawText("sweetmeal dunkables biscuits. But be careful, space is small (just big enough to fit inside",StartPosX,StartPosY+110)
  218. DrawText("your screen), it is also cyclical, so beware of incoming oval shaped objects.",StartPosX,StartPosY+130)
  219. DrawText("Keys:",StartPosX,StartPosY+180)
  220. DrawText(" - UP CURSOR ARROW = Thrust",StartPosX,StartPosY+200)
  221. DrawText(" - DOWN CURSOR ARROW = Teleport",StartPosX,StartPosY+220)
  222. DrawText(" - LEFT CURSOR ARROW = Rotate Ship Left",StartPosX,StartPosY+240)
  223. DrawText(" - RIGHT CURSOR ARROW = Rotate Ship Right",StartPosX,StartPosY+260)
  224. DrawText(" - ESCAPE = QUIT",StartPosX,StartPosY+280)
  225. DrawText("Yes, that's right, it's a glorified asteroids game!",StartPosX,StartPosY+320)
  226. SetColor 255,0,0
  227. DrawText("Note: Your score is based on the speed at which your ship is travelling when it fired.",StartPosX,StartPosY+340)
  228. End Select
  229. End Method
  230. '#End Region
  231. '#Region Method: Start
  232. Method Start()
  233. Self.MusicChannel = AllocChannel()
  234. If Self.Music = Null Then Self.Music = LoadSound("sounds\menu.ogg",True)
  235. PlaySound(Self.Music,Self.MusicChannel)
  236. SetChannelVolume MusicChannel,1.0
  237. ' Load GFX..
  238. If Self.Title = Null Then Self.Title = LoadImage("graphics\title.png")
  239. If Self.LowerTitle = Null Then Self.LowerTitle = LoadImage("graphics\lower.png")
  240. If Self.Options = Null Then Self.Options = LoadImage("graphics\options.png")
  241. If Self.Craft = Null Then Self.Craft = LoadImage("graphics\ship.png")
  242. ' Add a screen full of stars.
  243. For Local CountStars:Int = 0 To 1000
  244. Local Star:TMenuStar = TMenuStar.Create(World, Self, 10.0)
  245. Star.X = Rnd(WIDTH)
  246. Self.Stars.AddLast(Star)
  247. Next
  248. End Method
  249. '#End Region
  250. '#Region Method: Finish
  251. Method Finish()
  252. Self.Stars.Clear()
  253. Self.MusicChannel.Stop()
  254. Self.MusicChannel = Null
  255. End Method
  256. '#End Region
  257. End Type
  258. '#End Region
  259. '#Region Scene: MainGame
  260. ' Main Game scene
  261. Type MainGameScene Extends T2DDynamicGameScene
  262. '#Region Declarations
  263. Const STARS_PER_SECOND = 3
  264. Const FINISH_AT_LEVEL = 6
  265. Field Level:Int = 1
  266. Field Completed:Int = False
  267. Field DigestiveImage:TImage
  268. Field ShipImage:TImage
  269. Field StarsImage:TImage
  270. Field LargeImpactSound:TSound
  271. Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.0, 0.0, 0.0, True)
  272. Field Digestives:TPhysicsProviderCollection = New TPhysicsProviderCollection
  273. Field Bullets:TPhysicsProviderCollection = New TPhysicsProviderCollection
  274. Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
  275. Field Chunks:TFountain
  276. Const CHUNK_COUNT = 2
  277. Field ChunkImages:TImage[CHUNK_COUNT + 1]
  278. Field Player:TPlayer
  279. Field Shake:Float
  280. Field Pickups:TList = New TList
  281. '#End Region
  282. '#Region Method: Update
  283. Method Update()
  284. If KeyHit(KEY_ESCAPE) Then Self.TerminateMainLoop = True
  285. CheckEndOfLevel() ' Check if we need to move to the next level (IE, all digestives gone)
  286. ' Add new stars..
  287. For Local CountStars:Int = 0 To STARS_PER_SECOND
  288. Local Speed:Float = Self.Player.Speed()
  289. If Speed < 1.0 Then Speed = 1.0
  290. Local Star:TStar = TStar.Create(World, Self, Speed)
  291. Self.Stars.AddLast(Star)
  292. Next
  293. ' Update screenshake...
  294. Self.Shake :/ 1.02
  295. If Self.Shake < 0.0 Then Self.Shake = 0.0
  296. If Self.Shake > 6.0 Then Self.Shake = 6.0
  297. ' Update all the stars.
  298. Self.Stars.ApplyPhysics()
  299. ' Update the chunks
  300. Self.Chunks.UpdateWithFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
  301. ' Update all the digestives.
  302. Self.Digestives.ApplyPhysics()
  303. ' Update all the bullets.
  304. Self.Bullets.ApplyPhysics()
  305. ' Update the player.
  306. Self.Player.Update()
  307. Self.Player.ApplyFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
  308. Self.Player.ApplyPhysics()
  309. End Method
  310. '#End Region
  311. '#Region Method: Render
  312. Method Render()
  313. SetClsColor 0,0,0
  314. Cls
  315. If Self.Shake > 0.0 Then
  316. ScreenPan(Rnd(Shake),Rnd(Shake))
  317. EndIf
  318. ' Draw the spazzy psychodelic effect if it is enabled.
  319. Self.DrawPsychodelic()
  320. SetAlpha 1
  321. SetTransform
  322. ' Draw all the stars.
  323. Self.Stars.Draw()
  324. Self.Chunks.Draw()
  325. ' Draw the digestives.
  326. SetColor 255,255,255
  327. SetBlend(ALPHABLEND)
  328. Digestives.Draw()
  329. ' Draw the bullets
  330. SetBlend(LIGHTBLEND)
  331. Bullets.Draw()
  332. ' Draw the player.
  333. SetBlend(ALPHABLEND)
  334. Player.Draw()
  335. ' Draw the hud
  336. DrawHUD()
  337. End Method
  338. '#End Region
  339. '#Region Method: Start
  340. Method Start()
  341. AutoMidHandle True
  342. Self.Shake = 0
  343. Self.Chunks = TFountain.Create(Self.World,TRectangle.Create(0,0,WIDTH,HEIGHT))
  344. ' Load in the required Images...
  345. If Self.DigestiveImage = Null Then Self.DigestiveImage = LoadImage("graphics\digestive.png")
  346. If Self.ShipImage = Null Then Self.ShipImage = LoadImage("graphics\ship.png")
  347. If Self.StarsImage = Null Then Self.StarsImage = LoadImage("graphics\stars.png")
  348. For Local LoadCount:Int = 0 To CHUNK_COUNT
  349. Self.ChunkImages[LoadCount] = LoadImage("graphics\piece" + String(LoadCount + 1) + ".png")
  350. Next
  351. ' Set up the player
  352. Self.Player = TPlayer.Create(Self.World, Self.ShipImage,Self)
  353. Self.Player.LoadAssets()
  354. ' Load up the sounds.
  355. If Self.LargeImpactSound = Null Then Self.LargeImpactSound = LoadSound("Sounds\ImpactLarge.wav")
  356. ' Reset the game..
  357. Self.ResetGame()
  358. ' Create all the weapons..
  359. Self.Pickups.Clear()
  360. Local Bullet1Image:TImage = LoadImage("graphics\bullet1.png")
  361. Local Fire1Sound:TSound = LoadSound("sounds\fire.wav")
  362. ' Local Blaster:TWeapon = TWeapon.Create(Speed,Graphic,Size,Radius,Veer,FireRate,MainGame,Sound)
  363. Local Blaster:TWeapon = TWeapon.Create(10, Bullet1Image, 0.65, 4.0, 0,30, Self, Fire1Sound, Bullet1Image, "Blaster")
  364. Local FastBlaster:TWeapon = TWeapon.Create(9, Bullet1Image, 0.3, 4.0, 0.0, 15, Self, Fire1Sound, Bullet1Image, "Blaster Mk2")
  365. Local SprayBlaster:TWeapon = TWeapon.Create(8, Bullet1Image, 0.35, 4.0, 5.0, 1, Self, Fire1Sound, Bullet1Image, "Blaster Mk3")
  366. Local BlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,Blaster,Bullet1Image,0.01,Bullet1Image)
  367. Local FastBlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,FastBlaster,Bullet1Image,0.01,Bullet1Image)
  368. Local SprayBlasterPickup:TPickup = TPickup.Create(TPickup.MODIFIER_WEAPON,0,0,True,SprayBlaster,Bullet1Image,0.008,Bullet1Image)
  369. Local Score1000Pickup:TPickup = TPickup.Create(TPickup.MODIFIER_SCORE,1000,0,True,Null,Null,0.02,Bullet1Image)
  370. Local Score500Pickup:TPickup = TPickup.Create(TPickup.MODIFIER_SCORE,500,0,True,Null,Null,0.03,Bullet1Image)
  371. Local RotationPickup:TPickup = TPickup.Create(TPickup.MODIFIER_ROTATION,1.1,0,True,Null,Null,0.01,Bullet1Image)
  372. Local PsychodelicPickup:TPickup = TPickup.Create(TPickup.MODIFIER_PSYCHODELIC,0,1000,False,Null,Null,0.04,Bullet1Image)
  373. Local LivesPickup:TPickup = TPickup.Create(TPickup.MODIFIER_LIVES,1,0,True,Null,Null,0.001,Bullet1Image)
  374. Self.Player.Weapon = Blaster
  375. End Method
  376. '#End Region
  377. '#Region Method: Finish
  378. Method Finish()
  379. Self.Player.ThrusterChannel.Stop
  380. Self.Player.ThrusterChannel = Null
  381. End Method
  382. '#End Region
  383. '#Region Method: CheckEndOfLevel
  384. Method CheckEndOfLevel()
  385. If Digestives.IsEmpty() = True
  386. ' No more digestives..
  387. Level :+ 1
  388. If Level = FINISH_AT_LEVEL Then
  389. ' This was the last level.
  390. Self.Completed = True
  391. Self.TerminateMainLoop = True
  392. Else
  393. ' Move to the next level
  394. GotoLevel(Level)
  395. EndIf
  396. EndIf
  397. End Method
  398. '#End Region
  399. '#Region Method: DrawHUD
  400. Method DrawHUD()
  401. SetColor 255,255,255
  402. SetAlpha 1.0
  403. SetRotation 0
  404. DrawText "Level: " + Level,0,0
  405. Local Lives:String = "Lives: " + Player.Lives
  406. Local Score:String = "Score: " + Player.Score
  407. DrawText Score,(WIDTH / 2) - (TextWidth(Score) / 2) ,0
  408. DrawText Lives,(WIDTH - TextWidth(Lives)) ,0
  409. Local fr$="000"+Int(Self.Player.Speed()*1000) Mod 1000
  410. Local sp$=Int(Self.Player.Speed()*1000)/1000+"."+fr[fr.length-3..]
  411. DrawText "Speed: " + sp,0,15
  412. DrawText "Teleports: " + Self.Player.Teleports,0,30
  413. End Method
  414. '#End Region
  415. '#Region Method: ResetGame
  416. Method ResetGame()
  417. Digestives.Clear()
  418. Bullets.Clear()
  419. Stars.Clear()
  420. Chunks.Particles.Clear()
  421. Player.Lives = 5
  422. Player.Reset()
  423. GotoLevel(1)
  424. End Method
  425. '#End Region
  426. '#Region Method: GotoLevel
  427. Method GotoLevel(ToLevel:Int)
  428. Level = ToLevel
  429. For Local Count:Int = 1 To ToLevel
  430. Local Digestive:TDigestive = TDigestive.Create(World, DigestiveImage,Self)
  431. Digestive.X = Rnd(0,WIDTH)
  432. Digestive.Y = Rnd(0,HEIGHT)
  433. Digestive.Rotation = Rnd(360)
  434. Digestive.Weight = 5
  435. Digestive.SetVelocityFromAngle(Rnd(360.0),Rnd(0.5,1.5))
  436. Digestive.HitSound = Self.LargeImpactSound
  437. Digestives.AddLast(Digestive)
  438. Next
  439. End Method
  440. '#End Region
  441. '#Region Method: DrawPsychodelic
  442. Field PsychoAngle:Float = 0
  443. Field Psycho:Int = False
  444. Method DrawPsychodelic()
  445. If Psycho = True
  446. SetColor Rnd(0.0,255),Rnd(0.0,255),Rnd(0.0,255)
  447. PsychoAngle :+ 8
  448. SetBlend(SOLIDBLEND)
  449. TileImage(StarsImage,Sin(PsychoAngle) * 200,Cos(PsychoAngle) * 200)
  450. Else
  451. SetColor 255,255,255
  452. EndIf
  453. End Method
  454. '#End Region
  455. '#Region Method: FindSafeLocation
  456. Method FindSafeLocation:TPointD(Radius:Float)
  457. While True
  458. Local X:Int = Rnd(0,WIDTH)
  459. Local Y:Int = Rnd(0,HEIGHT)
  460. If Self.IsLocationSafe(X,Y,Radius)
  461. Local Out:TPointD = New TPointD
  462. Out.X = X
  463. Out.Y = Y
  464. Return Out
  465. EndIf
  466. Wend
  467. End Method
  468. '#End Region
  469. '#Region Method: IsLocationSafe
  470. Method IsLocationSafe:Int(X:Int,Y:Int,Radius:Float)
  471. Local TryCircle:TCircle = New TCircle
  472. TryCircle.X = X
  473. TryCircle.Y = Y
  474. TryCircle.Radius = Radius
  475. For Local Item:TDigestive = EachIn Self.Digestives
  476. If Item.Circle.CollidesWith(TryCircle)
  477. Return False
  478. EndIf
  479. Next
  480. Return True
  481. End Method
  482. '#End Region
  483. End Type
  484. '#End Region
  485. '#Region Scene: Ending
  486. ' The ending scene.
  487. Type EndingScene Extends T2DDynamicGameScene
  488. '#Region Declarations
  489. Const STARS_PER_SECOND = 0
  490. Const MAGNET_COUNT = 5
  491. Field ScrollPoint:Float
  492. Field Music:TSound
  493. Field MusicChannel:TChannel
  494. Field Title:TImage
  495. Field Time:Int = 1000000
  496. Field TEXTS_COUNT = 23
  497. Field Texts:String[TEXTS_COUNT]
  498. Field Stars:TPhysicsProviderCollection = New TPhysicsProviderCollection
  499. Field World:TWorldPhysicsProvider = TWorldPhysicsProvider.Create(0.2, 0.0, 0.0, True)
  500. '#End Region
  501. '#Region Method: Update
  502. Method Update()
  503. Self.Stars.ApplyPhysics()
  504. If KeyHit(KEY_ESCAPE) Then
  505. Self.TerminateMainLoop = True
  506. EndIf
  507. Self.Time :+ 1
  508. If Self.Time > 100 Then
  509. Self.Time = 0
  510. ' Add a new magnet
  511. Local ThisMagnet:TEndMagnet = New TEndMagnet
  512. ThisMagnet.X = Rnd(WIDTH)
  513. ThisMagnet.Y = Rnd(HEIGHT)
  514. ThisMagnet.Radius = Rnd(200,500)
  515. ThisMagnet.Polarity = TMagnet.PositivePolarity
  516. ThisMagnet.Strength = Rnd(0.1,0.5)
  517. Self.World.Magnets.AddLast(ThisMagnet)
  518. Self.World.ApplyMagnets = True
  519. EndIf
  520. Local X:Int = WIDTH/2
  521. Local Y:Int = HEIGHT/2
  522. For Local Magnet:TEndMagnet = EachIn Self.World.Magnets
  523. For Local Count:Int = 0 To STARS_PER_SECOND
  524. Local ThisStar:TEndingStar = TEndingStar.Create(Self.World, Self, Rnd(1.0,5.0), Magnet.X + (Sin(Rnd(360.0)) * 5.0), Magnet.Y + (Cos(Rnd(360.0)) * 5.0))
  525. ThisStar.SetVelocityFromAngle(Rnd(360),Rnd(1.0,5.0))
  526. Self.Stars.AddLast(ThisStar)
  527. Magnet.Stars :+ 1
  528. Next
  529. If Magnet.Stars > 500 Then
  530. Self.World.Magnets.Remove(Magnet)
  531. EndIf
  532. Next
  533. ' Update the scoller
  534. Self.ScrollPoint :- 0.5
  535. If Self.Scrollpoint < -((TEXTS_COUNT * 25) + 100)
  536. Self.ScrollPoint = HEIGHT + 20
  537. EndIf
  538. End Method
  539. '#End Region
  540. '#Region Method: Render
  541. Method Render()
  542. Cls
  543. Self.Stars.Draw()
  544. SetColor 255,255,255
  545. For Local Count:Int = 0 To TEXTS_COUNT - 1
  546. MainMenuScene.DrawTextCentered(Self.Texts[Count],Self.ScrollPoint + (25 * Count))
  547. Next
  548. End Method
  549. '#End Region
  550. '#Region Method: Start
  551. Method Start()
  552. Self.MusicChannel = AllocChannel()
  553. If Self.Music = Null Then Self.Music = LoadSound("sounds\ending.ogg",True)
  554. If Self.MusicChannel <> Null
  555. PlaySound(Self.Music,Self.MusicChannel)
  556. EndIf
  557. Self.Texts[0] = "Cast of Characters"
  558. Self.Texts[1] = "------------------"
  559. Self.Texts[2] = ""
  560. Self.Texts[3] = "Space Craft.......................Intrepid"
  561. Self.Texts[4] = "Digestive...............Sweet Meal Biscuit"
  562. Self.Texts[5] = "Star...............................Himself"
  563. Self.Texts[6] = ""
  564. Self.Texts[7] = "Written by Rob Hutchinson in roughly 5 days."
  565. Self.Texts[8] = "Email: [email protected]"
  566. Self.Texts[9] = "Web: http://www.proteanide.co.uk/"
  567. Self.Texts[10] = ""
  568. Self.Texts[11] = "Special Thanks To"
  569. Self.Texts[12] = "-----------------"
  570. Self.Texts[13] = "Richard Makepeace.............Inspiration"
  571. Self.Texts[14] = "James Readman.................Inspiration"
  572. Self.Texts[15] = ""
  573. Self.Texts[16] = "Greets"
  574. Self.Texts[17] = "------"
  575. Self.Texts[18] = "Pickup, Cabsy, Peters, ZanaX, Compona, Helen, + all other family and friends."
  576. Self.Texts[19] = ""
  577. Self.Texts[20] = ""
  578. Self.Texts[21] = ""
  579. Self.Texts[22] = "Thank you for playing."
  580. Self.ScrollPoint = HEIGHT + 20
  581. End Method
  582. '#End Region
  583. '#Region Method: Finish
  584. Method Finish()
  585. Self.Stars.Clear()
  586. If Self.MusicChannel <> Null Then
  587. Self.MusicChannel.Stop()
  588. Self.MusicChannel = Null
  589. EndIf
  590. End Method
  591. '#End Region
  592. End Type
  593. '#End Region
  594. Type TCircle
  595. Field X:Int
  596. Field Y:Int
  597. Field Radius:Float
  598. Method CollidesWith:Int(Circle:TCircle)
  599. Local Distance:Double = TPhysicsUtility.DistanceBetweenPoints(Self.X,Self.Y,Circle.X,Circle.Y)
  600. If Distance < (Self.Radius + Circle.Radius) Then Return True
  601. Return False
  602. End Method
  603. Method Draw()
  604. SetBlend(ALPHABLEND)
  605. SetAlpha(0.5)
  606. SetRotation 0
  607. DrawCircle(X,Y,Int(Radius))
  608. End Method
  609. Function DrawCircle(X,Y,Radius)
  610. DrawOval(X - Radius,Y - Radius,Radius * 2,Radius * 2)
  611. End Function
  612. End Type
  613. Type TDigestive Extends TPhysicsProvider
  614. Field Image:TImage
  615. Field Alpha:Float = 1.0
  616. Field Rotation:Float = 0
  617. Field Scale:Float = 1.0
  618. Field Circle:TCircle = New TCircle
  619. Field GameScene:MainGameScene
  620. Const InitialRadius:Float = 70.0
  621. Field HitSound:TSound
  622. Method SplitIntoChunks(X:Int,Y:Int,Multiplier:Float)
  623. GameScene.Digestives.Remove(Self)
  624. Local Channel:TChannel = AllocChannel()
  625. If Channel <> Null
  626. Channel.SetVolume(Self.Scale)
  627. PlaySound(Self.HitSound, Channel)
  628. EndIf
  629. Self.GameScene.Chunks.X = X
  630. Self.GameScene.Chunks.Y = Y
  631. Self.GameScene.Player.Score :+ Int(((Self.Scale * 100.0) + 4.0) * Multiplier)
  632. Self.GameScene.Shake :+ (Self.Scale * 3.5)
  633. If Self.Scale > 0.2
  634. For Local Count:Int = 0 To Int(Self.Scale * 5)
  635. Local Digestive:TDigestive = TDigestive.Create(Self.World, Self.Image, Self.GameScene)
  636. Digestive.X = Self.X
  637. Digestive.Y = Self.Y
  638. Digestive.Rotation = Rnd(360)
  639. Digestive.Weight = 5
  640. Digestive.SetVelocityFromAngle(Rnd(360.0),Rnd(0.5,1.5))
  641. Digestive.SetDrawScale(Self.Scale / 2)
  642. Digestive.HitSound = Self.HitSound
  643. GameScene.Digestives.AddLast(Digestive)
  644. Next
  645. For Local ChunkCount:Int = 0 To 4 * (Self.Scale * 10)
  646. Local Particle:TStaticParticle = Self.GameScene.Chunks.AddStaticParticle(Self.GameScene.ChunkImages[(Int(Rnd(0,MainGameScene.CHUNK_COUNT)))], Rnd(360.0), Rnd(0.5,10.0), 0, 0.01, [255,255,255])
  647. Particle.Friction = 0.97
  648. Particle.Size = Rnd(0.5,1.0)
  649. Particle.Rotation = Rnd(-5.0,5.0)
  650. Next
  651. Else
  652. For Local ChunkCount2:Int = 0 To Rnd(3,8)
  653. Local Particle:TStaticParticle = Self.GameScene.Chunks.AddStaticParticle(Self.GameScene.ChunkImages[(Int(Rnd(0,MainGameScene.CHUNK_COUNT)))], Rnd(360.0), Rnd(0.5,10.0), 0, 0.01, [255,255,255])
  654. Particle.Friction = 0.97
  655. Particle.Size = Rnd(0.2,0.5)
  656. Particle.Rotation = Rnd(-5.0,5.0)
  657. Next
  658. End If
  659. End Method
  660. Method Draw()
  661. SetAlpha Self.ALPHA
  662. SetRotation Self.Rotation
  663. SetScale Self.Scale,Self.Scale
  664. DrawImage(Self.Image, Self.X, Self.Y)
  665. SetScale 1,1
  666. End Method
  667. Method SetDrawScale(Scale:Float)
  668. Self.Scale = Scale
  669. Self.Circle.Radius = Self.InitialRadius * Self.Scale
  670. End Method
  671. Method PhysicsApplied()
  672. Rotation:+2
  673. Local HalfWidth:Int = ((Image.Width * Self.Scale) / 2)
  674. Local HalfHeight:Int = ((Image.Height * Self.Scale) / 2)
  675. If X < -HalfWidth Then X = WIDTH + HalfWidth
  676. If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
  677. If X > WIDTH + HalfWidth Then X = -HalfWidth
  678. If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
  679. Self.Circle.X = Self.X
  680. Self.Circle.Y = Self.Y
  681. End Method
  682. Function Create:TDigestive(World:TWorldPhysicsProvider,Image:TImage,GameScene:MainGameScene)
  683. Local Out:TDigestive = New TDigestive
  684. Out.GameScene = GameScene
  685. Out.Circle.Radius = InitialRadius
  686. Out.World = World
  687. Out.Image = Image
  688. Return Out
  689. End Function
  690. End Type
  691. Type TPlayer Extends TPhysicsProvider
  692. Field Lives:Int
  693. Field Score:Int
  694. Field Weapon:TWeapon
  695. Field Dead:Int = True
  696. Field Teleports:Int = 2
  697. Field Image:TImage
  698. Field Rotation:Float
  699. Field Acceleration:Float
  700. Field MaxAcceleration:Float = 4.0
  701. Field Motion:Float = 0.001
  702. Field AccelerationDropMultiplier:Float = 8
  703. Field Circle:TCircle = New TCircle
  704. Field GameScene:MainGameScene
  705. Field FireRateCount:Float = 0
  706. Field Thruster:TFountain
  707. Field Death:TFountain
  708. Field ThrusterImage:TImage
  709. Field DeathImage:TImage
  710. Field SparkleImage:TImage
  711. Field ThrusterSound:TSound
  712. Field CrashSound:TSound
  713. Field ThrusterChannel:TChannel
  714. Field TeleportSound:TSound
  715. Method Draw()
  716. SetTransform
  717. ' Render the thruster...
  718. SetBlend LIGHTBLEND
  719. SetScale 0.6, 0.6
  720. SetAlpha 1.0
  721. Self.Thruster.Draw()
  722. Self.Death.Draw()
  723. If Not Self.Dead Then
  724. ' Render the player.
  725. SetBlend ALPHABLEND
  726. SetAlpha 1.0
  727. SetScale 1.0,1.0
  728. SetColor 255,255,255
  729. SetRotation 360 - Self.Rotation
  730. DrawImage(Self.Image, Self.X, Self.Y)
  731. EndIf
  732. End Method
  733. Method PhysicsApplied()
  734. Local HalfWidth:Int = (Image.Width / 2)
  735. Local HalfHeight:Int = (Image.Height / 2)
  736. If X < -HalfWidth Then X = WIDTH + HalfWidth
  737. If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
  738. If X > WIDTH + HalfWidth Then X = -HalfWidth
  739. If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
  740. Self.Circle.X = Self.X
  741. Self.Circle.Y = Self.Y
  742. End Method
  743. Method Update()
  744. ' Update thruster and death particles.
  745. Local Particle:TStaticParticle = Self.Thruster.AddStaticParticle(Self.ThrusterImage, Self.Rotation + 180 + Rnd(-5.0,5.0), 1.0, 1, 0.04, [255,255,255])
  746. Local ActualRotation:Float = Self.Rotation + 180
  747. Self.Thruster.X = Self.X + (Sin(ActualRotation) * 10)
  748. Self.Thruster.Y = Self.Y + (Cos(ActualRotation) * 10)
  749. Local ThisSpeed:Float = Self.Speed()
  750. If ThisSpeed < 0 Then ThisSpeed = 0
  751. If ThisSpeed > 10.0 Then ThisSpeed = 10.0
  752. ' Add particles to the thruster..
  753. Particle.Size = (ThisSpeed / 10)
  754. Self.ThrusterChannel.SetVolume(ThisSpeed / 10)
  755. Self.ThrusterChannel.SetPan(Float(Self.X / Float(WIDTH / 2.0) - 1.0))
  756. Self.GameScene.Shake:+ 0.10 * (ThisSpeed / 10.0)
  757. Self.Thruster.Update()
  758. Self.Death.UpdateWithFriction(TPhysicsProvider.AxisX | TPhysicsProvider.AxisY)
  759. If Self.Dead
  760. ' Player is currently dead, wait for a nice chance to put them back down.
  761. If Self.Lives < 1 Then
  762. ' Wait for the death particles to become zeroed.
  763. If Self.Death.Particles.IsEmpty() Then
  764. Self.GameScene.TerminateMainLoop = True
  765. EndIf
  766. Else
  767. ' Check to see if the center spot is safe to plop the ship on.
  768. If Self.GameScene.IsLocationSafe(WIDTH/2, HEIGHT/2, 70)
  769. Self.Dead = False
  770. For Local Pops:Int = 0 To 200
  771. Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,2.0), 0, Rnd(0.01, 0.03), [255,255,255])
  772. Particle.X = Self.X
  773. Particle.Y = Self.Y
  774. Particle.Rotation = Rnd(-1.0,1.0)
  775. Particle.Friction = 0.97
  776. Particle.Size = Rnd(0.1,0.2)
  777. Next
  778. EndIf
  779. EndIf
  780. Else
  781. ' Update fire rate counter...
  782. Self.FireRateCount :- 1
  783. If KeyDown(KEY_UP)
  784. ' Thrust
  785. Self.Acceleration :+ Self.Motion
  786. ' Clamp the acceleration
  787. If Self.Acceleration > Self.MaxAcceleration Then Self.Acceleration = Self.MaxAcceleration
  788. ' Add acceleration.
  789. Self.IncreaseVelocityFromAngle(Self.Rotation,Self.Acceleration)
  790. Else
  791. Self.Acceleration :- (Self.Motion * Self.AccelerationDropMultiplier)
  792. If Self.Acceleration < 0.0 Then Self.Acceleration = 0
  793. EndIf
  794. If KeyDown(KEY_LEFT)
  795. ' RotateLeft
  796. Self.Rotation :+ 3
  797. EndIf
  798. If KeyDown(KEY_RIGHT)
  799. ' RotateLeft
  800. Self.Rotation :- 3
  801. EndIf
  802. If KeyDown(KEY_SPACE)
  803. ' FIRE!
  804. If Self.FireRateCount <= 0 Then
  805. Self.FireRateCount = Self.Weapon.FireRate
  806. Self.Weapon.Fire(Self)
  807. End If
  808. EndIf
  809. If KeyHit(KEY_DOWN)
  810. ' TELEPORT
  811. If Self.Teleports > 0 Then
  812. Self.Teleports :- 1
  813. Local Location:TPointD = Self.GameScene.FindSafeLocation(20)
  814. PlaySound(Self.TeleportSound)
  815. Self.Death.X = Self.X
  816. Self.Death.Y = Self.Y
  817. For Local Pops:Int = 0 To 50
  818. Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,10.0), 0, 0.02, [255,255,255])
  819. Particle.X = Self.X
  820. Particle.Y = Self.Y
  821. Particle.Rotation = Rnd(-1.0,1.0)
  822. Particle.Friction = 0.97
  823. Particle.Size = Rnd(0.1,0.2)
  824. Next
  825. Self.X = Int(Location.X)
  826. Self.Y = Int(Location.Y)
  827. Self.Death.X = Self.X
  828. Self.Death.Y = Self.Y
  829. For Local Pops:Int = 0 To 20
  830. Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.SparkleImage, Rnd(360.0), Rnd(0.5,2.0), 0, 0.02, [255,255,255])
  831. Particle.X = Self.X
  832. Particle.Y = Self.Y
  833. Particle.Rotation = Rnd(-1.0,1.0)
  834. Particle.Friction = 0.97
  835. Particle.Size = Rnd(0.1,0.2)
  836. Next
  837. EndIf
  838. EndIf
  839. ' COLLISION DETECT AGAINST DIGESTIVES!
  840. ' ---------------------------------------------------------
  841. For Local Item:TDigestive = EachIn Self.GameScene.Digestives
  842. If Item.Circle.CollidesWith(Self.Circle)
  843. Self.Lives :- 1
  844. Self.Dead = True
  845. PlaySound(Self.CrashSound)
  846. Local PlayerSpeed:Double = Self.Speed()
  847. Self.GameScene.Shake :+ PlayerSpeed / 1.5
  848. If PlayerSpeed > 10.0
  849. Item.SplitIntoChunks(Self.X,Self.Y,Self.Speed())
  850. EndIf
  851. Self.Death.X = Self.X
  852. Self.Death.Y = Self.Y
  853. For Local Pops:Int = 0 To 100
  854. If PlayerSpeed > 10 Then PlayerSpeed = 10
  855. Local Angle:Double = Self.Angle() + Rnd(-(80 - (8.0 * PlayerSpeed)), 80 - (8.0 * PlayerSpeed))
  856. Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.DeathImage, Angle, Rnd(0.1, Self.Speed()), 0, 0.03, [255,255,255])
  857. Particle.Friction = 0.98
  858. Particle.Size = Rnd(0.1,0.7)
  859. Particle.Color = [Rand(80,255),24,Rand(24,128)]
  860. Next
  861. For Local Pops:Int = 0 To 300
  862. Local Particle:TStaticParticle = Self.Death.AddStaticParticle(Self.DeathImage, Rnd(360.0), Rnd(0.1, 7.0), 0, Rnd(0.01,0.04), [255,255,255])
  863. Particle.Friction = 0.99
  864. Particle.Size = Rnd(0.1,0.4)
  865. Particle.Color = [Rand(80,255),24,Rand(24,200)]
  866. Next
  867. Self.Reset()
  868. EndIf
  869. Next
  870. EndIf
  871. End Method
  872. Method Reset()
  873. Self.X = WIDTH / 2
  874. Self.Y = HEIGHT / 2
  875. Self.Acceleration = 0
  876. Self.VelocityX = 0
  877. Self.VelocityY = 0
  878. Self.Teleports = 2
  879. Self.Dead = 2
  880. End Method
  881. Method LoadAssets()
  882. If Self.ThrusterImage = Null Then Self.ThrusterImage = LoadImage("graphics\bullet1.png")
  883. If Self.DeathImage = Null Then Self.DeathImage = LoadImage("graphics\pop.png")
  884. If Self.SparkleImage = Null Then Self.SparkleImage = LoadImage("graphics\sparkle.png")
  885. ' Load in the sounds...
  886. If Self.ThrusterSound = Null Then Self.ThrusterSound = LoadSound("sounds\thrust.wav",True)
  887. If Self.CrashSound = Null Then Self.CrashSound = LoadSound("sounds\crash.wav",False)
  888. If Self.TeleportSound = Null Then Self.TeleportSound = LoadSound("sounds\teleport.wav",False)
  889. Self.ThrusterChannel = AllocChannel()
  890. Self.ThrusterChannel.SetVolume(0)
  891. PlaySound(Self.ThrusterSound,Self.ThrusterChannel)
  892. End Method
  893. Function Create:TPlayer(World:TWorldPhysicsProvider, Image:TImage, GameScene:MainGameScene)
  894. Local Out:TPlayer = New TPlayer
  895. Out.Thruster = TFountain.Create(World, TRectangle.Create(0,0,WIDTH,HEIGHT))
  896. Out.Death = TFountain.Create(World, TRectangle.Create(0,0,WIDTH,HEIGHT))
  897. Out.GameScene = GameScene
  898. Out.Circle.Radius = 10
  899. Out.World = World
  900. Out.Image = Image
  901. Out.Friction = 0.985
  902. Out.Reset()
  903. Return Out
  904. End Function
  905. End Type
  906. Type TBullet Extends TPhysicsProvider
  907. Field Image:TImage
  908. Field Circle:TCircle = New TCircle
  909. Field GameScene:MainGameScene
  910. Field Size:Float = 1.0
  911. Field ScoreMultiplier:Float = 1
  912. Field TTL:Int
  913. Field Fading:Float = 1.0
  914. Const TIME_TO_LIVE = 100
  915. Method Draw()
  916. SetScale(Self.Size,Self.Size)
  917. SetAlpha(Self.Fading)
  918. DrawImage(Self.Image, Self.X, Self.Y)
  919. End Method
  920. Method PhysicsApplied()
  921. Local HalfWidth:Int = (Image.Width / 2)
  922. Local HalfHeight:Int = (Image.Height / 2)
  923. If X < -HalfWidth Then X = WIDTH + HalfWidth
  924. If Y < -HalfHeight Then Y = HEIGHT + HalfHeight
  925. If X > WIDTH + HalfWidth Then X = -HalfWidth
  926. If Y > HEIGHT + HalfHeight Then Y = -HalfHeight
  927. ' Shall we kill it off?
  928. Self.TTL :+ 1
  929. If Self.TTL > TIME_TO_LIVE Then
  930. Self.Fading :- 0.015
  931. If Self.Fading < 0.05
  932. Self.GameScene.Bullets.Remove(Self)
  933. EndIf
  934. EndIf
  935. ' If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then
  936. ' ' Bullet went off't screen
  937. ' Self.GameScene.Bullets.Remove(Self)
  938. ' EndIf
  939. Self.Circle.X = Self.X
  940. Self.Circle.Y = Self.Y
  941. ' COLLISION DETECT AGAINST DIGESTIVES!
  942. ' ---------------------------------------------------------
  943. For Local Item:TDigestive = EachIn Self.GameScene.Digestives
  944. If Item.Circle.CollidesWith(Self.Circle)
  945. If Self.Fading > 0.5
  946. Self.GameScene.Bullets.Remove(Self)
  947. Item.SplitIntoChunks(Self.Circle.X,Self.Circle.Y,Self.ScoreMultiplier)
  948. Exit
  949. EndIf
  950. EndIf
  951. Next
  952. End Method
  953. Function Create:TBullet(World:TWorldPhysicsProvider, Image:TImage, Player:TPlayer, Speed:Float, GameScene:MainGameScene, Size:Float, Radius:Float, Veer:Float)
  954. Local Out:TBullet = New TBullet
  955. Out.GameScene = GameScene
  956. Out.SetVelocityFromAngle(Player.Rotation + Rnd(-Veer,Veer),Speed)
  957. Out.Size = Size
  958. Out.Circle.Radius = Radius * Size
  959. Out.X = Player.X
  960. Out.Y = Player.Y
  961. Out.World = World
  962. Out.Image = Image
  963. Return Out
  964. End Function
  965. End Type
  966. Type TStar Extends TPhysicsProvider
  967. Field Color[]
  968. Field GameScene:MainGameScene
  969. Method Draw()
  970. SetColor Self.Color[0],Self.Color[1],Self.Color[2]
  971. DrawRect(X,Y,1,1)
  972. End Method
  973. Method PhysicsApplied()
  974. Self.VelocityX :* 1.01
  975. Self.VelocityY :* 1.01
  976. Local HalfWidth:Int = 5
  977. Local HalfHeight:Int = 5
  978. If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then
  979. ' Bullet went off't screen
  980. Self.GameScene.Stars.Remove(Self)
  981. EndIf
  982. End Method
  983. Function Create:TStar(World:TWorldPhysicsProvider,GameScene:MainGameScene, Speed:Float)
  984. Local Out:TStar = New TStar
  985. Local Pigment = Rand(24,255)
  986. Out.GameScene = GameScene
  987. Out.Color = [Pigment,Pigment,Pigment]
  988. Out.SetVelocityFromAngle(Rnd(360),Rnd(0.2,0.9) * Speed)
  989. Out.X = WIDTH / 2
  990. Out.Y = HEIGHT / 2
  991. Out.World = World
  992. Return Out
  993. End Function
  994. End Type
  995. Type TMenuStar Extends TPhysicsProvider
  996. Field Color[]
  997. Field MenuScene:MainMenuScene
  998. Method Draw()
  999. SetColor Self.Color[0],Self.Color[1],Self.Color[2]
  1000. DrawRect(X,Y,1,1)
  1001. End Method
  1002. Method PhysicsApplied()
  1003. ' Self.VelocityX :* 1.01
  1004. ' Self.VelocityY :* 1.01
  1005. Local HalfWidth:Int = 5
  1006. Local HalfHeight:Int = 5
  1007. If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then
  1008. ' Bullet went off't screen
  1009. Self.MenuScene.Stars.Remove(Self)
  1010. EndIf
  1011. End Method
  1012. Function Create:TMenuStar(World:TWorldPhysicsProvider,MenuScene:MainMenuScene, Speed:Float)
  1013. Local Out:TMenuStar = New TMenuStar
  1014. Local Pigment = Rand(24,255)
  1015. Out.MenuScene = MenuScene
  1016. Out.Color = [Pigment,Pigment,Pigment]
  1017. Out.SetVelocityFromAngle(90,Rnd(0.2,0.9) * Speed)
  1018. Out.X = 0
  1019. Out.Y = Rnd(HEIGHT)
  1020. Out.World = World
  1021. Return Out
  1022. End Function
  1023. End Type
  1024. Type TEndingStar Extends TPhysicsProvider
  1025. Field Color[]
  1026. Field EndScene:EndingScene
  1027. Method Draw()
  1028. SetColor Self.Color[0],Self.Color[1],Self.Color[2]
  1029. DrawRect(X,Y,1,1)
  1030. End Method
  1031. Method PhysicsApplied()
  1032. ' Self.VelocityX :* 1.01
  1033. ' Self.VelocityY :* 1.01
  1034. Local HalfWidth:Int = 5
  1035. Local HalfHeight:Int = 5
  1036. If X < -HalfWidth Or Y < -HalfHeight Or X > WIDTH + HalfWidth Or Y > HEIGHT + HalfHeight Then
  1037. ' Bullet went off't screen
  1038. Self.EndScene.Stars.Remove(Self)
  1039. EndIf
  1040. End Method
  1041. Function Create:TEndingStar(World:TWorldPhysicsProvider, EndScene:EndingScene, Speed:Float, X:Int, Y:Int)
  1042. Local Out:TEndingStar = New TEndingStar
  1043. Local Pigment = Rand(24,255)
  1044. Out.EndScene = EndScene
  1045. Out.Color = [Pigment,Pigment,Pigment]
  1046. Out.X = X
  1047. Out.Y = Y
  1048. Out.World = World
  1049. Return Out
  1050. End Function
  1051. End Type
  1052. Type TPickup Extends TLink
  1053. Const MODIFIER_SCORE = 0
  1054. Const MODIFIER_LIVES = 1
  1055. Const MODIFIER_ROTATION = 2
  1056. Const MODIFIER_PSYCHODELIC = 3
  1057. Const MODIFIER_WEAPON = 4
  1058. Field Modifies:Int = MODIFIER_SCORE
  1059. Field ByValue:Float
  1060. Field LastsFor:Int
  1061. Field Time:Int
  1062. Field IsPermanent:Int = False
  1063. Field Weapon:TWeapon
  1064. Field Icon:TImage
  1065. Field Probability:Double
  1066. Field OwnedIcon:TImage
  1067. Method Clone:TPickup()
  1068. Local Out:TPickup = New TPickup
  1069. Out.Modifies = Self.Modifies
  1070. Out.ByValue = Self.ByValue
  1071. Out.LastsFor = Self.LastsFor
  1072. Out.IsPermanent = Self.IsPermanent
  1073. Out.Weapon = Self.Weapon
  1074. Out.Icon = Self.Icon
  1075. Out.Probability = Self.Probability
  1076. Out.OwnedIcon = Out.OwnedIcon
  1077. Return Out
  1078. End Method
  1079. Function Create:TPickup(Modifies:Int,ByValue:Float,LastsFor:Int,IsPermanent:Int,Weapon:TWeapon,Icon:TImage,Probability:Double,OwnedIcon:TImage)
  1080. Local Out:TPickup = New TPickup
  1081. Out.Modifies = Modifies
  1082. Out.ByValue = ByValue
  1083. Out.LastsFor = LastsFor
  1084. Out.IsPermanent = IsPermanent
  1085. Out.Weapon = Weapon
  1086. Out.Icon = Icon
  1087. Out.Probability = Probability
  1088. Out.OwnedIcon = OwnedIcon
  1089. Return Out
  1090. End Function
  1091. End Type
  1092. Type TWeapon Extends TLink
  1093. Field Speed:Float
  1094. Field Graphic:TImage
  1095. Field Size:Float
  1096. Field Radius:Float
  1097. Field Veer:Float
  1098. Field FireRate:Int
  1099. Field MainGame:MainGameScene
  1100. Field Sound:TSound
  1101. Field Name:String
  1102. Field Icon:TImage
  1103. Method Fire(Player:TPlayer)
  1104. Local Shot:TBullet = TBullet.Create(MainGame.World, Self.Graphic, Player, Self.Speed + Player.Speed(), Self.MainGame, Self.Size, Self.Radius, Self.Veer)
  1105. Shot.ScoreMultiplier = (Player.Speed() * 4.0)
  1106. If Shot.ScoreMultiplier < 1.0 Then Shot.ScoreMultiplier = 1.0
  1107. Self.MainGame.Bullets.AddLast(Shot)
  1108. PlaySound(Self.Sound)
  1109. End Method
  1110. Function Create:TWeapon(Speed:Float,Graphic:TImage,Size:Float,Radius:Float,Veer:Float,FireRate:Int,MainGame:MainGameScene,Sound:TSound,Icon:TImage,Name:String)
  1111. Local Out:TWeapon = New TWeapon
  1112. Out.Speed = Speed
  1113. Out.Graphic = Graphic
  1114. Out.Size = Size
  1115. Out.Radius = Radius
  1116. Out.Veer = Veer
  1117. Out.FireRate = FireRate
  1118. Out.MainGame = MainGame
  1119. Out.Sound = Sound
  1120. Out.Icon = Icon
  1121. Out.Name = Name
  1122. Return Out
  1123. End Function
  1124. End Type
  1125. Type TEndMagnet Extends TMagnet
  1126. Field Stars:Int
  1127. End Type
  1128. Type THighScores
  1129. Const SCORE_COUNT = 10
  1130. Field Scores:Int[SCORE_COUNT]
  1131. Field Names:String[SCORE_COUNT]
  1132. Method Render(X:Int, Y:Int)
  1133. For Local Count:Int = 0 To SCORE_COUNT - 1
  1134. DrawText(Self.Names[Count], X,Y + (Count * 20))
  1135. Next
  1136. For Local Count2:Int = 0 To SCORE_COUNT - 1
  1137. DrawText(Self.Scores[Count2], X + 200,Y + (Count2 * 20))
  1138. Next
  1139. End Method
  1140. Method IsHighScore:Int(Score:Int)
  1141. For Local Count:Int = 0 To SCORE_COUNT - 1
  1142. If Score > Self.Scores[Count] Then
  1143. Return True
  1144. EndIf
  1145. Next
  1146. Return False
  1147. End Method
  1148. Method Add(Score:Int,Name:String)
  1149. ' Find out where we should put the score..
  1150. Local PlaceAt:Int = SCORE_COUNT - 1
  1151. For Local Count:Int = SCORE_COUNT - 1 To 0 Step -1
  1152. If Score > Self.Scores[Count] Then
  1153. PlaceAt = Count
  1154. EndIf
  1155. Next
  1156. ' Shuffle them all down..
  1157. For Local Shuffle:Int = SCORE_COUNT - 2 To PlaceAt Step -1
  1158. Self.Scores[Shuffle + 1] = Self.Scores[Shuffle]
  1159. Self.Names[Shuffle + 1] = Self.Names[Shuffle]
  1160. Next
  1161. Self.Scores[PlaceAt] = Score
  1162. Self.Names[PlaceAt] = Name
  1163. End Method
  1164. Method Save(File:String)
  1165. Local Out:TStream = OpenStream(File,False,True)
  1166. If Out <> Null
  1167. For Local Count:Int = 0 To SCORE_COUNT - 1
  1168. WriteInt(Out,Self.Scores[Count])
  1169. WriteLine(Out,Self.Names[Count])
  1170. Next
  1171. CloseStream(Out)
  1172. EndIf
  1173. End Method
  1174. Function Load:THighScores(File:String)
  1175. Local In:TStream = OpenStream(File,True,False)
  1176. Local Out:THighScores = New THighScores
  1177. If In = Null
  1178. ' Fill it full of high scores..
  1179. Out.Names[0] = "Loki"
  1180. Out.Names[1] = "Booty"
  1181. Out.Names[2] = "Rix"
  1182. Out.Names[3] = "Jamez"
  1183. Out.Names[4] = "Pies"
  1184. Out.Names[5] = "Bobny"
  1185. Out.Names[6] = "Berty"
  1186. Out.Names[7] = "Billy"
  1187. Out.Names[8] = "Bonny"
  1188. Out.Names[9] = "Boxer"
  1189. Out.Scores[0] = 100000
  1190. Out.Scores[1] = 80000
  1191. Out.Scores[2] = 50000
  1192. Out.Scores[3] = 40000
  1193. Out.Scores[4] = 30000
  1194. Out.Scores[5] = 20000
  1195. Out.Scores[6] = 10000
  1196. Out.Scores[7] = 5000
  1197. Out.Scores[8] = 4000
  1198. Out.Scores[9] = 1000
  1199. Else
  1200. For Local Count:Int = 0 To SCORE_COUNT - 1
  1201. Out.Scores[Count] = ReadInt(In)
  1202. Out.Names[Count] = ReadLine(In)
  1203. Next
  1204. CloseStream(In)
  1205. EndIf
  1206. Return Out
  1207. End Function
  1208. End Type
  1209. ' Main game setup.
  1210. ' ------------------------
  1211. Local Game:T2DDynamicGame = T2DDynamicGame.Create(WIDTH, HEIGHT, DEPTH, REFRESHRATE)
  1212. Global Scores:THighScores = THighScores.Load("hi.dat")
  1213. Game.DynamicTiming = DYNAMICTIMING
  1214. Game.DesiredFPS = DESIREDFPS
  1215. Game.Initialize() ' Go into graphics mode.
  1216. HideMouse
  1217. ' Create the main game scene.
  1218. Local MenuScene:MainMenuScene = New MainMenuScene
  1219. Local GameScene:MainGameScene = New MainGameScene
  1220. Local EndScene:EndingScene = New EndingScene
  1221. Local QuitFlag:Int = False
  1222. While Not QuitFlag
  1223. ' Attach The Game Scene To The Dynamic Game.
  1224. Game.Setscene(Menuscene)
  1225. ' Start The Main Loop.
  1226. Game.Mainloop()
  1227. If Not MenuScene.Exitgame
  1228. If MenuScene.ShowCredits
  1229. MenuScene.ShowCredits = False
  1230. Game.SetScene(EndScene)
  1231. Game.Mainloop()
  1232. Else
  1233. Game.Setscene(GameScene)
  1234. Game.Mainloop()
  1235. QFlushKeys()
  1236. If GameScene.Completed
  1237. GameScene.Completed = False
  1238. Game.SetScene(EndScene)
  1239. Game.Mainloop()
  1240. EndIf
  1241. QFlushKeys()
  1242. ' Check for high score.
  1243. If Scores.IsHighScore(GameScene.Player.Score) Then
  1244. ' We got a high score.
  1245. MenuScene.ViewMenu(MenuScene.VIEW_ENTERHIGH)
  1246. MenuScene.LastHighScore = GameScene.Player.Score
  1247. MenuScene.EnteredText = ""
  1248. EndIf
  1249. EndIf
  1250. Else
  1251. QuitFlag = True
  1252. EndIf
  1253. Wend
  1254. Scores.Save("hi.dat")
  1255. ' Clean up after we shut down.
  1256. Game.ShutDown()
  1257. ' Fin
  1258. Const DEBUG = True
  1259. Function DebugLog(Text:String)
  1260. If DEBUG Then Print Text
  1261. End Function