May 21, 2018, 06:22:20 AM

Author Topic: FUNGICIDE - Retro Game Competition Entry  (Read 688 times)

Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
FUNGICIDE - Retro Game Competition Entry
« on: January 19, 2018, 11:40:38 PM »
FUNGICIDE
The Earth has been infected by Alien Spores!
They arrive on Meteors from infected Asteroids and grow into Giant Fungus!
Your mission is to destroy them before they take over the planet!

Controls:
MovementCursor Keys (Up, Down, Left, Right)
Main WeaponSpace
BombZ
Quit or PauseEscape
ScreenshotF12

Game available for Windows and Linux.

I have not documented the dependencies for Linux, but it should run on your system if you already use BlitzMax.

Please post a screenshot of your high score table. I'd like to see how far you guys get :)
Follow me at ITSpeedway.net.

Offline Conjured Entertainment

  • Jr. Member
  • **
  • Posts: 81
    • Conjured Entertainment
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #1 on: January 20, 2018, 03:00:29 AM »

Please post a screenshot of your high score table. I'd like to see how far you guys get :)

You got it...

Very retro and fun to play.

I really like this game.


Online iWasAdam

  • Hero Member
  • *****
  • Posts: 521
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #2 on: January 20, 2018, 08:20:36 AM »
I've got my alien spore hat on now...

Offline therevills

  • Sr. Member
  • ****
  • Posts: 289
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #3 on: January 21, 2018, 04:22:55 AM »
For some reason the ship moves very slowly up and down - was this on purpose?

Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #4 on: January 21, 2018, 11:14:00 AM »
Very retro and fun to play.
I really like this game.

Thanks. Always good to hear that.

For some reason the ship moves very slowly up and down - was this on purpose?

Yeah, I slowed it down because it was starting to cause problems hitting the ground all the time. Maybe I overdid it a little.


Follow me at ITSpeedway.net.

Offline Steve Elliott

  • Hero Member
  • *****
  • Posts: 993
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #5 on: January 21, 2018, 11:14:48 AM »
Yes it's far too slow - quick change the speed before anybody else notices ;D
Windows 10, 64-bit, 8Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 750 Ti (2Gb)

Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #6 on: January 21, 2018, 11:24:19 AM »
Yes it's far too slow - quick change the speed before anybody else notices ;D

On a plus note. You can't hit the ground so easily.  Lol
Follow me at ITSpeedway.net.

Offline GaborD

  • Full Member
  • ***
  • Posts: 106
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #7 on: January 22, 2018, 05:19:05 AM »
 ;D

Offline RemiD

  • Hero Member
  • *****
  • Posts: 582
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #8 on: January 22, 2018, 09:04:34 PM »
I have just tested your game.

It works well on my computer/os (Windows 7 64bits)

Graphics : nice, consistant style. And it looks good even when scaled (not like my game :-p)
Sounds : cool effects , thanks for the option to configure the volume
Controls : easy enough to understand how to play
Gameplay : original world/enemies, shoot and hit, fun and addicitive, however instead of moving toward left or moving toward right, i would have added a way to move the ship more quickly or less quickly to be able to avoid the "spores"

Offline Conjured Entertainment

  • Jr. Member
  • **
  • Posts: 81
    • Conjured Entertainment
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #9 on: January 23, 2018, 01:07:45 AM »
Okay guys, where are the high score images?  :o

There are so many great games in this competition, and my top 3 were very close and almost equal favorites.

The thing that set this apart for me from most of the other games (including mine) was the length of play.

While my game and others had a set number of levels for a limited time of play, this one ends based on skill and increasing difficulty.
 
Most retro games had limited time to play with fixed ends to the game after the first batch of arcade machines, once the operators realized that allowing a player to marathon play on Asteroids or Pac-Man for hours on one quarter did not result in very much revenue for the arcade.

Then came games like Pole Position that had a fixed number of laps for a quick but exciting game, and it became the highest grossing arcade machine for the year it was released, so operators looked for games that offered fixed play.

Games like mine, or Get to Da Chopper, have a fixed number of levels for quick play and a decisive end, but Fungicide uses increasing difficulty to make the game play short lived, especially for noobs honing their Fungicide skills.

I get to the end of the other games, like mine, and feel a level of accomplishment for 'beating the game', but games like Fungicide give me that feeling every time I beat my personal best score, because increasing my skills can keep extending the game time.

Also, the fixed number of digits for the score is classic, because you want to make it to 100,000 and get rid of that leading zero, but that seems to be nearly impossible with the increase in spore population in later waves.

