Pages

Wednesday, December 29, 2010

Code::Blocks(5) C++ SDL and Life "life.cpp"

Here is the code for the main program file, just copy and paste into file life.cpp in the project, then save the project:

#include <SDL/SDL.h> //SDL library
#include <SDL/SDL_image.h> //+SDL_image library (I use it for loading .png files)

#include "engine.h" // The simple engine class

#include <sstream> // I use it to work with text streams

int main ( int argc, char** argv ) //when you use a SDL c++ app you have to initialize main that way
{

Engine myengine; //Create a object from the type "Engine"
myengine.SetVga(); //Start graphics mode
myengine.LoadTileset(); //Load the image tileset to a SDLSurface

std::stringstream text; //Variable used to display text
Uint8 CellMap[50][50]; //The cell map, here qe store the cell state
Uint8 x,y; //variables used to travel across the cell array
int xmax, ymax; //Max size of tiles to display on screen
Uint8 Counter; //Counter of the surrounding cells
bool Paused; //Game paused?

Paused=false;//Let's start with the game running

xmax=myengine.ScreenX / myengine.TileSize; //calculate maximun number of cells (x-width)
ymax=myengine.ScreenY / myengine.TileSize; //calculate maximun number of cells (y-height)

 for (x=0;x<50;x++){
    for (y=0;y<50;y++){
        CellMap[x][y]=0; //clean the cell map so everything is "0"
    };//end y for
 };//end x for

//I put just 5 cells, into a "slider" configuration
CellMap[1][3]=1;
CellMap[2][3]=1;
CellMap[3][3]=1;
CellMap[3][2]=1;
CellMap[2][1]=1;



    // program main loop
    bool done = false;
    while (!done) // will loop infinite times until we set done = true
    {
        // message processing loop
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            // check for messages
            switch (event.type)
            {
                // exit if the window is closed
            case SDL_QUIT:
                done = true;
                break;

                // check for keypresses
            case SDL_KEYDOWN:
                {
                    // exit if ESCAPE is pressed
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        done = true;
                    break;
                }
            } // end switch
        } // end of message processing



myengine.Frames++;//increase frame counter

myengine.FillColour(200,200,200);//Clear screen with grey color
if (myengine.TimeElapsed()>=1000) // every second (1000ms)
{
    myengine.UpdateTimer(); // reset time counter
    myengine.FPS = myengine.Frames; // update the frames per second counter
    myengine.Frames=0; // reset frame counter

    text.str(""); //clean variable "text"
    text << "FPS:" << myengine.FPS; //will set text = "FPS: number"
    SDL_WM_SetCaption(  text.str().c_str(), NULL ); //set the title of the window to "text">>"FPS: number"

if (Paused==false){ //If the game is not paused, process cell map (step 1)
    for (x=1;x<=(xmax-1);x++){
        for (y=1;y<=(ymax-1);y++){
            Counter=0;//now we count the number of surrounding cells
            if (CellMap[x-1][y-1]==1 or     CellMap[x-1][y-1]==3)Counter++;
            if (CellMap[x-1][y]==1 or       CellMap[x-1][y]==3)Counter++;
            if (CellMap[x-1][y+1]==1 or     CellMap[x-1][y+1]==3)Counter++;
            if (CellMap[x][y-1]==1 or       CellMap[x][y-1]==3)Counter++;
            if (CellMap[x][y+1]==1 or       CellMap[x][y+1]==3)Counter++;
            if (CellMap[x+1][y-1]==1 or     CellMap[x+1][y-1]==3)Counter++;
            if (CellMap[x+1][y]==1 or       CellMap[x+1][y]==3)Counter++;
            if (CellMap[x+1][y+1]==1 or     CellMap[x+1][y+1]==3)Counter++;

            if (CellMap[x][y]==0 and Counter==3)CellMap[x][y]=2; //Born
            if (CellMap[x][y]==1){
                if (Counter<2 or Counter >3)CellMap[x][y]=3; //Die
                };

            //myengine.BlitTileset(x,y,CellMap[x][y]);  >>DISABLED

        }; //End for y
    };  //End for x

    //myengine.Flip();                                  >>DISABLED

}//enf if pause
}//end if time elapsed >= 1 second


for (x=1;x<=(xmax-1);x++){//Process cell map (step 2)
    for (y=1;y<=(ymax-1);y++){

        if (CellMap[x][y]==2)CellMap[x][y]=1; //Born
        if (CellMap[x][y]==3)CellMap[x][y]=0; //Die

        myengine.BlitTileset(x,y,CellMap[x][y]); //Display cell on screen
    };
 };


myengine.UpdateMouse();//update x and y mouse position + mouse buttons pressed

if(myengine.MouseButtons ==SDL_BUTTON(SDL_BUTTON_LEFT)){//Pressed left mouse button
    int sx,sy;
    /*   That code shows how to do a simple mouse maping:
    we have the physicall position where mouse is (myengine.MouseX,myengine.Mousey)
    but we need to know which tile correspond to that physicall position
    so we make an integer division between mouse (x, y) and the tilesize,
    the resulting sx, and sy is the tile where we have our mouse cursor    */
    sx=myengine.MouseX/myengine.TileSize;
    sy=myengine.MouseY/myengine.TileSize;

    //swap cell state: dead>living living>dead
    if(CellMap[sx+1][sy+1]==0) //It the cell is dead
        {
            CellMap[sx+1][sy+1]=1;//Cell is living
        }else{ //else cell is living
            CellMap[sx+1][sy+1]=0;//kill the cell
        }

    text.str("");//clean variable "text"
    text << "Left mouse pressed at:X:" << sx <<  " Y: "<< sy;//will set text = "Left mouse pressed at:X: number Y: number"
    SDL_WM_SetCaption(  text.str().c_str(), NULL );//set the title of the window to "text">>"Left mouse pressed at:X: number Y: number"

};//end left mouse button if

if(myengine.MouseButtons ==SDL_BUTTON(SDL_BUTTON_RIGHT) ){//Pressed right mouse button
    if (Paused ==true)//if the game is paused
        {
            Paused =false;//continue game
        }else{
            Paused=true;//else the game is running , pause it
        };
   if (Paused==true) SDL_WM_SetCaption( "PAUSED" , NULL );//if the game is paused, show it in the title bar
};//end right mouse button if

myengine.Flip();//Finally, update the screen from the back buffer :)
myengine.Wait(1); //prevent application from freezing OS
    } // end main loop

