Pages

Showing posts with label Life Game. Show all posts
Showing posts with label Life Game. Show all posts

Monday, January 10, 2011

Code::Blocks(6) C++, SDL and Life, Putting all together

Now we have the project ready to compile, just press the "Build and run" project.



If we have configured properly Code::Blocks, installed the libraries and copied the file tileset.png on the same folder we should get that screen:


Finally we made it run! with the left mouse button  we can add more cells to the map and with the right mouse button we pause /continue the game.

Obviously the project is very simple:
(The italic comments are things we are going to change in the following tutorials to upgrade the program)
  • Initialize an instance of the (simple) engine class
  • Set the graphics mode 800x600x32bpp (Set any graphics mode and Full Screen /Windowed mode)
  • Load the tileset image(Load any tileset image)
  • Define an array to store the cells(Load a world map)
  • Process input > cell logic > Drawing
  • The drawing process has those steps:
  1. Fill the backuffer with a colour (clear screen)
  2. Draw the cells (cellmap array)
  3. Draw the mouse
  4. Flip backbuffer to the screen
You can download the complete code::block project including the tileset.png file in the new "Downloads" page in the blog.

If you have read the code from the tutorials, and the previous posts now you should be able to create a new project with code::blocks and you should have an idea about using the sdl library: Initializing a graphic mode, loading images to surfaces, blitting those surfaces to the screen..

I don't want to get deeper into those topics because other people have already made very good tutorials about that (links in the sidebar), what i really want is to play with the pieces that will build later the game , we should have learned how to build a map with an array and how to draw the map on the screen.

In the next tutorial we will go a step beyond: Draw our "hero" on the screen in a multi-layered map using keyboard to move it, controlling the obstacles in the terrain, and drawing stats on the screen (drawing), now it should look like a top-down rpg.

Feel free to play with the Life Game code before starting with the next tutorial: Change screen resolution, activate the intermediate state drawing on the screen, use bigger maps... the best way to learn is to play with the code.


Bye

    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!