RSS

a) Gameplay

The goal: our first game in 10 minutes flat!  Shoot the bad guys coming down the screen.

Getting started

Download the Part 1 of the project files and see file ‘gameplay-step1.bmx’

First, we use SuperStrict and Import the framework..

SuperStrict
Import matibee.mbmframework

Next we need to define our ‘game’ type that’s derived from AppModule.  The AppModule type adds a lot of functionality to our game right out of the box..

‘ make a module type that acts as a game
Type game Extends AppModule

 ’ simple create function
 Function Create ( resourceFile:String )
  Local g:game = New game
  g.Initialise( resourceFile, APP_GAME )
 End Function

 ’ an update method that’s called every ‘tick’
 Method Update( timeMS:Int )
  Super.Update( timeMS )
  If ( AppTerminate() Or KeyHit( KEY_ESCAPE ) )
   EndModule()
   Return
  End If
  ’ position our player
  GetSprite( “player” ).SetPosition( MouseX(), MouseY() )
 End Method

 ’ a draw method that’s called every tick
 Method Draw()
  ‘ draw our player
  GetSprite( “player” ).Draw()
  Super.Draw()
 End Method
End Type

In that type, we’ve made a simple Create() function and Update() and Draw() methods.  Create() must call Initialise() so the AppModule knows what resources it uses and what type of module it is. Update() simply looks for a reason to quit and puts the player sprite at the current mouse coordinates, but notice how the first thing it does, is call the Update method of its parent.  Draw simply draws the player and the rest of the code is simple too..

‘ we don’t need a mouse pointer
HideMouse()
‘ create the game module
game.Create( “Media/gameResources.txt” )
‘ init and run the app
InitApp( 800, 600, 32 )
RunApp()

The resource file

Take a look at the file we use to create the game with “Media/gameResources.txt”:

SPRITE player = Media/Sprites/player.png
SPRITE bullet = Media/Sprites/Bullet.png
SPRITE enemy = Media/Sprites/1/1.csv 

It simply defines the sprite names and the files each one uses.  These resource files are an import of the framework and we will be revisiting them several times before these tutorials are over.

Adding fire power

See file ‘gameplay-step2.bmx’

A lot of this is standard programming and Blitzmax programming methods.  There’s a million ways to add firing in a game and this is just one.  First, let’s add some fields to our game Type.  Here will will use a SpriteList type from the framework.  It gives us a list of free sprites and a list of live sprites and updates and draws them for us (when we ask it).  We also add a countdown timer so we can limit the firing speed:

 Field bulletSprites:SpriteList  ’ a list of bullet sprites
 Field fireDelay:Int    ’ a timer between bullet firings

In order to initialise the bullet list we can overide another AppModule method; Start().  This method is called once everytime the AppModule begins and is provided for one-time initialisation prior to the sequence of Update()/Draw() starting.  Here’s our start method, added to our game Type:

 ‘ a new method, called once when the module starts
 Method Start()
  Super.Start()
  
  ‘ create the bullet SpriteList
  bulletSprites = SpriteList.Create( GetSprite( “bullet” ), 20 )

 End Method  

You’ll see we must call Super.Start() before anything else to ensure all resources are loaded and any AppModule specific states are ready.

GetSprite is an AppModule function that returns a MasterSprite object.  For the player, we used that MasterSprite directly but because we want 20 bullet sprites in our list, each with it’s own screen position, we’re going to create instances of MasterSprite which will be plain Sprite objects.  The sprite called “bullet” was defined in the game modules resource file (Media\gameResources.txt).

Now we need to add some code to our game Types Update() function in order to fire new bullets, and move the ones we’ve got already..

  ’ move all our bullets up the screen
  For Local s:Sprite = EachIn bulletSprites.LiveList()
   s.SetY( s.GetY() - 0.6 * timeMS )
   If ( s.GetY() < -20 )
    bulletSprites.Kill( s )
   End If
  Next

  ’ see if we should fire another bullet
  If ( MouseDown( 1 ) )
   fireDelay :- timeMS
   If ( fireDelay <= 0 And bulletSprites.FreeCount() )
    Local s:Sprite = bulletSprites.NextFree()
    s.SetPosition( MouseX(), MouseY() )
    fireDelay = 100
   End If
  End If

