Tic Tac Toe: Setup
In this tutorial, we will be setting up a project for implementation of a small Tic Tac Toe game. The game will be written in C++ with the help of CMake and the SFML library. The setup below is expected to be working on macOS only. This is a step-by-step tutorial, some steps might look too verbose.
Prerequisites
This tutorial assumes that the system has C++ compiler, git, CMake and text editor/IDE already installed. The easiest way to get all that is to install Homebrew package manager and/or Xcode.
Quick check if everything is installed correctly:
clang++ -v
cmake --version
git --version
If none of the commands returned something like Command not found
, we're
ready to go.
Setting up a project
First, we need to create a folder for the project and initialize an empty git repository. The Git repository is optional. However, it will help us later with dependency management using Git Submodules. Open the terminal and type:
mkdir tictactoe
cd $_
git init
Output should indicate that the empty git repository was initialized.
Next, let's set up an empty C++ project. We will need to create a few folders and CMake configuration file:
mkdir bin
touch CMakeLists.txt
touch main.cpp
The bin
folder will be used to store compiled binary of the game.
Let's populate main.cpp
with a simple C++ program:
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return EXIT_SUCCESS;
}
To build this program, we'll need to add CMake configuration
into CMakeLists.txt
:
cmake_minimum_required(VERSION 3.24)
project(tictactoe VERSION 0.0.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
set(PROJECT_OUTPUT_BIN_DIR "${PROJECT_SOURCE_DIR}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_BIN_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_OUTPUT_BIN_DIR}")
add_executable(${PROJECT_NAME} main.cpp)
This CMake configuration specifies to use C++17 to compile the program,
redirects executable to be put to bin
folder and also turns off deprecated
warnings (-Wno-deprecated-declaration
) as SFML compilation generates quite a
lot of those on macOS, mostly because of OpenGL.
At this point, it should be possible to bootstrap the project and build it:
mkdir build
cmake -S . -B ./build
cmake --build ./build
After the project is built successfully, just run it from the terminal:
./bin/tictactoe
The program should print Hello, World!
and exit.
The next step is to add the SFML library to the project. There are many ways to do that, including installing pre-built shared libraries using a package manager. I went with Git Submodules and building library locally as it's more convenient if a project will need cross-platform support or quick update to the latest version of the dependency (stable release of the SFML was done in 2018, for example, and does not have a few needed fixes for macOS).
First, we need to create a folder for the Git Submodules:
mkdir vendor
The other popular name for the folder is third_party
or dependencies
, I'll
go with vendor
.
The second step is to add the SFML library repository as a submodule and switch to a specific commit. This tutorial assumes the same state of SFML library is used. The latest version of SFML support is not guaranteed.
git submodule add https://github.com/SFML/SFML.git ./vendor/SFML
cd ./vendor/SFML
git checkout 938e90b7d2b345d06783ba88fe8d8e1ca2f09855
cd ../..
At this point, we should have SFML library pinned to a specific commit added as a submodule to our repository.
The next step is to integrate the SFML library into the project. To accomplish
that CMakeLists.txt
needs to be changed:
# ...
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_OUTPUT_BIN_DIR}")
# new lines:
include_directories(vendor/SFML/include)
set(SFML_USE_STATIC_STD_LIBS TRUE)
set(BUILD_SHARED_LIBS FALSE)
add_subdirectory(vendor/SFML)
This will add the SFML library as a subproject. Next, we need to link libraries to our executable:
# ...
add_executable(${PROJECT_NAME} main.cpp)
# new lines:
target_link_libraries(${PROJECT_NAME}
sfml-graphics
sfml-window
sfml-graphics
sfml-system
sfml-audio)
The final CMakeLists.txt
should look like this:
cmake_minimum_required(VERSION 3.24)
project(tictactoe VERSION 0.0.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
set(PROJECT_OUTPUT_BIN_DIR "${PROJECT_SOURCE_DIR}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_BIN_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_OUTPUT_BIN_DIR}")
include_directories(vendor/SFML/include)
set(SFML_USE_STATIC_STD_LIBS TRUE)
set(BUILD_SHARED_LIBS FALSE)
add_subdirectory(vendor/SFML)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME}
sfml-graphics
sfml-window
sfml-graphics
sfml-system
sfml-audio)
Before adding SFML-related code to the game, let's check that the project builds without any issues from the root of the project:
cmake --build ./build
It should build the whole SFML library and statically link it to our empty project.
Now we're ready to add the basic SFML code to our game, replace main.cpp
contents with the next code:
#include <SFML/Graphics.hpp>
int main() {
sf::Vector2u windowSize{300, 300};
sf::RenderWindow window{sf::VideoMode{windowSize}, "Tic Tac Toe"};
while (window.isOpen()) {
sf::Event event{};
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) { window.close(); }
if (event.type == sf::Event::KeyPressed &&
(event.key.code == sf::Keyboard::Escape)) {
window.close();
}
}
window.clear(sf::Color::Black);
window.display();
}
return EXIT_SUCCESS;
}
Let's build and run the code above:
cmake --build ./build
./bin/tictactoe
The result should be a small empty window:
Press escape to exit the game.
It's time to commit all the changes. Let's first create .gitignore
file:
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# CLion
cmake-build-debug
cmake-build-release
# Executable
bin/*
!bin/.gitkeep
Pay attention to the last two lines. Those two are needed to ignore any contents
of the bin
folder but allow bin
folder to be committed to the repository.
The final step is to create an empty .gitkeep
file in the bin
folder:
touch ./bin/.gitkeep
Now we can commit the changes:
git add -A
git commit -m "Initial commit"
Done!
Link to the project on GitHub: https://github.com/i9or/tictactoe
In this tutorial, we've set up a basis for the C++ game using SFML. In the next part, we will try to draw graphics and add basic game logic. That's all for now, have a good one!
☙