Firing bullets at zombies


Code for this tutorial is on this git branch:

git clone -b zombies https://dglencross@bitbucket.org/dglencross/zombiegametutorial.git

Have a look here for help setting it up


Firing bullets

Also included in the latest code is the ability to fire bullets at zombies. They way the player actually does this is to touch on or close to the zombie.

In the earliest iteration of this, I had the zombies simply die when clicked on. This was very unsatisfying, so I implemented proper bullets. In the current version of the game, I don’t think it’s actually possible to miss – the zombies run directly at you, so when you fire a bullet in their direction, you are guaranteed to hit. However, you could imagine a development of the game where the zombies run from side-to-side, and so bullets could easily miss.

The bullets continue on when they hit a zombie, so they can actually hit multiple zombies on the map if they happen to be aligned.

Aiming

As described, the mechanism for firing is to click on/touch a zombie. In our PlayerInputSystem, we introduce a method for checking if the place we just touched is on a zombie.

private Zombie getTouchedZombie(int x, int y) {
   Vector2 touch = new Vector2(x,y);
   for (Zombie z : screen.getGameController().getZombies()) {
      if (!z.hasBeenShot() && z.getPos().dst(touch) < 2) {
         return z;
      }
   }

   return null;
}

All we do is loop over our zombies and check if they are close to the touch. This is some pretty basic ‘collision detection’. We call this method every time we touch somewhere on the screen. If it returns a zombie, we fire at it.

Zombie shot = getTouchedZombie(x, y);

if (shot != null) {
   getPlayer().shootZombie(shot);
   return false;
}

Note we also return from the touchDown method – we don’t want to walk towards the zombie. Whenever we shoot, the player stops walking.

Bullets

The Bullet class is where all of the logic for an individual bullet resides. It is created and then the fire() method is called, and given its starting point and its destination (i.e. the location of the zombie we have fired at).

public void fire(Vector2 destination, PlayerCharacter character) {
    currentPosition = character.getPos().cpy();
    endPosition = destination.cpy();

    dir = endPosition.cpy();
    dir.sub(currentPosition);
    dir.setLength(BULLET_SPEED);
}

Let’s look at what is going on here. In the first two lines, we assign our currentPosition to be the same as the character’s, and the endPosition to be the vector we have passed in.

We set the dir (direction) variable to be the difference between the start and end points, but at a shorter length. You can vary this length depending on how fast you want your bullets to move.

When we update then, we just keep adding that dir variable to the currentPosition to keep our bullet moving in a constant direction at constant speed:

public void update(float delta) {
    currentPosition.set(currentPosition).add(dir);
    sprite.setPosition(currentPosition.x, currentPosition.y);
}

Bullets colliding with zombies

Finally, we need some collision detection between zombies and bullets. This will work in the same way as the other basic collision detection we use (when checking whether a player has clicked near a zombie, or if a zombie is touching the player). Every time we update the zombies, we check whether they have been hit by a bullet.

This is in the GameController:

// check if a zombie has been hit by a bullet
for(Bullet b : bullets) {
   if (b.isLive() && z.getPos().dst(b.getPos()) < 1.0f) {
      z.shoot();
   }
}

If the bullet is still live, and it is very close to the zombie, we consider that a collision and kill the zombie by triggering its shoot method. (We also keep track of the number of shot zombies, but I’ve removed that from here just for clarity).

At this point of the development of the game, the zombie’s shoot method simply tells it that it has been shot. This means that when zombies come to be updated later, this zombie will not have its update method triggered, and the player can no longer interact with it, for example by dying when walking over it. We also set the zombie’s sprite to be a satisfyingly gory blood splatter.

Conclusion

In this tutorial we have shown how to fire bullets and have them ‘hit’ zombies.

There are still some improvements to be made for this, which I may work on in future (though it’s not a priority). These include:

  • collision detection could probably be more efficient
  • at time of writing, bullets never ‘die’. This would be fairly easy to implement though – just keep count of how far a bullet has travelled and set  ‘live = false’ after a certain distance
  • the bullet does not come out of the player character’s gun, but just starts from his ‘position’ on the map. Again, this could be done fairly easily I think – but it seemed fiddly so I haven’t bothered (particularly as I might change the player sprite in future)

Next up will either be some kind of GUI, or perhaps map improvements – the map still looks a bit crap at the moment. In Dinowar we have logic to work out corners and how edges fit together, something that I may implement in a future tutorial for this.

Dinowar edges made smooth


If you like these tutorials, or want to see a game that was written in much the same way, please download Dinowar from the Google Play Store. It costs nothing and is ad-free.

Leave a Reply

Your email address will not be published. Required fields are marked *