This game keeps me wanting to go back and do more damage, and fight my way to that 100k.

Classic, Epic, and tons of Retro fun!

Despite the few bugs in the game restarts, this one is my favorite, and now you know why.




Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #10 on: January 23, 2018, 06:11:27 AM »
Graphics : nice, consistant style. And it looks good even when scaled (not like my game :-p)
Sounds : cool effects , thanks for the option to configure the volume Controls : easy enough to understand how to play
Gameplay : original world/enemies, shoot and hit, fun and addicitive,
Appreciate that. Good to hear. Thanks.

however instead of moving toward left or moving toward right, i would have added a way to move the ship more quickly or less quickly to be able to avoid the "spores"
Turbo mode. That is simple to add and is now on my list for post competition changes along with improved Up/Down controls and fixing the online high score system that I had to comment out at the last minute!

Okay guys, where are the high score images?  :o
Yeah, please upload them. The online high score system is non functional and I'm going to have to add you all manually when I fix it.

The thing that set this apart for me from most of the other games (including mine) was the length of play.

While my game and others had a set number of levels for a limited time of play, this one ends based on skill and increasing difficulty.
 
Most retro games had limited time to play with fixed ends to the game after the first batch of arcade machines, once the operators realized that allowing a player to marathon play on Asteroids or Pac-Man for hours on one quarter did not result in very much revenue for the arcade.

Then came games like Pole Position that had a fixed number of laps for a quick but exciting game, and it became the highest grossing arcade machine for the year it was released, so operators looked for games that offered fixed play.

Games like mine, or Get to Da Chopper, have a fixed number of levels for quick play and a decisive end, but Fungicide uses increasing difficulty to make the game play short lived, especially for noobs honing their Fungicide skills.

I get to the end of the other games, like mine, and feel a level of accomplishment for 'beating the game', but games like Fungicide give me that feeling every time I beat my personal best score, because increasing my skills can keep extending the game time.

Also, the fixed number of digits for the score is classic, because you want to make it to 100,000 and get rid of that leading zero, but that seems to be nearly impossible with the increase in spore population in later waves.

This game keeps me wanting to go back and do more damage, and fight my way to that 100k.

Classic, Epic, and tons of Retro fun!

Despite the few bugs in the game restarts, this one is my favorite, and now you know why.
Thanks for the vote. Pleased you like it.

I had not thought about levels and increased difficulty in that way before. I remember the days playing games like defender for hours on one coin and then spending a fortune trying to finish dragons lair (never did).

Fungicide originally had four enemy types designed and the graphics for them are already drawn. They were introduced at different levels but two of them never made it due to time restraints (except the shrooms which I use as a desktop icon in Windows). I hope I get to finish this at some point.



Follow me at ITSpeedway.net.

Offline Derron

  • Hero Member
  • *****
  • Posts: 943
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #11 on: January 27, 2018, 12:52:16 PM »
Was not really able to play it on linux (excuse the big GIF file)





Game stucked here and there - sometimes ship was "invisible" (think it passed a barrier in the "stuck"-loops).
Used Wine then to run the windows binary... way smoother (but still slight stucks here and there).
The startscreen (story + testers) is not in the rotation of control and highscore. Escape did not return to the titlescreen. It went away too fast so I was not able to completely read the "story" .


"Z" is placed on the "Y" key on German keyboard layouts...


Why do small "moving" fungicides give less points than the easier to hit bigger enemies?


Highscore initials are tough to make: similar to Adams SyntaxBomb you need to hit the keys for each up/down movement. KeyDown() and a lastDownTime-comparison would help here.


My Wife told me that the sounds reminded her on the old Atari 2600 games.




bye
Ron


Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #12 on: January 27, 2018, 11:48:37 PM »
@Derron: Thanks for the feedback, much appreciated.

Invisible ship! Hmm, not seen that myself, but looking at the gif when the meteor arrives there is a gap in the tail which shows its stuttering. That can only happen when the game loop tries to play catch up and DeltaTime from the last loop cycle is a large duration and so it moves a long distance. Can't think what would be doing that.

What version of Linux are you using? It was developed mostly on my 32bit Linux Mint notebook and runs much smoother than on windows. I didn't try Wine myself.

I hadn't considered the story to be part of the lobby system, but I'll release another version after the competition with some changes and this is now on the list. I've also added the Z and Y keys issue to my list, although I'm not sure what to do about it at the moment.

I see what you mean about the points. Should be more points for the spore as it's more difficult to hit.

High score system is already on my list.

Follow me at ITSpeedway.net.

