Hello reader!
In this post we’re creating the necessary code to display the game’s board. It should be very easy to understand, so if you have any problems or suggestions please make a comment.
The main loop :
////////////////////////////////////////////////////////////
// main.cpp
////////////////////////////////////////////////////////////
#include
#include "board.h"
int main()
{
// Create main window, using the best available resolution
sf::RenderWindow App(sf::VideoMode::GetMode(0),
"Your first SFML game: 4 in a row!");
// Reduce CPU usage by limiting the times a frame
// is drawn per second
App.SetFramerateLimit(30);
// This is the main loop
// It will loop until you exit the program
while (App.IsOpened())
{
// Here we process the events list
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
}
// Clear the screen with a color
App.Clear();
// Here you will draw all stuff in the frame buffer
// Render the frame on screen
App.Display();
}
return EXIT_SUCCESS;
}
If you compile this code, it will create a black window. This is the base of our code.
To create a board we shall have a class called Board. It should have a method to draw the board on screen, one to restart the game, one to insert tokens in a column and of course one to know if a player has won.
First we include the SFML headers and we define the size of the board:
////////////////////////////////////////////////////////////
// board.h
////////////////////////////////////////////////////////////
#ifndef BOARD
#define BOARD
#include
#define BOARD_Y_SIZE 6
#define BOARD_X_SIZE 7
Then we define some enums that we’ll use later on.
// These are the kind of tokens found in the board
enum Token
{
Empty,
Red,
Yellow,
};
// And these, the outline types of the tokens
enum Outline
{
Normal,
Highlight
};
// Returned when trying to place a token in a column
enum Move
{
Placed,
Full,
EndOfGame
};
Then we define the Board class with the necessary methods.
// This class has all the methods and properties to be used
// in the game board
class Board
{
public:
// Constructor
Board(sf::RenderWindow &App;);
// Destructor
~Board();
// Sets the board to empty tokens
void restart();
// Used to draw the board on screen
void draw();
// Called in each turn
Move addTokenInColumn(unsigned int column, Token playerColor);
// Gets the original window width
int getWindowWidth();
// The color of the gameboard
sf::Color::Color boardColor;
private:
// Used to know if a player has won
bool isEndOfGame (const unsigned int y, const unsigned int x);
bool fourHorizontal(const unsigned int y, const unsigned int x);
bool fourVertical (const unsigned int y, const unsigned int x);
bool fourDiagonal (const unsigned int y, const unsigned int x);
// The matrix that represents the board in memory
// Add borders to ease the search of a winnefr combination
Token board[BOARD_Y_SIZE+2][BOARD_X_SIZE+2];
Outline boardOutline[BOARD_Y_SIZE+2][BOARD_X_SIZE+2];
// The window where to draw the board
sf::RenderWindow &myWindow;
// Colors of the board
sf::Color redColor;
sf::Color yellowColor;
sf::Color emptyColor;
sf::Color lineColor;
sf::Color highlightColor;
// Properties that define the size of a token
float windowHeight;
float windowWidth;
// The size of the outline token brush
float outline;
// The radius of a token
float radius;
// The space between tokens
float spaceY, spaceX;
};
#endif
We proceed then with the implementation. The constructor is a bit long I know;), but it initializes the colors of the board, the size of the tokens and the board itself.
Just a note, myWindow is initialized with the reference of the RenderWindow (the frame where you draw your stuff^^) passed from the main loop :
////////////////////////////////////////////////////////////
// board.cpp
////////////////////////////////////////////////////////////
#include "board.h"
Board::Board(sf::RenderWindow &App;) : myWindow (App)
{
// Set the colors of the board
boardColor = sf::Color::Color(0, 102, 153);
redColor = sf::Color::Color(214, 71, 0);
yellowColor = sf::Color::Color(235,235,0);
emptyColor = sf::Color::Color(224,224,224);
lineColor = sf::Color::Color(0, 51, 102);
highlightColor = sf::Color::Color(255, 153, 0);
// Get the size of the window
// in order to calculate the size of a token
windowHeight = myWindow.GetHeight();
windowWidth = myWindow.GetWidth();
// Get the best circle size
if (windowHeight < windowWidth)
{
radius = windowHeight/(BOARD_Y_SIZE*2.0);
// set the vertical space between circles equal
// to 1/2 of the radius
spaceY = 1.0/2.0 * radius;
// set the outline of the circle as 1/15 of the radius
outline = 1.0/15.0 * radius;
// decrease the radius, by substracting the space
// between circles and its outline
radius = radius - spaceY/2.0 - outline;
// set the horizontal space, knowing that there are
// BOARD_X_SIZE circles and BOARD_X_SIZE + 1 spaces in a row
spaceX = (windowWidth-(BOARD_X_SIZE*2.0)*radius)/(BOARD_X_SIZE + 1.0);
}
else
{
radius = windowWidth/(BOARD_X_SIZE*2.0);
// set the horizontal space between circles equal
// to 1/2 of the radius
spaceX = 1.0/2.0 * radius;
// set the outline of the circle as 1/15 of the radius
outline = 1.0/15.0 * radius;
// decrease the radius, by substracting the space
// between circles and its outline
radius = radius - spaceX/2.0 - outline;
// set the horizontal space, knowing that there are
// BOARD_Y_SIZE circles and BOARD_Y_SIZE + 1 spaces in a row
spaceX = (windowWidth-(BOARD_Y_SIZE*2.0)*radius)/(BOARD_Y_SIZE + 1.0);
}
// Empty the board
restart();
}
// Fill this destructor if needed
Board::~Board(){}
Then, the method to initialize the board itself (the tokens and its outline):
void Board::restart()
{
// Change the value of all the elements of board to Empty
for(int y=0; y0; i--)
{
// add the token (red or yellow) if there is space in the column
if(board[i][column] == Empty)
{
board[i][column] = playerColor;
//Verify if the player has won
if (isEndOfGame(i, column))
return EndOfGame;
else
return Placed;
}
}
// if it ends up here, it means the column is already full
// and the token cannot be placed in the column
return Full;
}
The code that verifies if a player has won, and highlights the winning line(s):
bool Board::isEndOfGame(const unsigned int y, const unsigned int x)
{
// Search for combinations of 4 or more tokens of the same
// color and highlight them
// We create a temp variable to force the call of all the
// four in a row searches, this way, all the combinations
// of four or more tokens get highlighted
bool t = false;
t |= fourHorizontal(y, x);
t |= fourVertical(y, x);
t |= fourDiagonal(y, x);
return t;
}
bool Board::fourHorizontal(const unsigned int y, const unsigned int x)
{
// Search for combinations of 4 or more tokens of the same
// color in a horizontal line
Token tokenColor = board[y][x];
int cnt = 1, i;
// search right the same color tokens
for(i = x + 1; board[y][i]==tokenColor; i++)
cnt++;
// search left the same color tokens
for(i = x - 1; board[y][i]==tokenColor; i--)
cnt++;
// Highlight the winner row
if(cnt>=4)
{
while(board[y][++i] == tokenColor)
boardOutline[y][i] = Highlight;
return true;
}
else
return false;
}
bool Board::fourVertical(const unsigned int y, const unsigned int x)
{
// Search for combinations of 4 or more tokens of the same
// color in a vertical line
Token tokenColor = board[y][x];
int cnt = 1, i;
// search down the same color tokens
for(i = y + 1; board[i][x]==tokenColor; i++)
cnt++;
// search up the same color tokens
for(i = y - 1; board[i][x]==tokenColor; i--)
cnt++;
// Highlight the winner row
if(cnt>=4)
{
while(board[++i][x] == tokenColor)
boardOutline[i][x] = Highlight;
return true;
}
else
return false;
}
bool Board::fourDiagonal(const unsigned int y, const unsigned int x)
{
// Search for combinations of 4 or more tokens of the same
// color in a vertical line
Token tokenColor = board[y][x];
bool t = false;
int cnt = 1, i, j;
// search down-left the same color tokens
for(i = y + 1, j = x - 1; board[i][j]==tokenColor; i++, j--)
cnt++;
// search up-right the same color tokens
for(i = y - 1, j = x + 1; board[i][j]==tokenColor; i--, j++)
cnt++;
// Highlight the winner diagonal
if(cnt>=4)
{
while(board[++i][--j] == tokenColor)
boardOutline[i][j] = Highlight;
t = true;
}
cnt = 1;
// search down-right the same color tokens
for(i = y + 1, j = x + 1; board[i][j]==tokenColor; i++, j++)
cnt++;
// search up-left the same color tokens
for(i = y - 1, j = x - 1; board[i][j]==tokenColor; i--, j--)
cnt++;
// Highlight the winner diagonal
if(cnt>=4)
{
while(board[++i][++j] == tokenColor)
boardOutline[i][j] = Highlight;
return true;
}
else
return t;
}
And finally the code to get the windows width, without having a reference to “the window”:
int Board::getWindowWidth()
{
// Returns the current width of the board/window
// We use this as the UI doesn't have a reference
// to the window (App or myWindow)
return myWindow.GetWidth();
}
This is for the board implementation, it is certainly the biggest part of the game. But hey!, we’re almost finished ;) We just need a user interface, to enable the player to interact with the game, and that’s it. With a few more lines of code, you’ll be able to play you’re first SFML game!!