Unofficial Pokemon Board Game – Flow Control

The application flow determines what happens and when it happens. In nearly all of my previous projects, the flow sort of just emerged as user interactions and app reactions were tied together. However, you may find value in taking the time to create flow charts. Almost like an artist would create some thumbnails before painting, flow charts can provide you a way to quickly rough out the logic you’ll need to implement. If you can make it clear now, it should be clear later too. In addition to being a good diagram to follow during development, a good flow chart can also serve as an excellet piece of documentation for later – one which probably far surpasses the value of code comments.

Flow Charts

To be honest, I have almost never used flow charts before this little project. Largely this was because I never found free software that I liked well enough to make them, and perhaps because I underestimated their worth. I wanted to create some this time due to prior requests in my other projects, so I decided to push through. I actually found a tutorial for creating them using Microsoft Word and it turned out fairly well. I liked being able to use the gridlines and easily place and manipulate shapes on the canvas.

The way I approached the diagramming for this project was to use a progressive detail model. In other words, I allowed myself to speak in very broad concepts, and fill in the details as layers or sub-flow charts where necessary. You can see this as we progress from the Main Flow on to each of the subsequent flows.

Main Flow

At the top of the flow chart is a green circular node labeled “Start” – this symbol is called a terminator. It indicates the launch of our app. There is a paired terminator at the bottom of the chart. This one is labeled “End” and colored red. It could indicate that a user had completed the entire flow, or that the application has ended.

The other nodes in the flow chart are blue. As a general rule, each of these nodes will represent a “state” of the application in which we might be showing a screen and waiting for input, or playing an animation and waiting for it to complete, etc. There are three different blue symbols used:

  • Process – this is the rectangular symbol (see “Intro” node). I use it to represent a state which is simple and doesnt require any further details. It also looks like a “State” in Unity’s Animation Controller.
  • Preparation – this is the symbol that looks like a horizontal Rupee from Zelda (see “Setup” and “Play” nodes). I use it to represent a state which is complex and will be further defined by another flow chart. This also looks like a “Sub-State Machine” in Unity’s Animation Controller.
  • Decision – this is the diamond symbol (see “Game Over” node). It is used to indicate a branch in the program flow.

All of the nodes are connected by arrows. Usually the arrows are one-way, although I do use two-way arrows on occasion. The arrows indicate the flow – it shows what state can be entered when the current state completes. Beginning with the “Start” terminator node, you can follow the arrow and see that the first state will be the “Intro” state. This is a fully defined state – all that I will provide is a title screen with a play button, although some games use far more complex introductions, such as showing samples of gameplay if the state is idle for too long. When the “Intro” completes we will enter a “Setup” mode, then a “Play” mode, and finally when the game ends we may choose whether or not to repeat the entire process again.

Setup Flow

Shown above, is the progressive detailing of a “Setup” flow. The design is similar to the one used with the main flow, although in place of the “terminator” nodes I have used “connector” nodes – their symbol is just a circle. In this case, you can think of the green connector as being whatever appears in the super layer as input – in this case it would be the “Intro” node. You can also think of the red connector as being whatever appears in the super layer as the output target – in this case it will be the “Play” node.

Setup begins with a menu screen where we decide what it is we are setting up. The process required to create a new game is different than one used to load a game, so you can see a branch at this point. However, I like to tidy up my flow by meeting at a common point before exit. This allows for a common point to finish setup or perform cleanup. In this case, I need to do things like prepare the game board and pawns based on the game settings regardless of if I started a new game or loaded one. As a bonus, in the event that I want to modify the program flow later (such as what comes after “setup”) then I would only need to change the target in the “Complete” node rather than in each of the other branch nodes.

Create Flow

When creating a game I will show two different screens. On the first screen a user will determine the number of players. Then on the next screen, we loop through all of the players and provide a name and starter Pokemon for each. Note that there is a double arrow between the two nodes – this indicates that there is a way to go backward through the flow. Perhaps the user selected the wrong number of players.

Play Flow

Whenever we enter the Play mode, or when a new turn becomes active, the “Get Ready” state will show an alert to let everyone know whose turn it is. This could be especially important in a locally played game where there is sensitive information (like a hand of cards or unit locations in a fog-of-war tactics game) but in this game it is just a formality.

Next, we enter the “Get Set” state. Here the player has options on how to proceed. Reviewing the “Team” is an optional step, and can allow you a chance to heal any wounded Pokemon, power them up and/or evolve them, etc. Since I don’t provide menus to do these tasks anywhere else, this will likely be a first step in every player’s turn.

When a player is ready, they will then choose to “Roll” – and they will see an animated screen simulating the dice roll. This roll number will determine how far they can potentially travel on their journey around the board.

The “Journey” flow is complex – it handles the logic of what a player can encounter while traveling around the board. Some of the encounters may allow the player to win the game. If so, “Play” will exit, otherwise, we will set the game to the “Next Player” and then the process will repeat.

Journey Flow

The journey flow begins in the “Move” state where we animate a player’s pawn advancing by one tile on the gameboard. This will always occur, as no roll can be less than one, but the entire journey flow is repeatable, so this state can be re-entered many times for a single roll and in this way you can move a pawn as far as it needs to go.

As a pawn moves around the board, there are several “interruptions” or “points of interest” that we may want to resolve before allowing the pawn to continue. These are visits to a Pokecenter, Pokestop, Random Encounters (to catch wild Pokemon), and Gyms. In the prototype game, I structured the board so that only one of each appeared at a time. However, with the way that the flow is configured, the game could support all of them occurring on a single tile, and the order of the events would still need to occur in a satisfactory way. For example, I would like a Pokecenter to heal my buddy Pokemon before trying to catch that really rare but really strong Pokemon that just appeared on the same tile. This is only a hypothetical scenario of course but I wanted to maintain the flexibility.

