Empty Your Mind Tutorial 9
From SwinGame
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.
Contents |
Preparing A Data Required
In danmaku game, the "hit box" is much smaller than the actual ship. Therefore, we will need an image that defines the player's ship's collision box. The example image can be found here. This data should be stored in the ShipData structure. The new implementation of the ShipData structure follows.
ShipData = record theSprite : Sprite; speed : Single; health : Integer; alive : Boolean; shootDelay, currentDelay : Integer; maxMagazine, currentMagazine, reloadDelay: Integer; //Enemy data time, offset : Integer; direction : EnemyMovement; //The sprite data used for the player collision theSpriteC : Sprite; end;
Do not forget to initialise the theSpriteC in the LoadGame procedure. We will need to synchronise the position of the collision box with the actual ship's position to use the collision box. This should be done after moving the ship's position (i.e. after MovePlayerShip). The code to synchronise the position should be:
player.theSpriteC.xPos := player.theSprite.xPos; player.theSpriteC.yPos := player.theSprite.yPos;
Collision Detection With Bullets
We will be writing a single procedure that will check a collision with bullets for both the player and the enemies. The following steps must be takes to check a collision between a bullet and a ship.
- Find a bullet that is alive
- Check if the bullet is against the ship specified. Go back to the step 1 if not.
- Initialise the sprite used to check the collision depending on the side of the ship.
- Check if the ship and the enemy have collided. Go back to the first step if not.
- Subtract the ship's health by the amount of damage the bullet should do.
- Kill the ship and play a sound effect if the health is lower than 0.
- Kill the bullet collided.
The steps should be repeated until it checks all bullets. The implementation of the steps follows.
procedure ProcessShipCollision(var shipToProcess : ShipData; var game : GameData; shipSide : BulletSide); var i : Integer; tempSprite : Sprite; begin for i := 0 to High(game.bullets) do begin if game.bullets[i].alive and not (game.bullets[i].side = shipSide) then begin //Initialise the sprite used to check the collision if shipSide = Enemy then tempSprite := shipToProcess.theSprite else tempSprite := shipToProcess.theSpriteC; if HaveSpritesCollided(game.bullets[i].theSprite, tempSprite) then begin shipToProcess.health := shipToProcess.health - game.bullets[i].damage; //Kill and play a sound effect if the health is lower than 0 if shipToProcess.health <= 0 then begin shipToProcess.alive := false; PlaySoundEffect(game.sounds[1]); end; //Kill the bullet collided game.bullets[i].alive := false; end; end; end; end;
This method to check and process a collision needs to know which side the ship is on because the procedure must check if the bullet is not fired by the ship's own side. The sound effect played in the procedure is played when a ship gets destroyed. The sound effect I have used in my game can be found here. The ProcessShipCollision routine should be called after processing the ship and from the UpdateEnemies procedure.
To update the player's ship:
ProcessShipCollision(game.player, game, Player);
To update a enemy's ship, you will need to add a new line after checking if the enemy has gone out of the screen. The new implementation of the UpdateEnemies procedure:
procedure UpdateEnemies(var game : GameData); var i : Integer; begin for i := 0 to High(game.enemies) do begin if (game.enemies[i].time <= game.gameTimer) and game.enemies[i].alive then begin game.enemies[i].theSprite.xPos := game.enemies[i].theSprite.xPos + game.enemies[i].speed; if IsSpriteOffscreen(game.enemies[i].theSprite) then begin game.enemies[i].alive := false; continue; end; ProcessShipCollision(game.enemies[i], game, Enemy); ShootEnemyBullet(game.enemies[i], game); DrawSprite(game.enemies[i].theSprite); UpdateSpriteAnimation(game.enemies[i].theSprite); end; end; end;
The final thing you need to do to kill the player is to end the game if the player is not alive. Insert the following line into your game loop to quit the game when the player gets hit.
if not game.player.alive then break;
Summary
In this tutorial, I have gone through:
- Collision detection
The current project files can be downloaded from here.