myengine.~Engine(); //Destroy object myengine >> that will free the SDSSurfaces and close SDL

return 0; //Everything is ok
}

Code::Blocks(4) C++ SDL and Life "engine.cpp"

Here is the code for the engine class implementation, just copy and paste into file engine.cpp in the project, then save the project:

#include "engine.h"

Engine::Engine()//Create the class and assign default values
{

SDL_Init( SDL_INIT_VIDEO ); //We start SDL, just video at the moment

screen=NULL;
tileset=NULL;

SDL_WM_SetCaption( "Life Game - Tile test", NULL ); //Caption of the window

SDL_ShowCursor(SDL_DISABLE); // hide system mouse

TileSize =50; // size of the default tile 50 pixels x 50 pixels

ScreenX=800; //screen width
ScreenY=600; //screen height
bpp=32; //screen bpp

StartTick = SDL_GetTicks();//Initialize timer
Frames=0; //Initialize frames = 0
}

Engine::~Engine()//Destructor
{
    //Free all the surfaces
    if (screen!=NULL)SDL_FreeSurface(screen); //Free screen surface
    if (tileset!=NULL)SDL_FreeSurface(tileset); //Free tileset surface

    SDL_Quit(); //Close SDL
}

void Engine::SetVga() // set video mode
{
screen = SDL_SetVideoMode(ScreenX, ScreenY, bpp,SDL_SWSURFACE|SDL_DOUBLEBUF);
/* It will set up a windowed video mode (width=screenx, height = screeny, bpp = bpp)
if we want to use a fullscreen mode we have to add
"|SDL_FULLSCREEN" after SDL_DOUBLEBUF  */
}