For each separate point of interest, the new state will be responsible for determining whether or not the criteria is met to take an action. For example, when we enter the “Pokecenter” state, the code will need to look at the current player’s position on the board. It will check that board tile for the presence of a “Pokecenter” component and if found, it will apply any system actions and display any screens which are relevant. Otherwise, it will simply pass the flow on to the next state.

Encounter Flow

If the random encounter system should spawn a Pokemon on your journey, then you will see a screen asking whether or not you want to try to capture it. Perhaps it is a strong Pokemon and your buddy is already injured, or perhaps you simply don’t want to bother with another low level creature – you might want to ignore the encounter. The menu will allow you to skip everything, and we can jump straight to the “Complete” step and move on.

If you do want to attempt a capture, then you will engage the Pokemon in a battle. There is a battle loop, where the active Pokemon can choose what kind of attack to perform, and as long as the other Pokemon is not KO’d then the loop will continue.

At any point in the battle, you can use the command menu to attempt the capture – you will throw your Pokeball and hope for success. The lower the Pokemon’s hit points, the higher your chance to catch it. If you want to be 100% sure to catch it, then you should get a KO first. In this flow, even if the wild Pokemon should KO your own buddy Pokemon, the flow will still move on to the Capture screen. If you managed to do enough damage, you might still have a good chance of capture.

Gym Flow

The gym flow has a few bits in common with the encounter flow – they both include a battle. However, the gym battles are more involved. At the start, you have a menu that lets you choose whether or not you are ready to challenge the gym. If you are, you will see another screen where you assemble your attack team. The gym battles are 2 on 2 matches – you can use up to two of your Pokemon in the attempt to defeat both of the gym’s defenders. If the match is going poorly you can always “Retreat” so that you don’t have to use as many “Revive” and “Potion” resources to get back to normal. Otherwise, you can battle on! After a KO, the flow will check if the team has another Pokemon ready to fight. If not, then the battle will be over and we show a win or lose screen accordingly. Defeating a gym gives the player a badge, and the first player to acquire four badges wins the game.

Flow Controller

There are many ways that the flow could be implemented. Some might use a bunch of independent controllers which cooperate sequentially through notifications or events, others might try to use Unity’s Animation Controller and model a state machine that looked like our flow chart. You may have other ideas as well, but in this project I decided to try a new approach for myself and have a single controller that was responsible for the entire flow.

Initially you might be concerned that the controller will end up too large, or will need to handle too many jobs. However, it really has one job – to control the flow of the app. However, control of the app really just means telling other view controllers when to appear, or telling a game system when to activate. The view controllers and systems can each go much further in scope and code as necessary to complete the task relevant to the state of the flow controller.

If you look at the root of the hierarchy in the “Game” scene in Unity, the “FlowController” script has been attached to the “Master Controller” game object. All of the view controllers are descendants of this object. The flow controller maintains references to all of the view controllers which it will need to trigger. It also maintains a reference to the models like the current “game” or active “battle” that the systems and view controllers might need to interact with. The flow controller can pass the models on as necessary when showing the view controller or activating a system.

The Flow Controller also holds a “State Machine” which is based on my old Partial Class State Machine concept. I have modified and simplified the code since that post, so take a look at the scripts in the Scripts/Common/State Machine folder if you are interested. By using these classes all of the states of the flow controller are created with injected functionality from the flow controller itself. It will allow me access to all of the fields and properties of the controller as well as the sibling states, etc. and all without needing to make or pass along additional references while creating those states. Each state will appear in its own file even though its code is part of the flow controller class. You can get an idea of what it will look like by expanding the Scripts/Controller/FlowController/States folder in the Project pane.

We wont cover all of the implementation of this controller now, because there are too many other things which remain un-implemented. Instead, we will revisit its states repeatedly as we cover each step of the project. However, I can show a sample template of what a state implementation could look like. Below is a fake state implementation for a state called “Foo”:

public partial class FlowController : MonoBehaviour {
	State FooState {
		get {
			if (_fooState == null)
				_fooState = new State(OnEnterFooState, null, "Foo");
			return _fooState;
		}
	}
	State _fooState;

	void OnEnterFooState () {
		// Do stuff here
	}
}

If I were creating this state, I would add a new code file by the same name, “FooState” to somewhere within the “FlowController” folder hierarchy (wherever it was used). Note that the class definition includes the keyward “partial” and the class name isn’t “FooState” but is “FlowController” instead. There is a property definition called “FooState” which is lazily loaded to create the “_fooState” field member, using a similiarly named “OnEnterFooState” method as its enter action. In this example I didn’t need an exit state, so I left it null, and I gave the state a label named “Foo” – this label is serializable and allows you to see what state is active when using the Unity inspector in “Debug” mode. I use this basic naming convention all over. To create the “Intro” state, I would simply do a search and replace of all the Foo’s for Intro’s.

Summary

In this lesson I talked a bit about flow charts, their symbols and how I created them. I also provided the flow charts for the entire game prototype, and briefly discussed each one. Then I explained how the flow charts would be implemented as part of a Flow Controller class with a state machine.

I didn’t cover any real code in this post, although the project repo has been updated to better reflect how the flow controller’s states will be implemented as we go. I have deleted some placeholder scripts, added and moved others, etc. Not all of it was necessary but I like to keep things organizaed.

Don’t forget that there is a repository for this project located here. Also, please remember that this repository is using placeholder (empty) assets so attempting to run the game from here is pretty pointless – you will need to follow along with all of the previous lessons first.

Leave a Reply

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