Offline Derron

  • Hero Member
  • *****
  • Posts: 943
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #13 on: January 28, 2018, 07:34:49 AM »
I also made sure to not have a >28 days uptime session (to avoid borked up delta timing because of the integer wrap).

Dunno what caused this. Am running Linux Mint 18.3 64Bit.
If you want you could code me a simple "game loop"-example outputting the necessary stuff.


My game loop looks like this:
Code: BlitzMax
  1. [...]
  2.    Method RunRender()
  3.       'the time available for rendering has to consider the time
  4.       'used for updating - so subtract that from the accumulator
  5.       _renderAccumulator:+ Max(0, _lastLoopTime - getCurrentLoopTime()) / 1000.0
  6.  
  7.       if(_renderAccumulator > _renderRate)
  8.          local start:Long = Time.GetTimeGone()
  9.  
  10.          'if there is a function connected - run it
  11.          if _funcRender then _funcRender()
  12.  
  13.          'subtract the time reserved for a render from the accumulator
  14.          _renderAccumulator = 0
  15.  
  16.          'for stats
  17.          timesRendered:+1
  18.  
  19.          _renderTime :+ (Time.GetTimeGone() - start)
  20.       endif
  21.    End Method
  22.  
  23.    Method RunUpdate()
  24.       'each loop the looptime is added to an accumulator
  25.       'as soon as the accumulator is bigger than the time reserved
  26.       'for an update ("timeStep"), the loop does as much updates
  27.       'as the accumulator "fits"
  28.       _updateAccumulator:+ Max(0, _lastLoopTime)/1000.0
  29.  
  30.       local start:Long = Time.GetTimeGone()
  31.      
  32.       while(_updateAccumulator > _updateRate)
  33.          'if there is a function connected - run it
  34.          if _funcUpdate then _funcUpdate()
  35.  
  36.          'subtract the time reserved for an update from the accumulator
  37.          _updateAccumulator = Max(0.0, _updateAccumulator - _updateRate)
  38.          'for stats
  39.          timesUpdated:+1
  40.       wend
  41.  
  42.       _updateTime :+ (Time.GetTimeGone() - start)
  43.    End Method
  44.  
  45.  
  46.    Method RunSystemUpdate()
  47.       'each loop the looptime is added to an accumulator
  48.       'as soon as the accumulator is bigger than the time reserved
  49.       'for an system update ("timeStep"), the loop does as much updates
  50.       'as the accumulator "fits"
  51.       _systemUpdateAccumulator:+ Max(0, _lastLoopTime)/1000.0
  52.  
  53.       local start:Long = Time.GetTimeGone()
  54.      
  55.       while(_systemUpdateAccumulator > _systemUpdateRate)
  56.          'if there is a function connected - run it
  57.          if _funcSystemUpdate then _funcSystemUpdate()
  58.  
  59.          'subtract the time reserved for an update from the accumulator
  60.          _systemUpdateAccumulator = Max(0.0, _systemUpdateAccumulator - _systemUpdateRate)
  61.          'for stats
  62.          timesSystemUpdated:+1
  63.       wend
  64.  
  65.       _systemUpdateTime :+ (Time.GetTimeGone() - start)
  66.    End Method
  67.  
  68.  
  69.    Method Loop()
  70.       'compute time last loop neeeded
  71.       '1/2: compute delta
  72.       _lastLoopTime  = Time.GetTimeGone() - _loopBeginTime
  73.       '2/2: store for next run
  74.       _loopBeginTime = Time.GetTimeGone()
  75.  
  76.       'update values for FPS/UPS stats
  77.       updateStatistics()
  78.  
  79.       'the loop time is limited to 250 ms to avoid spiral of dead
  80.       _lastLoopTime  = Min(250, _lastLoopTime)
  81.  
  82.  
  83.       RunSystemUpdate()
  84.       RunUpdate()
  85.       RunRender()
  86.  
  87.       'for looptime-average-calculation
  88.       _loopTimeSum :+ GetCurrentLoopTime()
  89.       _loopTimeCount :+ 1
  90.  
  91.       'if there was time left but no updates need to be done
  92.       'ALTERNATIV?: hierfuer feststellen wieviel zeit ein loop haette
  93.       'und wieviel davon benutzt worden ist... den rest dann "delayen"
  94.       if _renderRate > 0 and (_systemUpdateRate*1000 + _updateRate*1000 - getCurrentLoopTime() > 0)
  95.          delay(1)
  96.       endif
  97.    End Method
  98.  


And it works for me (and some hundreds/thousands of users) on Linux, Mac and Windows - at least nobody created issues about timing problems.