void Engine::FillColour(Uint8 r, Uint8 g, Uint8 b)//Fill the screen with a colour
{
    SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, r, g, b));// r-ed, g-reen,b-lue
}

void Engine::Flip()//flips backbuffer into primary buffer(screen)
{
    SDL_Flip(screen);
}

void Engine::LoadTileset() //loads an image into a memory (tileset), assigns the colorkey
{
    SDL_Surface* TmpSurface = NULL; //Temporary surface for loading
    TmpSurface = IMG_Load( "tileset.png"); //Load the image into a temporary surface
    if( TmpSurface != NULL )
    {
        tileset= SDL_DisplayFormat( TmpSurface );//optimize surface
        SDL_FreeSurface( TmpSurface); //free temporary surface
    }
    SDL_SetColorKey(tileset,SDL_SRCCOLORKEY | SDL_RLEACCEL,SDL_MapRGB(screen -> format, 255, 0, 255)); //set the color key
}

void Engine::UpdateMouse()
{
MouseButtons = SDL_GetMouseState(&MouseX, &MouseY); //Update mouse state
SDL_Rect start,end;
//set the cliping for the source surface (the tileset)
start.x= 200;
start.y=0;
start.w=TileSize;
start.h=TileSize;
//set the cliping for the destination surface (the screen)
end.x = MouseX;
end.y = MouseY;
end.w = TileSize;
end.h = TileSize;
SDL_BlitSurface(tileset, &start, screen, &end); //Blits the mouse pointer into the screen
}

void Engine::BlitTileset(int x, int y, int tile) //Blits a tile from our tileset to the screen
{
SDL_Rect start,end;
//set the cliping for the source surface (the tileset)
start.x= tile*TileSize;
start.y=0;
start.w=TileSize;
start.h=TileSize;
//set the cliping for the destination surface (the screen)
end.x = (x-1)*TileSize;
end.y = (y-1)*TileSize;
end.w = TileSize;
end.h = TileSize;
SDL_BlitSurface(tileset, &start, screen, &end); //Blits a tile from our tileset to the screen
}

void Engine::Wait(Uint32 ms) //Just pause for ms miliseconds
{
    SDL_Delay(ms);
}

int Engine::TimeElapsed() //Count time elapsed
{
    return SDL_GetTicks() - StartTick;
}

void Engine::UpdateTimer() //Reset time counter
{
    StartTick = SDL_GetTicks();
}

Code::Blocks(3) C++ SDL and Life "engine.h"

Here is the code for the engine class header, just copy and paste into file engine.h in the project, then save the project:


#ifndef ENGINE_H
#define ENGINE_H

#include <SDL/SDL.h> //SDL library
#include <SDL/SDL_image.h> //+SDL_image library (I use it for loading .png files)

class Engine
{
    public:

    SDL_Surface* screen; //The screen
    SDL_Surface* tileset; //A simple tileset for testing purposes only

    int ScreenX;//Width of the screen
    int ScreenY;//Height of the screen
    int bpp;//Bit Per Pixel (colour depth)

    int MouseX; //Mouse x position
    int MouseY; //Mouse y position
    Uint8 MouseButtons; //Mouse button pressed

    int Frames; //Actual frame
    int FPS;      //Frames per second
    int StartTick;
    int LastTick;

    Uint8 TileSize; //size of the default tile


        Engine(); //creator
        virtual ~Engine(); //destructor
        void SetVga(); //Set the video mode
        void FillColour(Uint8 r,Uint8 g,Uint8 b); //fill screen with a colour
        void Flip(); //Flips the backbuffer to the primary buffer
        void LoadTileset(); //loads a test tileset
        void UpdateMouse(); //refresh mouse position and buttons pressed
        void BlitTileset(int x,int y, int tile); // Blit a tile from our tileset to the screen
        void Wait(Uint32 ms); //waits ms miliseconds
        int TimeElapsed(); //Get the time passed since last time control
        void UpdateTimer(); //Update the start time control
    protected:
    private:
};

