Empty Your Mind Tutorial 5

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.

This page contains a Tutorial. Tutorials are designed to walk you through the development of a small game.
Warning: You must have completed the previous tutorial(s) to go through this tutorial

Shooting A Bullet pt.2

We need to check the player's key input and shoot a bullet if a key is being pressed. In my game, I'm using the Z key to shoot a bullet. The following code will shoot bullets in five directions when the key is being pressed.

procedure ShootPlayerBullet(var game : GameData);
const
	BULLETSPEED = 12;
	DAMAGE = 3;
var
	tempBullet : BulletData;
begin
	if IsKeyPressed(VK_Z) then begin
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(270, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(255, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(285, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(240, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(300, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
	end;
end;

As you can see from the ShootPlayerBullet routine, I have used the GetVectorFromAngle to create the vector of the bullets. The first parameter defined the angle and the second parameter defined the magnitude of the vector. The bullet pattern can easily be modified by changing the vector. This must be called before drawing a player sprite. You also need to call UpdateBullets after calling ShootPlayerBullet.

Note: UpdateSprite routine also updates the sprite's position based on the vector.

You may have noticed that the ship can now fire bullets but without a delay. Therefore, we have to implement a system to create a delay between the bullets. To do this, we must introduce an another data entry for the ShipData structure. We need the following information to create a delay.

  • The time between the bullets
  • The time left until shooting the next bullet

The following record is the new implementation of the ShipData

ShipData = record
	theSprite : Sprite;
	speed : Single;
	shootDelay, currentDelay : Integer;
end;

The CurrentDelay entry will act like a counter until shooting the next bullet. The following steps must be taken to create a delay between the bullets.

  1. Decrement the currentDelay by 1
  2. Shoot bullets and reset the currentDelay if the Z key is being pressed and the currentDelay is 0

The new implementation of ShootPlayerBullet with a delay between the bullets:

procedure ShootPlayerBullet(var game : GameData);
const
	BULLETSPEED = 12;
	DAMAGE = 3;
var
	tempBullet : BulletData;
begin
	if game.player.currentDelay > 0 then
		game.player.currentDelay := game.player.currentDelay - 1;
	if IsKeyPressed(VK_Z) and (game.player.currentDelay = 0) then begin
		game.player.currentDelay := game.player.shootDelay;
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(270, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(255, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(285, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(240, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(300, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
	end;
end;
Note: Do not forget to initialise the shootDelay and currentDelay in the LoadGame routine. My shoot delay is set to 4

We now have a beautiful delay between all bullets. However, they do not have a reload time. Reload time occurs after shooting a certain amount of bullets. In the reload time, the player will not be able to shoot a bullet. The steps to fire a bullet should be:

  1. Decrement the number of bullets left if there are no bullets or negative amount of bullets left
  2. Check if the reloading has finished
  3. Shoot if not reloading
  4. Decrement the number of bullets left

You will need to alter the ShipData structure to implement the reload delay. The new implementation of the ShipData structure:

ShipData = record
	theSprite : Sprite;
	speed : Single;
	shootDelay, currentDelay : Integer;
	maxMagazine, currentMagazine, reloadDelay: Integer;
end;

The implementation of reload:

procedure ShootPlayerBullet(var game : GameData);
const
	BULLETSPEED = 12;
	DAMAGE = 3;
var
	tempBullet : BulletData;
begin
	if game.player.currentMagazine <= 0 then
		game.player.currentMagazine := game.player.currentMagazine - 1;
	if game.player.currentDelay > 0 then
		game.player.currentDelay := game.player.currentDelay - 1;
	if game.player.currentMagazine < 1 then begin
		if game.player.currentMagazine = -1 * game.player.reloadDelay then
			game.player.currentMagazine := game.player.maxMagazine;
	end	else if IsKeyPressed(VK_Z) and (game.player.currentDelay = 0) then begin
		game.player.currentMagazine := game.player.currentMagazine - 1;
		game.player.currentDelay := game.player.shootDelay;
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(270, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(255, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(285, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(240, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
		tempBullet := CreateBullet('PlayerBullet', game.player, DAMAGE, Normal, 
									Player, GetVectorFromAngle(300, BULLETSPEED));
		DeployBullet(tempBullet, game.bullets);
	end;
end;

Summary

In this tutorial, I have gone through:

  • Managing lots of bullets
  • Structuring the bullet data
  • Moving a sprite using a vector
  • Limiting the bullet fire rate

The current project files can be downloaded from here.

List Of Tutorials

  1. Introduction
  2. Player Ship
  3. Background
  4. Bullet pt.1
  5. Bullet pt.2
  6. Music and SoundEffect
  7. Enemies pt.1
  8. Enemies pt.2
  9. Collision Detection
  10. Further Extensions