In the last lesson, we implemented the Fatigue stat – caused by attempting to draw cards from an empty deck. However, although we could watch the stat change, it had no real effect on the game itself. In this lesson, we will add a reaction to fatigue which applies damage to the player’s hero by the fatigue amount. As a result, we have the means to determine when a game will end – whenever a hero’s hit points have dropped to zero.
In the previous lesson, I mentioned two cases where drawing cards should not be allowed: when your deck is empty, and when your hand is full. In many cases an exception to a game action could result in the complete cancellation of the action, but what if the action could be partially performed? For example, imagine that you needed to draw three cards, and only had two in your deck. Rather than cancel the entire action, you should still draw the two cards that were available, and then apply fatigue for the third draw attempt only. Let’s try it out.
One of the most powerful features of the Action system is the way it can chain together actions with reactions into a long sequence of events. At the moment we have only implemented a single action – changing turns, but in a game like Hearthstone, this action will always have at least one reaction. When a player starts their turn, they are supposed to draw a card. Let’s go ahead and implement the draw a card feature as a reaction to the action for changing turns.
In the previous lesson, we implemented the systems and models necessary to change turns. However, outside of watching a checkmark appear in a unit test, there was no visible evidence of anything occuring. Having a “view” to represent the data is an important step of the process, but is something that really can be anything you want, and therefore should be separated as much as possible. The final result could be 2D or 3D. It doesn’t have to be animated, though it definitely could be, and might even include stuff like flashy particles, who knows? The important thing is that a user can understand and interact with the game.
We’ve laid some nice foundations in the past few lessons, and now its time to actually start building up the game on top of it all. We’ll start with somthing pretty simple to help drill in the basic ideas, while also adding a little more functionality. Since we are making a turn based game, we’ll begin by learning to change turns.
In a game like Hearthstone, every action is significant and can serve as the trigger for a whole new sequence of actions. This includes obvious actions like attacking and casting spells, but also includes less obvious actions such as drawing cards and even changing turns! Although you may already be familiar with event-driven programming, you may not have thought about ways to sort event responders by custom criteria, or considered how to invoke the handlers over time so that you can also play animations in sequence. Let’s look at some architecture to support these ideas.
We started out by creating an architecture to allow systems to talk to each other, and still don’t have any systems. Even worse, we have no models for the systems to operate on! Let’s take a few steps back and start building up our game from the beginning.
Whenever I begin a new project, the first thing I think about is how I want to set up the architecture. Basically I am looking for the answer to this question: “How will all the stuff know about all the other stuff?”. In the past I usually resorted to a pattern called the Singleton to make it easy for data to be accessible from anywhere. In this case, I don’t want to rely on Singletons because I want my code to be testable, and from what I have read, the two don’t tend to go together well.
The goal of this project series will be to create a foundation from which you could make your own Collectible Card Game (CCG) / Trading Card Game (TCG). I sent out a poll to see what everyone would be most interested in building, but the results were pretty much the same for every entry and included a bunch of games I had never played. So, I decided to base the series primarily on Hearthstone, since it is my personal favorite.