#endif // ENGINE_H

Wednesday, December 22, 2010

Code::Blocks(2) C++ SDL and Life

Now it's time to open Code::Blocks:
-Go to "Applications" > "Programming" > "Code::Blocks"



The first time we open Code::Blocks it will ask you which compiler to use, we have to select the GNU GCC compiler:
Now we have the start screen and a tip window will pop up, close the tips window and you will see basically four areas:
    • On the left, the current project files (header (.h) and source (.cpp))
    • On the right the code from the opened files
    • On the top, the menus and the toolbars
    • On the bottom, Code::Blocks messages, such as debugger messages, etc.
Now we are going to create the project, select "File" > "New"  > "Project" :


Select "Empty project" and press "Go"



Just press "Next"



Now write the project name (i have used "Life"), then select where do you want to save it (which folder) and press "Next" again.




Defaults are ok now, press "Next"





We have a new, empty project, let's add the first file, press the new button:


And select "Empty file", then press "Yes" to save the new file




This project is going to have three files:
  1. life.cpp
  2. engine.h
  3. engine.cpp
life.cpp is the main program, engine.h is the simple engine header, and engine.cpp the implementation, let's start first to code the engine, so write "engine.h" and "save"


Finally, we have to tell code::block to include the file in the project, so it can compile and debug them properly, just press ok


Notice now the workspace "Life" has a new folder "headers" inside you will find the new file "engine.h", time to create the other two files and save them:

-Press "New file" > "empty file" > "yes"> write the name (engine.cpp then life.cpp) and "save" , "ok"

Project should look like that now:


Now let's open "Project" > "Build options",In  "Linker settings" > "Other linker options" write: -lSDL -lSDL_image, that will make the compiler to link the program against the right libraries (SDL and SDL_image).



Last thing before we start to write down the c++ code:


Save the upper image as "tileset.png" to the "life" directory, other way the project won't work at all.

In the next 3 posts the code for: "engine.h", "engine.cpp" and finally "life.cpp"

Monday, December 13, 2010

Code::Blocks(1) C++, SDL and Life

Time to finally start using code::blocks, we are going to create a simple first project:



Conway's Game of life

We have a few objectives to accomplish with the tutorial:

  • Use Code::Blocks to create projects, add classes, configure libraries, etc.
  • Setting up SDL with Code::Blocks
  • Creating a simplistic game engine.
  • Loading and displaying a image tile set on the screen.
  • Basic use of mouse, keyboard, timing.



Our prerequisite for the tutorial is a simple tile set image:


I have made it using Gimp, we have 5 different tiles, from left to right: empty cell, living cell, new born cell, death cell and the mouse cursor.


Conway's Game of Life is a simulation of "living" cells, let's suppose our world is a big 2D grid, now let's suppose again that each cell in the grid can have 4 different states :
  • 0 > Empty cell , a void in the map.
  • 1 > A living cell.
  • 2 > A new born cell.
  • 3 > A dying cell.
Actually, only the first to states are really important, the other are only used in an intermediate state to process correctly the map, the time is measured in "ticks" every tick if an empty cell has exactly 3 adjacent living cells will generate a new born cell, and a living cell that has less than 2, or more than 3 adjacent cells will die, I'm going to show a way of making a program to simulate the game with c++ and then i will start with code::blocks + SDL:

//We need a grid to store data, we have a map of 50 x 50 cells
Uint8 CellMap[50][50];

// A temporary counter of surrounding cells 
Uint8 counter;

// Variables used when working with the 2d array "CellMap" 
Uint8 x,y;

//Now let's initialize the array, it's always a very good idea to initialize variables to prevent unexpected results in the program.

 for (x=0;x<50;x++){
     for (y=0;y<50;y++){
         CellMap[x][y]=0; //We will start with an empty map
     }; //end y for
 }; // end x for

