Page 1 of 1

Beginning SDL - Part 5.1 - Game Objects

#1 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Posted 04 July 2010 - 02:13 PM

*
POPULAR

Beginning SDL - Part 5.1 - GameObjects

This tutorial has been a long time coming, hopefully what you gain from it
will have been worth the wait. I am going to split these game object tutorials
into different parts, starting with a simpler approach and eventually leading
to a more advanced and feature heavy approach. So on with the first part.

Game Objects

Every game has objects, players, enemies, buttons, health bars, scenery objects, the list
goes on. Keeping track of all these objects is a huge task but a good OOP design can make
it all a bit more manageable. Like the previous tutorials the concepts I use are not SDL
specific so can be reused for any game you make with any library.

By the end of this tutorial you will have a game object class and a way to use them effectively
within a game state. Knowledge of the other tutorials is assumed and the code used directly relates
to previous tutorials, so read them first.

Onto the coding, create GameObject.h and GameObject.cpp files

GameObject.h
#ifndef GAME_OBJECT_H
#define GAME_OBJECT_H

#include "Game.h" 
#include "Sprite.h"

class GameObject
{
	public:
	
		GameObject() {}
		~GameObject() {}
		
		void Load(char* filename);
		void Update();
		void Draw();
		void Clean();
		
	private:
		
		SDL_Surface* m_pSprite
		
};

#endif



Im sure that is all pretty self explanatory, we create the functions that a game object
will need, the load function takes a filename as a parameter which will be the image file
we are going to use for the object. We create a SDL_Surface* as a member variable m_pSprite.

GameObject.cpp
#include "GameObject.h"

void GameObject::Load(char* filename)
{
	m_pSprite = Sprite::Load(filename); // use our sprite class to load the image
}

void GameObject::Update()
{
	// nothing for now
}

void GameObject::Draw()
{
	// nothing for now
}

void GameObject::Clean()
{
    SDL_FreeSurface(m_pSprite); // free the surface
}




OK so you might be wondering why we can't just use the Sprite::Draw() function inside the GameObject::Draw()
function, and the answer is...we can, but if you remember correctly the Sprite::Draw() function takes
a pointer to the screen surface. We need to find a way to expose this to our GameObject class.

We will do this by making our game class a singleton, there may be other ways to do this but I am going
to take this approach. Grab this snippet and
add it to your project. This class helps create singleton classes extremely easily. Use google for more information
on Singletons and the Singleton pattern.

Open up your Game.h file and make these changes
#ifndef  _GAME_H_
#define _GAME_H_

#include <SDL.h>

#include "Sprite.h"
#include "Singleton.h" // add the header you downloaded earlier

#include <vector>

class GameState; // make sure this class knows about the GameState class.

class Game
        {
        public:
                
                // Game(); // remove public constructor
				~Game(); // add public destructor
                
                void Init(const char* title, int width, int height, 
                                  int bpp, bool fullscreen);
                
                void ChangeState(GameState* state); // new function
                void PushState(GameState* state);  // new function
                void PopState(); // new function
                
                void HandleEvents(); // remove pointer to game class
                
                void Update();
                
                void Draw();
                
                void Clean();
                
                bool Running() { return m_bRunning; }
                void Quit() { m_bRunning = false; }
				
				SDL_Surface* GetScreen() { return m_pScreen; }
                
        private:
		
				Game() {} // add private constructor
				friend class Singleton<Game>
                
                // the stack of states
                std::vector<GameState*> states;
                
                SDL_Surface* m_pScreen;
                
                bool m_bFullscreen;
                bool m_bRunning;
                
};
typedef Singleton<Game> GameInst; // typedef the game instance so you don't
// have to type all that whenever you want to use it
#endif



Now open up Game.cpp and add the destructor and remove the constructor, the destructor
is just empty for now.

So now the game class is a singleton we can use it like so

GameInst::Instance()-> // add function call or whatever



Its extremely useful, but now we have to make sure our main function creates
the game as a singleton, open up main.cpp

#include "PlayState.h
#include <iostream>

int main(int argc, char* argv[])
{

	GameInst::Instance()->Init("test",640,480,32,false);

	GameInst::Instance()->ChangeState(PlayState::Instance());

	while(GameInst::Instance()->Running())
	{
		GameInst::Instance()->HandleEvents();
		GameInst::Instance()->Update();
		GameInst::Instance()->Draw();
	}

	GameInst::Instance()->Clean();

	return 0;
}



As you can see, rather than create the game in this file we simply initialise
the game as a singleton and can the call any of its functions using
GameInst::Instance()->

I also added a state called playstate which is exactly the same as the playstate
from the last tutorial but without the specifics we added last time, here it is.

#ifndef  _PLAY_STATE_H_
#define _PLAY_STATE_H_

#include "SDL.h"
#include "GameState.h"
#include "Sprite.h"

class PlayState : public GameState
{
        public:
                void Init();
                void Clean();
                
                void Pause();
                void Resume();
                
                void HandleEvents(Game* game);
                void Update(Game* game);
                void Draw(Game* game);
                
                // Implement Singleton Pattern
                static PlayState* Instance()
                {
                        return &m_PlayState;
                }
                
        protected:
                
                PlayState() {}
                
        private:
                static PlayState m_PlayState;
                
};

#endif



and the cpp

#include <stdio.h>

#include "SDL.h"
#include "Game.h"
#include "PlayState.h"

PlayState PlayState::m_PlayState;

void PlayState::Init()
{       
        printf("PlayState Init Successful\n");
}

void PlayState::Clean()
{
        printf("PlayState Clean Successful\n");
}

void PlayState::Pause()
{
        printf("PlayState Paused\n");
}

void PlayState::Resume()
{
        printf("PlayState Resumed\n");
}

void PlayState::HandleEvents(Game* game)
{
        SDL_Event event;
        
        if (SDL_PollEvent(&event)) {
                switch (event.type) {
                        case SDL_QUIT:
                                game->Quit();
                                break;
                }
        }
}

void PlayState::Update(Game* game) 
{
}

// We have to change the way we get the screen in this function
void PlayState::Draw(Game* game) 
{
        SDL_Flip(GameInst::Instance()->GetScreen());
}



You may be starting so see why we went through all this work, now we can access
functions specific to the game class from anywhere in our code meaning now we can
use our sprite draw class within the gameobject class and pass in the pointer to the screen
using the game class GetScreen function.

#include "GameObject.h"

void GameObject::Load(char* filename)
{
	m_pSprite = Sprite::Load(filename); // use our sprite class to load the image
}

void GameObject::Update()
{
	// nothing for now
}

void GameObject::Draw()
{
	// we can now use the sprite draw function
	Sprite::Draw(GameInst::Instance()->GetScreen(), m_pSprite, 0, 0);
}

void GameObject::Clean()
{
    SDL_FreeSurface(m_pSprite); // free the surface
	delete this; // delete object
}



So now we can test out the GameObject class

Playstate.h
#ifndef  _PLAY_STATE_H_
#define _PLAY_STATE_H_

#include "SDL.h"
#include "GameState.h"
#include "GameObject.h" // replace Sprite.h with GameObject.h

class PlayState : public GameState
{
        public:
                void Init();
                void Clean();
                
                void Pause();
                void Resume();
                
                void HandleEvents(Game* game);
                void Update(Game* game);
                void Draw(Game* game);
                
                // Implement Singleton Pattern
                static PlayState* Instance()
                {
                        return &m_PlayState;
                }
                
        protected:
                
                PlayState() {}
                
        private:
                static PlayState m_PlayState;
				
				GameObject * testObject; // create a pointer to a game object
                
};

#endif



Playstate.cpp
#include <stdio.h>

#include "SDL.h"
#include "Game.h"
#include "PlayState.h"

PlayState PlayState::m_PlayState;

void PlayState::Init()
{       
		testObject = new GameObject(); // create the game object
		testObject->Load("naruto.bmp") // load the bmp for gameobject
        printf("PlayState Init Successful\n");
}

void PlayState::Clean()
{
		testObject->Clean(); // delete the game object and free surface
        printf("PlayState Clean Successful\n");
}

void PlayState::Pause()
{
        printf("PlayState Paused\n");
}

void PlayState::Resume()
{
        printf("PlayState Resumed\n");
}

void PlayState::HandleEvents(Game* game)
{
        SDL_Event event;
        
        if (SDL_PollEvent(&event)) {
                switch (event.type) {
                        case SDL_QUIT:
                                game->Quit();
                                break;
                }
        }
}

void PlayState::Update(Game* game) 
{
}

void PlayState::Draw(Game* game) 
{
		testObject->Draw(); // draw the game object
        SDL_Flip(GameInst::Instance()->GetScreen());
}



naruto.bmp is attached at the bottom of this tutorial if you want to use it :) that should now
give you an image in the top left of naruto, woohoo. Not very exciting though after all that work,
and he has a green box around him. But the good news is that we now have a great gameobject class. So like I said at the beginning of
this tutorial, I have split these tutorials up into parts so that they can become increasingly complex
and build on each other. So before I leave this one I will show you how to use SDL_image in
our sprite class.

There are loads of tutorials on how to set up SDL_image online for any IDE so I won't covert that here,
http://www.lazyfoo.n...0508e/index.php is a good start.

Now you have it set up we can make the necessary changes to the sprite class so that we can load any image file type
that we want :)

Sprite.h
#ifndef  _SPRITE_H_
#define _SPRITE_H_

#include <SDL.h>
#include <SDL_image.h> // add the library header

class Sprite
{
public:

	Sprite();

	static SDL_Surface* Load(char* pFile);

	static   bool   Draw(SDL_Surface* dest, SDL_Surface* src, int x, int y);

	static bool   Draw(SDL_Surface* dest, SDL_Surface* src, int x, int y, int x2,  
		int y2, int width, int height);
};

#endif



Sprite.cpp
#include "Sprite.h"

// constructor 
Sprite::Sprite()
{
}

SDL_Surface* Sprite::Load(char* File)
{
        SDL_Surface* temp = NULL;
        SDL_Surface* optimized = NULL;

        if((temp = IMG_Load(File)) == NULL) // change SDL_LoadBMP to IMG_Load and thats all there is to it
        {
                  return NULL;
        }
        
        optimized = SDL_DisplayFormatAlpha(temp);
        SDL_FreeSurface(temp);

        return optimized;
}

bool Sprite::Draw(SDL_Surface* dest, SDL_Surface* src, int x, int y)
{
          if(dest == NULL || src == NULL)
           {
                                  return false;
           }

           SDL_Rect  destR;

           destR.x = x;
           destR.y = y;

           SDL_BlitSurface(src, NULL, dest, &destR);
           
                return true;
}

bool Sprite::Draw(SDL_Surface* dest, SDL_Surface* src, int x, int y, int x2, int y2, int width, int height) {
        if(dest == NULL || src == NULL) {
                return false;
        }
        
        SDL_Rect destR;
        
        destR.x = x;
        destR.y = x;
        
        SDL_Rect srcR;
        
        srcR.x = x2;
        srcR.y = y2;
        srcR.w = width;
        srcR.h = height;
        
        SDL_BlitSurface(src, &srcR, dest, &destR);
        
        return true;
}



Now you can load up lots of image files not just BMP's. We can now load PNG files which support transparency
which eliminates the need for colour keying. I have also attached naruto.png to the bottom of
the tutorial with transparency so you can see how great PNG files transparency is. If you want
to know how to create transparency on png files check out my tutorial here http://www.dreaminco...y-in-png-files/

The next tutorial is coming very very soon.

Happy coding.

Attached File  naruto.bmp (20.09K)
Number of downloads: 561
Attached Image

Is This A Good Question/Topic? 6
  • +

Replies To: Beginning SDL - Part 5.1 - Game Objects

#2 bmcfallen  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 31
  • Joined: 26-April 10

Posted 06 August 2010 - 09:15 PM

Thanks stayscrisp, this is great stuff, and I have been waiting for the next in the series. Haven't done any of this code yet but will let you know if there are any errors (in other words I'll come crying to you for help :stupid: )

Keep up the great work!
Was This Post Helpful? 0
  • +
  • -

#3 gnu00b  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 01-February 12

Posted 01 February 2012 - 05:33 PM

First of all, thank you so much for these tutorials. They have taught me a lot!

I was wondering if someone could help me with an error I have been getting:
obj\Debug\GameObject.o:C:/Users/gnu00b/Desktop/cpp/dic/Game/Singleton.h:10: undefined reference to `Game::Game()'

I did not modify Singleton.h at all, so I've looked at GameObject.cpp. I commented this line in the Draw function out:
//Sprite::Draw(GameInst::Instance()->GetScreen(), m_pSprite, 0, 0);

That gave me this error:
obj\Debug\PlayState.o:PlayState.cpp:(.text$_ZN9SingletonI4GameE8InstanceEv[Singleton<Game>::Instance()]+0x68): undefined reference to `Game::Game()'