In the first part, we’re using two methods of Sprite - Get_Y() and Set_Y().  The Y value is changed according to the timeMS delta time, and if it reaches a certain position off the screen it’s ‘killed’ ie - removed from the live list and put back in the free list by our SpriteList object.

In the second part we look if the mouse button is down and decrease the fire time (again according to timeMS). When fire time reaches zero we can release a new bullet if we’ve got any ‘free’.  We get a Sprite from our SpriteList and set it’s position to the ship position.  We also reset the fire delay time to another 100 milliseconds.

Finally we want to draw our live bullets.  That’s done by adding one call in our Draw() method..

‘ draw all the bullets
  bulletSprites.Draw()

Adding enemies!

See file ‘gameplay-step3.bmx’

This is very similar to the way we added bullets using a SpriteList Type and a countdown timer to release more enemies.  These are the fields added to the game Type:

Field enemySprites:SpriteList  ’ a list of enemy sprites
Field enemyDelay:Int   ’ a delay between launching new enemies

To initialise them, we add code to game.Start() which is almost a direct copy of what we did for the bullets:

‘ create the enemy SpriteList
  enemySprites = SpriteList.Create( GetSprite( “enemy” ), 100 )

To update them we add some more code to game.Update() :

‘ move all our enemies down the screen
  For Local s:Sprite = EachIn enemySprites.LiveList()
   s.SetY( s.GetY() + 0.1 * timeMS )
   If ( s.GetY() > 620 )
    EndModule()
    Return
   End If
  Next

  ’ update the enemy sprite animations
  enemySprites.Update( timeMS )

  

Apart from the direction and speed, this is very similar to the way we handled the bullets but with one important difference.  Because the enemy sprite is animated we have to call it’s Update() function.  Here we can update them all by using the Update method of the SpriteList.

If any sprites have made it off the bottom of the screen then it’s game over, we end the module.

Some more code is added to Update() to deal with releasing new enemies onto the screen;

 ’ release some new enemies..
  enemyDelay :- timeMS
  If ( enemyDelay <= 0 )
   For Local t:Int = 0 To 2
    If ( enemySprites.FreeCount() )
     Local s:Sprite = enemySprites.NextFree()
     s.SetPosition( Rand( 10, 770 ), -40 - Rand( 1, 10 ) )
     s.RandomizeTime()
    End If
   Next
   enemyDelay = 400
  End If
 

This time we are using a method of Sprite to set it’s position, imaginatively called SetPosition.  We are also randomizing it’s animation time using the RandomizeTime method.

We also need to draw our enemies.  And in the same way as the bullets, we add one call to the Draw() method:

‘ draw the enemies
  enemySprites.Draw()

Killing the bad guys!

See file ‘gameplay-step4.bmx’

We just need some basic collision code between the bullets and the enemies.  Nothing fancy here, just simple distance checks.  Remember this is a framework tutorial, not a game programming tutorial!

We’ll do the collision in game.Update() and any enemies that are hit will be ‘killed’ (removed from the live list and put back in the free list of SpriteList) and do the same for the bullet that hit them.  We’ll also see if the player has collided with any enemies and also end the module if he has:

  ’ do collisions between the bullets and the enemies
  For Local s:Sprite = EachIn bulletSprites.LiveList()
   For Local t:Sprite = EachIn enemySprites.LiveList()
    Local xdist:Float = s.GetX() - t.GetX()
    Local ydist:Float = s.GetY() - t.GetY()
    If (( (xdist * xdist) + (ydist * ydist) ) <= 512.0 )
     enemySprites.Kill( t )
     bulletSprites.Kill( s )
     Exit
    End If
   Next
  Next

  ’ do collisions between the player and the enemies
  Local player:MasterSprite = GetSprite( “player” )
  For Local s:Sprite = EachIn enemySprites.LiveList()
   Local xdist:Float = s.GetX() - player.GetX()
   Local ydist:Float = s.GetY() - player.GetY()
   If (( (xdist * xdist) + (ydist * ydist) ) <= 512.0 )
    EndModule()
    Return
   End If
  Next

And that’s it, we have a game!  Or at least the start of one.  Next time we’ll look at adding a main menu..

On to Step 2 - Adding a  main menu

Comments are closed.