bye
Ron

Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 62
    • ITSpeedway - Ramblings of a geek!
Re: FUNGICIDE - Retro Game Competition Entry
« Reply #14 on: February 03, 2018, 02:26:32 PM »
If you want you could code me a simple "game loop"-example outputting the necessary stuff.

Thanks @Derron, I'll transplant your game loop code into the sample and see what I get.

I have drawn up the following sample using the game loop from Fungicide and adding 1000 sprites it seems to run smoothly. On my old  Dell Latitude D620! (32bit running Linux Mint), I get 35fps for 1000 sprites and 53fps for 100 sprites which was better than I expected.

I'm using a MilliSecsLong() function based on some code by ImaginaryHuman in my Delta Time code.

Code: BlitzMax
  1. SuperStrict
  2. ?linux
  3.         '# Fix for Linux Mint / Ubuntu
  4.         Import "-ldl"
  5. ?Win32
  6.         '# Windows Application Icon
  7. '       Import "bin/ProjectIcon.o"
  8. ?
  9.  
  10. '# Randomise the game
  11. SeedRnd MilliSecs()
  12.  
  13. '# Frame and game timings
  14. Global fps:Float = 0
  15. Global NextFrame:Long = MilliSecsLong()
  16. Global KeyFrame:Long = MilliSecsLong()
  17.  
  18. '# Start the game by Launching the lobby
  19. AppTitle = "MyGame"
  20. Global game:TEngine = New TEngine.Create()
  21. Global player:TPlayer
  22.  
  23. HideMouse()
  24.  
  25. '# Add some sample "enemies"
  26. For Local n:Int = 1 To 100
  27.         New TEnemy.Create()
  28. Next
  29.  
  30. While game.running
  31.  
  32.         '# Delta Time
  33.         Delta.Update()
  34.  
  35.         '# Collisions
  36.         ResetCollisions()
  37.  
  38.         '# Allow key-press every 16ms
  39.         If MilliSecsLong()> KeyFrame Then
  40.                 KeyFrame = MilliSecsLong() + 16
  41.                 game.update( Delta.time, True )
  42.         Else
  43.                 game.update( Delta.time, False )
  44.         End If 
  45.  
  46.  
  47.         '# REFRESH SCREEN 60FPS
  48.         If MilliSecsLong() > nextframe Then
  49.  
  50.                 '# Clear the screen
  51.                 SetClsColor( $f,$f,$f )
  52.                 Cls
  53.  
  54. '               game.backdrop()
  55.                 game.draw()            
  56.                 If player Then player.draw()
  57.                
  58.                 SetColor( $ff,$ff,$ff )
  59.                 DrawText( "FPS:"+FramesPerSecond(), 0,game.GRH-game.TXH )
  60.  
  61.                 Flip 0
  62.                 nextframe = MilliSecsLong() + 16.7 '60 Frames per second
  63.         End If
  64.        
  65. Wend
  66.  
  67. '############################################################
  68. '# Delta Time
  69. '# Based on code by WAVE:
  70. '# http://www.truplo.com/blitzmaxbeginnersguide/wave18.html
  71. '#
  72. '# Uses LONG miliisecs functions to overcome INT over-run after 28 days.
  73. Type Delta
  74. Global _last:Long = MilliSecsLong()
  75. Global _now:Long  = Delta.Update()
  76. '#
  77. Global Time:Float
  78.         '------------------------------------------------------------
  79.         Function Update()
  80.                 _now  = MilliSecsLong()
  81.                 Time  = Float( _now - _last ) / 60.0
  82.                 _last = _now
  83.         End Function
  84. End Type
  85.  
  86. '############################################################
  87. '# Fix for Millisecs() integer over-run
  88. '# Based on code by ImaginaryHuman:
  89. '# http://www.blitzbasic.com/Community/post.php?topic=84114&post=950107
  90. Function MilliSecsLong:Long()
  91. Global MilliSeconds:Long=0:Long                 'Initialize before use
  92. Global LastMilliSeconds:Long=get()              'Initialize before use
  93.         Return get()
  94.         '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  95.         Function get:Long()
  96.         Local Milli:Long=Long(MilliSecs())+2147483648:Long           'Convert to 32-bit unsigned
  97.         If Milli<LastMilliSeconds Then MilliSeconds:+4294967296:Long 'Accumulate 2^32
  98.         LastMilliSeconds=Milli
  99.         Return MilliSeconds+Milli
  100.         End Function
  101. End Function
  102.  
  103. '############################################################
  104. Function FramesPerSecond:Int()
  105. Global _counter:Int, _time:Long, _frames:Int
  106. Local _now:Long
  107.         _counter :+ 1
  108.         _now = MillisecsLong()
  109.         If _time < _now Then
  110.                 _frames  = _counter
  111.                 _time    = _now + 1000  '# Update again in 1 second
  112.                 _counter = 0
  113.         End If
  114. Return _frames
  115. End Function
  116.  
  117. '############################################################
  118. Type TEngine
  119. Field running:Int = True                                '# Application is still running
  120. Field paused:Int = False                                '# Game has been paused
  121. Field enemies:Int = 0
  122. Field GRW:Int = 640
  123. Field GRH:Int = 480
  124. Field TXH:Int = 0                                               '# Height of text
  125.  
  126.         '------------------------------------------------------------
  127.         Method Create:TEngine()
  128.                 Graphics( GRW, GRH )
  129.                 TXH = TextHeight("8")
  130.                 Return Self    
  131.         End Method
  132.  
  133.         '------------------------------------------------------------
  134.         ' UPDATE ALL SPRITES AND GAME STATES
  135.         Method update( delta:Float, keystate:Int=False )
  136.                 '#
  137.                 If AppTerminate() Then running = False
  138.                 '# Update all Sprites
  139.                 Enemies = 0
  140.                 For Local Sprite:TSprite = EachIn TSprite.list
  141.                         If( TEnemy(Sprite) ) Then Enemies:+1
  142.                         Sprite.update( delta, keystate )
  143.                 Next
  144.         End Method
  145.                
  146.         '------------------------------------------------------------
  147.         ' DRAW OBJECTS
  148.         Method draw()
  149.                 For Local Sprite:TSprite = EachIn TSprite.list
  150.                         Sprite.draw()
  151.                 Next
  152.         End Method
  153.  
  154.         '------------------------------------------------------------
  155.         Method quit()
  156.                 running = False
  157.         End Method
  158.  
  159. End Type
  160.  
  161. '############################################################
  162. Type TSprite
  163. Global list:TList = CreateList()
  164. Field x:Float, y:Float
  165. Field vx:Float, vy:Float
  166. Field speed:Float = 2.0
  167. Field size:Float = 3.0
  168. Field r:Int=$FF, g:Int=$FF, b:Int=$FF
  169.  
  170.         Method update( delta:Float, keystate:Int )
  171.                 x:+vx*speed*delta
  172.                 y:+vy*speed*delta
  173.                 If x+size>game.GRW Then
  174.                         x  = game.GRW-(x-game.GRW)
  175.                         vx = -vx
  176.                 End If
  177.                 If x-size<0 Then
  178.                         x  = -x
  179.                         vx = -vx
  180.                 End If
  181.                 If y+size>game.GRH Then
  182.                         y  = game.GRH-(y-game.GRH)
  183.                         vy = -vy
  184.                 End If
  185.                 If y-size<0 Then
  186.                         y  = -y
  187.                         vy = -vy
  188.                 End If
  189.         End Method
  190.        
  191.         Method draw()
  192.                 SetColor( r, g, b )
  193.                 DrawOval( x-size,y-size,size*2, size*2)
  194.         End Method     
  195. End Type
  196.  
  197. '############################################################
  198. Type TEnemy Extends TSprite
  199. Field points:Int = 10
  200.         Method New()
  201.                 ListAddLast( list, Self )
  202.         End Method
  203.  
  204.         Method Create()
  205.                 x=Rand(size, game.GRW-size)            
  206.                 y=Rand(size, game.GRW-size)            
  207.                 vx=RndFloat()*5-2.5    
  208.                 vy=RndFloat()*5-2.5            
  209.                 g=Rand(0,8)*32
  210.                 b=Rand(0,8)*32
  211.         End Method
  212. End Type
  213.  
  214. '############################################################
  215. Type TPlayer Extends TSprite
  216. Field angle:Int =0
  217.  
  218.         Method Create()
  219.                 x=game.GRW/2
  220.                 y=game.GRH/2
  221.         End Method
  222.        
  223.         Method update( delta:Float, keystate:Int )
  224. '               If keystate Then
  225. '                       If KeyDown( KEY_SPACE ) Then fire()
  226. '               End If
  227.         End Method
  228.        
  229.         Method draw()
  230.                 SetColor( r, g, b )
  231.                 DrawRect( x-size,y-size,x+size,y+size)
  232.         End Method
  233.  
  234.         Method fire()
  235.         End Method
  236.        
  237. End Type
  238.  

Follow me at ITSpeedway.net.