Empty Your Mind Tutorial 4
This tutorial will teach you how to use the SwinGameSDK to develop a simple danmaku game which looks cool. At the end of this tutorial you should be able to use pascal to implement your own space invaders or scrolling shooter style game which makes use of Vectors, animated Sprites, SoundEffects, and Music.
Bullet Data Structure
It is possible for you to implement the bullet data using a parallels arrays, but it can get unnecessarily complex. I will be defining a bullet data structure and an enumerations. We will need few things to represent a bullet data structure.
- Bullet sprite
- Damage it can cause (Integer)
- Kind of a bullet
- Alive (True if this bullet is alive)
- Side (Enemy bullet or the player's bullet)
As you can see, we need to define enumerations for Kind of a bullet and Side. The implementation of the structure is shown bellow.
//Kind of a bullet BulletKind = ( Normal ); //Side BulletSide = ( Player, Enemy ); BulletData = record theSprite : Sprite; damage : Integer; kind : BulletKind; alive : Boolean; side : BulletSide; end;
Creating A Bullet
We will have to create a bullet to fire a bullet. This is a simple initialisation process to set the bullet information. We need the following information to create a bullet.
- The name of a bullet image
- The ship data to know where the bullet was fired from
- The amount of damage the bullet can cause
- Kind of a bullet
- Side of a bullet
- Movement vector of a bullet
The following function will implement the initialisation of a bullet and return a new bullet.
function CreateBullet(imgName : String; shotFrom : ShipData; damage : Integer; kind : BulletKind; side : BulletSide; vec : Vector) : BulletData; begin result.theSprite := CreateSprite(GameImage(imgName)); result.theSprite.xPos := shotFrom.theSprite.xPos + shotFrom.theSprite.width div 2 - result.theSprite.width div 2; result.theSprite.yPos := shotFrom.theSprite.yPos + shotFrom.theSprite.height div 2 - result.theSprite.height div 2; result.damage := damage; result.alive := true; result.side := side; result.kind := kind; result.theSprite.movement := vec; end;
There will be hundreds of bullets flying on the screen at the same time. Therefore we must have an efficient bullet management system. To implement this, I'm going to have an array of BulletData which contains every bullet in the game. The new GameData record is…
GameData = record player : ShipData; images : Array of Sprite; bullets : Array of BulletData; end;
You will also need to modify the LoadGame routine to initialise the game structure.
const BULLETCOUNT = 500; … //Initialise all bullets SetLength(game.bullets, BULLETCOUNT); for i := Low(game.bullets) to High(game.bullets) do begin game.bullets[i].alive := false; end;
This will kill all bullets at the start of the game and sets the maximum numbers of bullets to 500.
Shooting A Bullet pt.1
Shooting a bullet can be done very easily by going through the bullets array. The steps to shoot a bullet is…
- Find a dead bullet
- Copy the new bullet into the dead bullet
procedure DeployBullet(bullet : BulletData; var bullets : Array of BulletData); var i : Integer; begin for i := Low(bullets) to High(bullets) do begin if not bullets[i].alive then begin bullets[i] := bullet; exit; end; end; WriteLn('No bullets to deploy…') end;
Calling the DeployBullet routine by passing the appropriate parameters will shoot the bullet. However, we need to draw the bullets and update the positions. The following steps must be taken to implement this.
- Find a bullet which is alive
- Kill the bullet if the bullet is offscreen
- Draw the bullet
- Move the bullet
- Repeat the step 1 to 4 until all bullets are processed
The implementation of the steps:
procedure UpdateBullets(var bullets : Array of BulletData); var i : Integer; begin for i := Low(bullets) to High(bullets) do begin if bullets[i].alive then begin if IsSpriteOffscreen(bullets[i].theSprite) then begin bullets[i].alive := false; continue; end; DrawSprite(bullets[i].theSprite); UpdateSprite(bullets[i].theSprite); end; end; end;