Push Button, Receive Code

Programming tutorials, games, music...free beer.

How to Make a Space Invaders Clone with SFML Part 1

Posted by Mark on Wednesday January 29th, 2014 at 4:36pm
This multi-part tutorial is under construction. The assets are available here:
NASIC Game Assets

Source code is available on Github:
NASIC
 
Simply snag yourself a copy of the source, then unpack the assets into the directory with "main.cpp". I used Code::Blocks with MinGW (g++ version 4.7.2). You should be able to compile this without any trouble if you download and build the latest version of SFML and the latest version of THOR - THOR always matches the master branch of SFML. A compiled Boost (version 1.55 - latest at the time of writing this tutorial) library is also necessary to build the project.

Don't feel like compiling it yourself, or maybe you just wanna take it for a spin? Download this zip file containing the binary and the assets - Enjoy! **NOTE** This build was tested on two laptops running Windows (both Windows 8, I believe) so far with integrated gpu's (Specs on mine: AMD E-300 APU with RADEON HD Graphics). It is almost unplayable on these systems currently because of the horrible integrated graphics cards. I'm looking for a way to run this using the software renderer, bypassing these cards completely, but for now try running it on a machine with a dedicated graphics card if you can.
NASIC Game and Assets - Compiled for Windows

Until the series is complete, site sign-up and comments will be disabled. Thanks for your patience. Until then...cheers!  

Here is some footage of the game to give you an idea of what is to come as far as the details of the tutorial series. I know...the quality is a bit low on the video. The software I used to capture video may need some settings tweaked in order to ratchet up the quality, but until I figure it out this will have to do. ;)



If you're anything like me, one of the games you grew up playing was Space Invaders by Taito. My aim is to walk you through how to create a, hopefully sexier, clone of Space Invaders using c++, SFML graphics library, and the THOR extension for SFML. If at any point you want to grab a copy of the source, check out the repo on github.

The first thing we will need to do is create a substrate through which we can properly organize our game states and the code therein. We will use an adaptation of a Finite State Machine (FSM) for this purpose (I say an adaptation of, because I'm fairly certain that we will break the pure "State" pattern at some point). Although our state machine is admittedly simple and old-school, we don't need anything fancy here. For a description of what an FSM is and is not, this article may be of some assistance.

First, we set up our definition for the game class. It is a pretty simple interface all wrapped up in the namespace "nasic" which stands for "Not Another Space Invaders Clone. Each state is clearly dilineated in the state enum and the states are all mapped to static private methods. These methods are private because there is no need to access them outside of the game class. The use of the "s_" before each state is just a convention to keep things clear. Any convention will do, but you should probably adopt something and keep it consistent. There are only two data members for this class, the state (represented as an sf::Uint32) and the window. The game state (m_state) is declared as static as well as the window. Because there will only be one instance of the game class, there is effectively only one copy of each data member. You should be advised, however, that there is nothing here to stop you from instantiating more than one game class. Why you would want to do this, I don't know - just don't do it. The window will be passed by reference to each game state as we implement classes for each state. As the number of states in your game grows in complexity, you will notice that this design has some limitations. But for a simple game, it will do nicely. Here is our definition (Game.hpp):

#ifndef GAME_HPP
#define GAME_HPP

#include <iostream>
#include <SFML/Graphics.hpp>

namespace nasic
{
    class Game
    {
        public:
            Game();
            ~Game();

            static void init();

    private:
            static void run();

            static void intro();
            static void menu();
            static void options();
            static void info();
            static void level();
            static void win();
            static void lose();

            static bool isQuitting();

            enum state
            {
                s_uninitialized,
                s_intro,
                s_menu,
                s_info,
                s_options,
                s_level,
                s_win,
                s_lose,
                s_quit
            };

        private:
            static sf::Uint32 m_state;
            static sf::RenderWindow m_window;
    };
}

#endif // GAME_HPP

The implementation is quite simple as well. We will implement each function according to the state we are in. For now, it will look something like this (Game.cpp):

#include <Game.hpp>

nasic::Game::Game()
{
    
}

nasic::Game::~Game()
{
    
}

void nasic::Game::init()
{
    using nasic::Game;
    //if the game is not in an uninitialized state
    //when it is first run, bail
    if(!m_state == state::s_uninitialized)
        return;

    sf::VideoMode mode = sf::VideoMode::getDesktopMode();

    m_window.create(sf::VideoMode(mode.width,mode.height,mode.bitsPerPixel), "Not Another Space Invaders Clone", sf::Style::Fullscreen);
    m_state = state::s_intro;

    while(!isQuitting())
    {
        run();
    }
    std::cout<<"Quitting..."<<std::endl;
    m_window.close();
}

bool nasic::Game::isQuitting()
{
    using nasic::Game;
    return m_state == state::s_quit;
}

void nasic::Game::run()
{
    switch(m_state)
    {
    case state::s_intro:
    {
        intro();
        m_state = state::s_menu;
    }
    break;

    case state::s_menu:
    {
        menu();
    }
    break;

    case state::s_info:
    {
        info();
    }
    break;

    case state::s_options:
    {
        options();
    }
    break;

    case state::s_level:
    {
        level();
    }
    break;

    case state::s_win:
    {
        win();
    }
    break;

    case state::s_lose:
    {
        lose();
    }
    break;

    default:
        break;
    }
}

void nasic::Game::intro()
{
    using nasic::Game;
    m_window.setTitle("Intro");
    std::cout<<"Intro State"<<std::endl;

    //create an intro object
    
}

void nasic::Game::menu()
{
    m_window.setTitle("Menu");
    std::cout<<"Menu State"<<std::endl;

    //create a menu object
    
}

void nasic::Game::info()
{
    m_window.setTitle("Info");
    std::cout<<"Info State"<<std::endl;

    //create an info object
    
}

void nasic::Game::options()
{
    m_window.setTitle("Options");
    std::cout<<"Options State"<<std::endl;

    //create an options object
    
}

void nasic::Game::level()
{
    m_window.setTitle("Level");
    std::cout<<"Level State"<<std::endl;

    //create a level object
    
}

void nasic::Game::win()
{
    m_window.setTitle("You Win");
    std::cout<<"Win State"<<std::endl;

    //create a win object

}

void nasic::Game::lose()
{
    m_window.setTitle("You Lose");
    std::cout<<"Lose State"<<std::endl;

    //create a lose object

}

//initialize static member variables
sf::Uint32 nasic::Game::m_state = s_uninitialized;
sf::RenderWindow nasic::Game::m_window;

Most of the implementation for the game class is straight-forward. It consists of a game loop (nasic::Game::run()) with a switch statement that calls functions internally based on the game state. We've also stubbed out places for our state objects - which we will create next. The main gotcha for your implementation is the definition of the static data members. In C++, you must define them somewhere in the implementation file. We do this at the end of the file. For an explanation, see this thread. Finally, we will call our static method "init()" in the main entry point for our game:

#include <iostream>
#include <exception>
#include <Game.hpp>

int main()
{
    try
    {
        nasic::Game::init();
    }
    catch(std::exception& e)
    {
        std::cout<<e.what()<<std::endl;
    }
    return 0;
}

Although it's not much to look at, we have a pretty solid skeleton for our game. It should be clear from above what the basic flow of states in our game will be. In part 2 of this series, we will make a cool intro state to add to our machine.

Go to Part 2