Saturday, May 4, 2013

Adding Player Health

Video is at the very end of the post in case you want to skip straight to it.

Two posts ago I introduced a new Screen Management architecture that I had implemented. Currently, Entity state can be easily managed and manipulated by using Behaviors. Additionally, Sections can be created and destroyed (and rendered at the same time, with different cameras). But what if two Sections need to communicate to each other? For example, Player Health is something that both the game screen (so enemies can reduce it) and the HUD screen (so it can be displayed) need to know about!

Both 'Sections' need to know about a shared variable, Health.

Entities are local to a section and shouldn't be passed around, so we don't really want to use a behavior attached to an entity to do our work.

One option is to use a Global state object of some sort. But that's no good, because globals are generally difficult to manage and lead to poor design. For example, if I wanted to load a game, I'd have to manually implement a 'reset' on the game state. With proper object management, I should be able to just toss out the existing game state and replace it with a fresh one. In addition, a global state would imply nonsensical designs where you could access the player's health from the title screen. So, no to globals.

Another option is to tie a Game Model (this can be any object you want) to a Section, but allow the model to be shared across sections. This is the design I ended up implementing. Here is an example of how the main game might be set up with a shared model:

The code that sets up a simple shared Game Model

Once this is done, Behaviors can access the Game Model. For the sake of convenience, I've decided to introduce a base class for behaviors that belong in-game (as opposed to, say, stuff on a start-up screen). Here is a sample (and simple) usage:

Highlighted is the code that makes the player lose health. Simple!

Note that I've added a 'damage amount' variable to the 'DamagePlayer' trigger. So now what? Well, I've created some Hearts that live in the HUD Section. Each Heart has an update method that polls the game model to determine how it should be displayed. For example, if the current health is 5, and the heart is the 7th heart, the heart should be invisible. If the current health is 5.5, and the heart is the 6th heart, then we'd show a partial heart (for the sake of simplicity, I just draw it at half-scale).

The player has 5.5 health remaining

As always, there is a fun little video of everything in action. Some notes:
  • As a demo of both subtracting and adding health, I've added a simple little ghost enemy that does damage proportional to its size and little heart pickups. The ghost in the first room does 1 damage, the bigger ghosts do 2.5 damage. The heart pickups restore 1 health.
  • The model caps the player's health at 8 for this demo. You can see that additional heart pickups, once full, don't give the player more health.
  • I'll be adding game music to the videos just for flavor. This is being played through the game's audio engine, which I added recently (it wasn't worth a blog post--it's pretty simple for now). Of course, once I get my own music I'll be using that!
  • The ghost enemy is just a demo whipped up in a few minutes, nothing necessarily permanent. True enemy design will come at a later phase.
  • I had to re-implement section transitions after changing from Lua to pure C#, but hadn't gotten around to actually doing it until this week. 
Anyway, the video. Enjoy!

No comments:

Post a Comment