It seems like the error occurs whenever there's a call to a function of GameInst, but I am stumped as to how to correct this problem. Thank you for your help.

Game.cpp
Spoiler


Game.h:
Spoiler


main.cpp:
Spoiler


Singleton.h
Spoiler

Was This Post Helpful? 0
  • +
  • -

#4 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Posted 08 February 2012 - 05:58 AM

Hi mate,

The problem is that you have declared a constructor yet you haven't defined it

here's your declaration:
private: 
Game(); //add private constructor



Yet you have commented out the definition of this constructor

//constructor
/*
Game::Game()
{
}
*/



Just uncomment the definition and all should be well :)
Was This Post Helpful? 0
  • +
  • -

#5 howzilla  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 14-March 12

Posted 14 March 2012 - 10:20 AM

Can you direct me to the first tutorial in your series Beginning SDL? Thanks.

Sorry - I see the link now. Doh!
Was This Post Helpful? 0
  • +
  • -

#6 gamer27lv  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 11-May 12

Posted 13 May 2012 - 09:30 PM

Hello I am trying to build on the game state tutorial with this one and I am getting this error: invalid declarator before 'states'

that is right here:

Game(){}
friend class Singleton<Game>

vector<GameState*> states; //i am using namespace std

what can I be doing wrong? there are very little steps to mess up it seems like...

View Postgamer27lv, on 13 May 2012 - 09:28 PM, said:

Hello I am trying to build on the game state tutorial with this one and I am getting this error: invalid declarator before 'states'

that is right here:

Game(){}
friend class Singleton<Game>

vector<GameState*> states; //i am using namespace std

what can I be doing wrong? I don't see many places it can go wrong..


Hello I am trying to build on the game state tutorial with this one and I am getting this error: invalid declarator before 'states'

that is right here:

Game(){}
friend class Singleton<Game>

vector<GameState*> states; //i am using namespace std

what can I be doing wrong? I don't see many places it can go wrong..

sorry... I thought I was editing my comment but I was quoting it....
Was This Post Helpful? 0
  • +
  • -

#7 gamer27lv  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 11-May 12

Posted 13 May 2012 - 10:03 PM

in your code you have
friend class Singleton<Game>

but I had to add a semi-colon to the end of it I was getting an error without it.

friend class Singleton<Game>;
Was This Post Helpful? 0
  • +
  • -

#8 gamer27lv  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 11-May 12

Posted 16 May 2012 - 11:18 PM

void StageLevelOne::Clean(){
    for(unsigned int i = 0; i != GameObjects.size(); i++) {
        if(!GameObjects[i]) continue;
        GameObjects[i]->Clean();   //debugger points at this line
    }
    SDL_FreeSurface(g_pStageTiles);
}



I am getting a segmentation fault error that crashes when I switch between game states.
It appears to be when trying to clear the game objects. I only have one game object in my case which is a player that runs around.

Is anyone else having this problem trying to follow this tutorial?
Was This Post Helpful? 0
  • +
  • -

#9 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Posted 17 May 2012 - 01:10 AM

Hmmm, I don't think this tutorial gets to adding the objects to a vector. Can you post some of your code please :)
Was This Post Helpful? 0
  • +
  • -

#10 gamer27lv  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 11-May 12

Posted 17 May 2012 - 02:18 AM

View Poststayscrisp, on 17 May 2012 - 01:10 AM, said:

Hmmm, I don't think this tutorial gets to adding the objects to a vector. Can you post some of your code please :)


oh great timing! I just fixed it! lol jk thank you so much for the tutorial buddy.

I posted again with how I fixed it, i think on part two of your tutorial in the comments
Was This Post Helpful? 0
  • +
  • -

#11 mars1990  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 13-March 13

Posted 13 March 2013 - 04:15 PM

Hi,
If we made Game a singleton class, I think we don't need to pass param to other class methods. For example in:
void PlayState::Update(Game* game)
{
}



Am I right or wrong?
(can't check it now myself)
Was This Post Helpful? 0
  • +
  • -

#12 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Posted 18 March 2013 - 04:16 PM

You are correct, you could do that if you like.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1