#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 }
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:
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"
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:
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"
-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.
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:
- life.cpp
- engine.h
- engine.cpp
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:
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 :
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!
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.
//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 greymyengine.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 buffermyengine.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 screenmyengine.Flip();//wait 50 miliseconds to limit frame ratemyengine.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:
SDL library and add ons:
Other useful packages:
A great Version control tool
A library to draw almost any shape, scaling and rotating images by Jhony D
Box 2D: 2D physics:
(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
- gimp
Other useful packages:
A nice web browser:
- Firefox
A great Version control tool
- subversion
- make ->Not used in the tutorials, but very useful
- cmake ->Not used in the tutorials, but very useful
A library to draw almost any shape, scaling and rotating images by Jhony D
Box 2D: 2D physics:
- Box2D: http://box2d.org/
Subscribe to:
Posts (Atom)