NOGDUS

Articles, Tutorials, and other things. => SDL Game Programming => Topic started by: Richard Marks on March 07, 2009, 07:25:37 PM



Title: C++ and SDL Linux Game Development
Post by: Richard Marks on March 07, 2009, 07:25:37 PM
C++ and SDL Linux Game Development

I am going to assume a few things.
First; You are using ubuntu.
Second; You possess the knowledge of how to use your Linux system like running programs, installing, etc.

We will be needing these tools:
  • g++
  • scons
  • git
  • giggle
  • gedit
  • wget
  • SDL
  • SDL_image
  • SDL_mixer
  • Ruby
  • ImageMagick

If you don't have any of the aforementioned tools then find the right command below and execute it in a terminal.
Code:
$ sudo apt-get install binutils
$ sudo apt-get install g++
$ sudo apt-get install scons
$ sudo apt-get install git
$ sudo apt-get install giggle
$ sudo apt-get install gedit gedit-plugins
$ sudo apt-get install wget
$ sudo apt-get install libsdl1.2-dev
$ sudo apt-get install libsdl-image1.2-dev
$ sudo apt-get install libsdl-mixer1.2-dev
$ sudo apt-get install ruby1.8 ruby-full
$ sudo apt-get install imagemagick

Now, lets get our project directory setup.
I recommend you follow this to the letter.

Code:
$ cd ~/
$ mkdir Projects
$ cd Projects
$ mkdir SDLShooter
$ cd SDLShooter
$ mkdir src include docs release
$ mkdir release/data
$ mkdir release/data/graphics
$ touch readme.txt changes.txt SConstruct src/main.cpp src/SDLShooter.cpp include/SDLShooter.h
$ convert -size 640x480 plasma:fractal release/data/graphics/background.png
$ git init
$ git add .
$ git commit -a

You will be in an editor called Nano.
Type in "initial project started" hit ENTER, then press CTRL+O and hit ENTER to save changes then press CTRL+X to exit.

Now, we open all our source files and our build script into gedit:

Code:
$ gedit src/*.cpp include/*.h SConstruct &

Now we add our project's framework code.

main.cpp
Code:

// CODESTYLE: v2.0

// main.cpp
// Project: SDLShooter Project (SHOOTER)
// Author: Richard Marks

// C STANDARD LIBRARY
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cctype>
#include <cstdarg>

// STL
#include <vector>
#include <string>
#include <map>
#include <algorithm>

// SDL
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

// GAME
#include "SDLShooter.h"

int main(int argc, char* argv[])
{
// instance the game class
SHOOTER::Game game;

// init game
if (game.Initialize(argc, argv))
{
// make sure SDL exits correctly
atexit(SDL_Quit);

// start the main loop
game.Execute();

// clean up
game.Destroy();
}
else
{
fprintf(stderr, "Game Init Failed!\n");
}

// return to the OS
return 0;
}



SDLShooter.h
Code:

// CODESTYLE: v2.0

// SDLShooter.h
// Project: SDLShooter Project (SHOOTER)
// Author: Richard Marks
// Purpose: all game class definitions

#ifndef __SDLSHOOTER_H__
#define __SDLSHOOTER_H__

struct SDL_Surface;
union SDL_Event;

namespace SHOOTER
{
class Game
{
public:
/// constructor -- only purpose is to init every pointer to zero
Game();

/// destructor -- has no purpose. use Destroy() method
~Game();

// inits the game
bool Initialize(int argc, char* argv[]);

/// the main game loop
void Execute();

/// clean up after everything
void Destroy();

private:
/// stops the main loop
void Stop();

/// begin drawing the scene (clears the entire screen to black)
void BeginScene();

/// no drawing should take place after this (flips screen buffers so we see what we have drawn)
void EndScene();

private:
/// the SDL screen
SDL_Surface* mainScreen_;

/// the SDL event
SDL_Event* mainEvent_;

/// used by the main loop to tell if we should end it or not
bool gameIsRunning_;

}; // end class

} // end namespace
#endif


SDLShooter.cpp
Code:

// CODESTYLE: v2.0

// SDLShooter.cpp
// Project: SDLShooter Project (SHOOTER)
// Author: Richard Marks
// Purpose: all game class definitions

// C STANDARD LIBRARY
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cctype>
#include <cstdarg>

// STL
#include <vector>
#include <string>
#include <map>
#include <algorithm>

// SDL
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

#include "SDLShooter.h"


namespace SHOOTER
{
Game::Game() :
mainScreen_(0),
mainEvent_(0),
gameIsRunning_(false)
{
}

////////////////////////////////////////////////////////////////////////////

Game::~Game()
{
}

////////////////////////////////////////////////////////////////////////////

bool Game::Initialize(int argc, char* argv[])
{
// initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
// log the error
fprintf(stderr, "SDL Library Initialization Failed!\n\tSDL Error: %s\n", SDL_GetError());

// return failure
return false;
}

// initialize the screen
mainScreen_ = SDL_SetVideoMode(800, 600, 24, SDL_HWSURFACE | SDL_DOUBLEBUF);

if (!mainScreen_)
{
// log the error
fprintf(stderr, "SDL Screen Initialization Failed!\n\tSDL Error: %s\n", SDL_GetError());

// return failure
return false;
}

// set the window caption
SDL_WM_SetCaption("SDLShooter -- An SDL game project by Richard Marks <ccpsceo@gmail.com>", 0);

// create the SDL event handler instance
mainEvent_ = new SDL_Event;
if (!mainEvent_)
{
// log the error
fprintf(stderr, "Unable to create event handler instance!\n");

// return failure
return false;
}

// start our engines ^-^
gameIsRunning_ = true;

// return success
return true;
}

////////////////////////////////////////////////////////////////////////////

void Game::Destroy()
{
#define _TMP_DELOBJ(object) if (object) { delete object; object = 0; }

// we do NOT delete the mainScreen_ variable because SDL does that itself!
_TMP_DELOBJ(mainEvent_)

#undef _TMP_DELOBJ
}

////////////////////////////////////////////////////////////////////////////

void Game::Execute()
{
// better input handling
const int MOTIONBUTTON_UP = 0x0;
const int MOTIONBUTTON_DOWN = 0x1;
const int MOTIONBUTTON_LEFT = 0x2;
const int MOTIONBUTTON_RIGHT = 0x3;
bool motionButtonDown[4] = { false, false, false, false };

// main loop
while(gameIsRunning_)
{
// process the events
while(SDL_PollEvent(mainEvent_))
{
switch(mainEvent_->type)
{
// the window was closed
case SDL_QUIT:
{
// stop the engine
this->Stop();
} break;

// a key was pressed
case SDL_KEYDOWN:
{
// what key is down
switch(mainEvent_->key.keysym.sym)
{
case SDLK_ESCAPE:
{
// stop the engine
this->Stop();
} break;

case 'w':
case 'W':
case SDLK_UP:
{
motionButtonDown[MOTIONBUTTON_UP] = true;
} break;

case 's':
case 'S':
case SDLK_DOWN:
{
motionButtonDown[MOTIONBUTTON_DOWN] = true;
} break;

case 'a':
case 'A':
case SDLK_LEFT:
{
motionButtonDown[MOTIONBUTTON_LEFT] = true;
} break;

case 'd':
case 'D':
case SDLK_RIGHT:
{
motionButtonDown[MOTIONBUTTON_RIGHT] = true;
} break;

default: break;
} // end switch
} break;

// a key was released
case SDL_KEYUP:
{
// what key is up
switch(mainEvent_->key.keysym.sym)
{
case 'w':
case 'W':
case SDLK_UP:
{
motionButtonDown[MOTIONBUTTON_UP] = false;
} break;

case 's':
case 'S':
case SDLK_DOWN:
{
motionButtonDown[MOTIONBUTTON_DOWN] = false;
} break;

case 'a':
case 'A':
case SDLK_LEFT:
{
motionButtonDown[MOTIONBUTTON_LEFT] = false;
} break;

case 'd':
case 'D':
case SDLK_RIGHT:
{
motionButtonDown[MOTIONBUTTON_RIGHT] = false;
} break;
default: break;
}
} break;

default: break;
} // end switch
} // end while


////////////////////////////////////////////////////////////////////
// update game objects
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// render game
////////////////////////////////////////////////////////////////////

// begin the scene
this->BeginScene();

// draw objects here

// end the scene
this->EndScene();

// reduce the cpu hoggingness of SDL ^-^
SDL_Delay(20);


} // end while -- main loop
}

////////////////////////////////////////////////////////////////////////////

void Game::Stop()
{
gameIsRunning_ = false;
}

////////////////////////////////////////////////////////////////////////////

void Game::BeginScene()
{
SDL_FillRect(mainScreen_, 0, SDL_MapRGB(mainScreen_->format, 0, 0, 0));
}

////////////////////////////////////////////////////////////////////////////

void Game::EndScene()
{
SDL_Flip(mainScreen_);
}

} // end namespace


Finally, here is the SConstruct file that will build our project:

SConstruct
Code:
#
# SConstruct
# this scons build script produces the executable for the project
################################################################################
# a little preparation for building an SDL project
buildEnv = Environment(CCFLAGS = '-g -Wall')
projectConfig = {}
buildEnv.ParseConfig('sdl-config --cflags --libs')

################################################################################
# this is the file name of the executable file to output
projectConfig['executable'] = 'GameExe'
################################################################################
# if you need to look in special folders for include files add them here
projectConfig['include path'] = Split("""
.
./include/
""")
################################################################################
# if your libs are in special locations set their paths here
projectConfig['library path'] = Split("""
""")
################################################################################
# if you need to link against other libs, add them here
projectConfig['libraries'] = Split("""
SDL_image
""") + buildEnv['LIBS']
################################################################################
# add your sources for your project here
projectConfig['sources'] = Glob('src/*.cpp')
################################################################################
buildEnv.Program('release/'+projectConfig['executable'], projectConfig['sources'],
LIBS = projectConfig['libraries'],
LIBPATH = projectConfig['library path'],
CPPPATH = projectConfig['include path'])
################################################################################

Save everything.
Now, in your terminal:

Code:
$ scons
$ cd release
$ ./GameExe

Cool eh? 8)