//We will start with just 5 living cells in a configuration called "slider"
CellMap[1][5]=1;
CellMap[2][5]=1;
CellMap[3][5]=1;
CellMap[3][4]=1;
CellMap[2][3]=1;

 // program main loop
    bool done = false;
    while (!done) //Will make an infinity loop unless we set done=true
    {
//Clear screen with a light grey
myengine.FillColour(200,200,200);
//FIRST LOOP //x loop for for (x=1;x<50;x++){         //y loop for         for (y=1;y<50;y++){              //Counter of the adjacent cells                        Counter=0;             //Count the number of adjacent living cells             if (CellMap[x-1][y-1]==1 or     CellMap[x-1][y-1]==3)Counter++;             if (CellMap[x-1][y]==1 or       CellMap[x-1][y]==3)Counter++;             if (CellMap[x-1][y+1]==1 or     CellMap[x-1][y+1]==3)Counter++;             if (CellMap[x][y-1]==1 or       CellMap[x][y-1]==3)Counter++;             if (CellMap[x][y+1]==1 or       CellMap[x][y+1]==3)Counter++;             if (CellMap[x+1][y-1]==1 or     CellMap[x+1][y-1]==3)Counter++;             if (CellMap[x+1][y]==1 or       CellMap[x+1][y]==3)Counter++;             if (CellMap[x+1][y+1]==1 or     CellMap[x+1][y+1]==3)Counter++;             //minimum adjacent cells = 0             //maximum adjacent cells = 8             //if a cell has is dead "0" and is surrounded by 3 cells will born             if (CellMap[x][y]==0 and Counter==3)CellMap[x][y]=2; //Born            //if a cell is living "1" and is surrounded by less than 2 cells,            //or more than 3 cells, will die            // the problem is that if we change the state from 0 to 1 or 1 to 0,            //when we continue counting, the results will not be correct, so we           //use a temporary state (2 for new born and 3 for dying cell), so           //when we continue counting adjacent cells the result will be ok                     if (CellMap[x][y]==1){                 if (Counter<2 or Counter >3)CellMap[x][y]=3; //Die                 }                 //draw the cell on the screen                myengine.BlitTileset(x,y,CellMap[x][y]);         }; //End for y     };  //End for x //Update the screen with the back buffer
myengine.Flip();
} //SECOND LOOP //x loop for for (x=1;x<50;x++){         //y loop for         for (y=1;y<50;y++){         //now we clean the map with the final cell state (1 or 0)         if (CellMap[x][y]==2)CellMap[x][y]=1; //Born         if (CellMap[x][y]==3)CellMap[x][y]=0; //Die         //draw the cell on the screen         myengine.BlitTileset(x,y,CellMap[x][y]);     };  }; //update the screen
myengine.Flip();
//wait 50 miliseconds to limit frame rate
myengine.Wait(50);
} //End of main loop

Notice i have written a few lines of code with red color, I'm going to create a c++ class to encapsulate a simple engine so many SDL functions will be integrated in it, making easier the process to write programs; i have removed too code from the program to make it more readable, I will show the complete code later.

On the next post, our first Code::Blocks c++ project!

Software Packages

That is a recompilation of all the needed /recommended / useful packages to use the tutorials:

(In blue the linux / Debian packages, in red link to other sites)

GNU c and c++ compilers:
  • gcc
  • g++

Code::Blocks IDE:
  • codeblocks

SDL library and add ons:
  • libsdl1.2-dev
  • libsdl-image-1.2-dev
  • libsdl-mixer-dev
  • libsdl-net-1.2-dev
  • libsdl-ttf-2.0-dev
The GNU image manipulation program:
  • gimp


Other useful packages:


A nice web browser:
  • Firefox 

A great Version control tool
  • subversion
Make and c-style make
  • make ->Not used in the tutorials, but very useful
  • cmake ->Not used in the tutorials, but very useful
Sprig, the definitive add on library for SDL:
A library to draw almost any shape, scaling and rotating images by Jhony D


Box 2D: 2D physics: