I now had code written for both the game logic and graphics capabilities, so it was time to put the finishing touches on my application’s first draft. The ‘StandoffApp’ class encapsulates this functionality, marrying together all of the disparate pieces that I had already developed. LazyFoo’s tutorial series proved to be essential once again, this time providing me with a structural template on which to base my SDL_Event input handling loop.
enum Action_e
{
NONE,
PRE_DEPLOY,
DEPLOY,
MOVE,
ROTATE,
SHOOTOUT,
};
void StandoffApp_c::handleLmbDown(const SDL_Event& e)
{
if (mCurrentGame.getCurrentMove().mCurrentAction == Game_n::NONE) {
/* transform the mouse click event's coordinate in pixels into a
* "screen tile" coordinate - for reference, the board's upper left
* hand corner is at (1, 4) in the "screen tile" coordinate system
*/
std::pair<int, int> screen_tile_coord =
std::make_pair(e.button.x / ResourceManager_n::TILE_WIDTH,
e.button.y / ResourceManager_n::TILE_WIDTH);
/* loop through the current player's available pieces (either in reserve
* or in play) to determine if the mouse click event selects a piece
*/
bool piece_hit_flag = false;
const std::vector<Game_n::PiecePtr>& pieces = (mCurrentGame.mCurrentTurn % 2)
? mCurrentGame.getPlayer1Pieces()
: mCurrentGame.getPlayer2Pieces();
std::vector<Game_n::PiecePtr>::const_iterator it;
for (it = pieces.begin(); it != pieces.end(); ++it)
{
if ((*it)->getPosition() == screen_tile_coord &&
(*it)->getPlayState() != Piece_n::DEAD) {
mCurrentGame.setCurrentPiece(*it);
piece_hit_flag = true;
}
}
/* if we did not hit a piece with this click AND a piece is already
* selected, attempt to move the current piece to the click position
*/
if (!piece_hit_flag && mCurrentGame.getCurrentPiece() != nullptr) {
mCurrentGame.move(screen_tile_coord);
}
}
}
The Standoff application functions essentially as a state machine. Once initiated, the game’s main processing loop serves to regulate the set of actions available to the user. The state of the application is determined by two factors: the current action - represented by the Action_e enumeration - and the current turn. Each particular state only allows for the input of certain commands, so the state machine’s progression always proceeds in a deterministic manner. The input handling algorithms - StandoffApp::handleLmbDown and handleKeyDown - provide the validations necessary to ensure that only the appropriate actions are accepted, preventing the state machine from becoming stuck.
After a call to StandoffApp::draw on startup, each iteration of the main loop features a redrawing of the board and pieces. The drawing routine only recognizes pieces that are in play or in reserve; dead pieces remain on the board, to be cleaned up upon exit. The draw method itself simply invokes the ResourceManager’s renderSpriteAt (link to prev page) function for each appropriate piece, in addition to the cursor and the briefcase.

I made sure to include the ability revert a move in an attempt to compensate for the application’s clunky controls. Deploying a piece in particular can require a couple tries to get right, given that this action requires both move and rotate commands to be input in the correct order. Still, the rest of the game’s mechanics feel polished enough, at least for a first pass. The first testing phase has already revealed an array of possible alterations that could be made in the interest of streamlining gameplay.
