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
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.
naruto.bmp (20.09K)
Number of downloads: 386





MultiQuote




|