![]() |
|
#1
|
||||
|
||||
|
This tutorial assumes you know a fair amount of C++ and have at least attempted to program a simple game (and that you were partially successful). Lets get started... We will need to create a new class to handle the events (this will come in handy later) Code:
// GameEngine.h file
// This is included so we can manage our game states with this class
#include <stack>
#include <engine.h>
// We must include all the game states here
#include "SplashState.h"
// For stack
using namespace std;
// Main LTE namespace
using namespace engine;
// Sub namespaces for LTE
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
// The main event receiver must inherit from IEventReceiver in order to work
// with the creation of the LTE device
class GameEngine :
public IEventReceiver
{
public:
GameEngine(void);
~GameEngine(void);
// The overridden event catcher function
bool OnEvent(SEvent e);
// Main loop
bool Run(void);
private:
// Main engine device
engineDevice * device;
// Video driver
IVideoDriver * driver;
// Scene Manager
ISceneManager * smgr;
// Graphical user interface
IGUIEnvironment * guienv;
// Stack of gamestates
stack<GameState *>stateStack;
public:
// Sets the engine device
void SetDevice(engineDevice * _engine);
};
Code:
#include "GameEngine.h"
// We can't initialize until we get a pointer to the LTE device and
// the LTE device can't be created until it gets a pointer to the
// derivative of IEventReceiver (figure that one out if you can)
GameEngine::GameEngine(void)
{
}
GameEngine::~GameEngine(void)
{
}
// This is the overridden function that actually handles the events
bool GameEngine::OnEvent(SEvent e)
{
// Make sure both the device is created and that the game state
// stack is not empty
if (!device || stateStack.empty() == true)
return false;
// Switch through each event type and then pass it to the top state on the stack
switch (e.EventType)
{
// This is used by the graphical user interface
case EET_GUI_EVENT:
stateStack.top()->OnEvent(e);
return true;
break;
// This is for virtual mouse input (it is a fix from the original irrlicht engine)
case EET_MOUSE_INPUT_EVENT:
stateStack.top()->OnEvent(e);
return true;
break;
// This is our input from buttons (minus the analog stick)
case EET_KEY_INPUT_EVENT:
stateStack.top()->OnEvent(e);
return true;
break;
// This is for log events (not even sure if this works in LTE)
case EET_LOG_TEXT_EVENT:
return true;
break;
// In the release of LTE that I created this is disabled because it was done
// extremely poorly, and barely worked (use a different one)
case EET_AUDIO_EVENT:
stateStack.top()->OnEvent(e);
return true;
break;
// This is used if you want to pass events to it
case EET_USER_EVENT:
stateStack.top()->OnEvent(e);
return true;
break;
default:
break;
};
return false;
}
// Main loop
bool GameEngine::Run(void)
{
// Create and add our first state
SplashState * splash = new SplashState(device);
// Add the state to our stack
stateStack.push(splash);
// Run the game loop of the top state
if (stateStack.top())
{
// We loop this until LTE decides it is time to stop
// In this loop is where you will want to conditionally change states
while (device->run())
{
// We call the run of the top state
stateStack.top()->Run();
}
}
return true;
}
// Sets the LTE engine device
void GameEngine::SetDevice(engineDevice * _engine)
{
if (_engine)
device = _engine;
}
Code:
// where play state is an inherited class from GameState
/***new***/
#include <engine.h>
/***new***/
// This is included because it sets up the program to be run on PSP
// (this is the same common.h that is used in the examples in the LTE SDK)
#include "common.h"
#include "GameEngine.h"
/***new***/
// I prefer using namespaces you can skip this if you know what you are doing
/***new***/
// Main LTE namespace
using namespace engine;
/***new***/
// Sub namespaces
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
/***new***/
// Because we use common.h we use engineMain instead so we don't have to worry
// about setting up the PSP specific callbacks and everything like that
int engineMain(unsigned int argc, void * argv)
{
/***new***/
// Set up for PSP (this is in common.h it is used to set up the PSP specific stuff)
setupPSP();
/***new***/
// Our device objects that are used to control LTE
engineDevice * device = NULL;
IVideoDriver * driver = NULL;
ISceneManager * smgr = NULL;
IGUIEnvironment * guienv = NULL;
/***new***/
// Create a new game engine
GameEngine * ge = new GameEngine();
/***new***/
// Create our device, and get our handlers (the reason we set them to NULL and
// then fill them in so we can check later to make sure they are present)
// Here we pass our new game engine object to the createDevice function to get a
// new device. It also sends the events to ge now.
device = createDevice(ge, false);
driver = device->getVideoDriver();
smgr = device->getSceneManager();
guienv = device->getGUIEnvironment();
// Give ge a pointer to the device
ge->SetDevice(device);
// Transfer control to the game engine
ge->Run();
}
Code:
// GameState.h
#include <engine.h>
// Main LTE namespace
using namespace engine;
// Sub namespaces
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
class GameState
{
public:
// Constructor (so we can get access to the LTE device
GameState(engineDevice * _engine);
// Destructor (virtual so that derived functions are called when calling
// from a GameState pointer.
virtual ~GameState(void);
// Main game loop (must be overriden)
virtual void Run() = 0;
// OnEvent (This is where we deal with our events that will be passed
// from GameEngine
virtual bool OnEvent(SEvent e);
protected:
// LTE engine
engineDevice * device;
// Video driver
IVideoDriver * driver;
// Scene Manager
ISceneManager * smgr;
// Graphical user interface
IGUIEnvironment * guienv;
};
Code:
// GameState.cpp
#include "GameState.h"
GameState::GameState(engineDevice * _engine)
{
// Point to our LTE engine
device = _engine;
// Grab it so it won't die. This is one way to keep track of how many
// pointers there are to this object. When there are none it will be deleted
// automatically
device->grab();
// Set the driver
driver = device->getVideoDriver();
// Set the scene manager
smgr = device->getSceneManager();
// Set the guienv
guienv = device->getGUIEnvironment();
}
GameState::~GameState(void)
{
// We drop the device so that it can be deleted automatically (this must be
// called for each ->grab()
device->drop();
device = NULL;
}
bool GameState::OnEvent(SEvent e)
{
// This is where we deal with any events we have
// more on this in another tutorial
if (!device)
return false;
switch (e.EventType)
{
case EET_GUI_EVENT:
return true;
break;
case EET_MOUSE_INPUT_EVENT:
return true;
break;
case EET_KEY_INPUT_EVENT:
return true;
break;
case EET_LOG_TEXT_EVENT:
return true;
break;
case EET_AUDIO_EVENT:
return true;
break;
case EET_USER_EVENT:
return true;
break;
default:
break;
};
return false;
}
Code:
// SplashState.h
#include "gamestate.h"
#include <engine.h>
// Main LTE namespace
using namespace engine;
// Sub namespaces
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
class SplashState :
public GameState
{
private:
// This is our splash image that will be displayed on the screen
ITexture * splash;
// This is to help count how long it is displayed
u32 oldTick;
public:
SplashState(engineDevice * _engine);
~SplashState(void);
// Main loop of state
void Run(void);
};
Code:
// SplashState.cpp
#include "SplashState.h"
// This is our constructor we are constructing the game state from the parameters
// that are passed to SplashState
SplashState::SplashState(engineDevice * _engine)
: GameState(_engine)
{
if (driver)
{
// Here we load the splash screen texture file into our Texture pointer
// You'll need to provide a 480x272 bitmap to use as your splash screen
splash = driver->getTexture("splash.bmp");
// We grab the current number of ticks. Later we use this to tell how much
// time has passed so we know when to go to the next state
oldTick = device->getTimer()->getTime();
}
}
SplashState::~SplashState(void)
{
// Drop our texture
splash->drop();
// This is used to clear all of the textures currently in use
// Never use this unless you are sure everything that uses a texture
// is done using it and deleted
driver->removeAllTextures();
}
// Main loop of state
void SplashState::Run(void)
{
// Do any before scene stuff here
// Call begin scene (do as little as possible between this and end scene)
// This has to be called before rendering anything to the screen
driver->beginScene(true, true, SColor(255, 255, 255, 255));
// This tells the scene manager to draw everything that it has inside of it
smgr->drawAll();
// Here we want to draw our splash texture to the screen (this assumes it is a
// full screen image)
driver->draw2DImage(splash, position2d<s32>(0, 0), rect<s32>(0, 0, 480,272), 0, SColor(255, 255, 255, 255), false);
// Draw the guienv
guienv->drawAll();
// Draw anything we want on top of the guienv
// End the scene (this is called after drawing everything)
driver->endScene();
// Do after the scene stuff
// Make sure the screen shows up for 2 seconds
if (device->getTimer()->getTime() - oldTick > 2000)
{
// Change the splash or do whatever you want to do here because the
// splash screen is done showing up
}
}
__________________
A wise man once said "...what was I saying..." |
|
#2
|
|||
|
|||
|
Thanks for posting another tutorial. I'm adding it to the mega thread
|
|
#3
|
||||
|
||||
|
You are welcome If this doesnt work please tell me. So I can fix it. The next tutorial will be about how to load a level and make it run at a decent frame rate. It will include how to set up the camera for an FPS style shooter.
__________________
A wise man once said "...what was I saying..." |
|
#4
|
||||
|
||||
|
Hey - that's a nice structured flow, but I have a few concerns regarding resource management..
That deconstructor is very poor... Imagine implementing a 'paused' state or even a 'sub-menu' state, constantly unloading/reloading textures and resources - it'd be horrendous, though i think you are just using this as an example and are well aware of that lol. But hey - you are committing a taboo by dropping the 'splash' ITexture and only are getting away with it due to the 'removeAllTextures' proceeding it. I don't know if i may be seeing things wrong but rule of thumb, unless you clearly use the word 'create' when defining that variable, don't drop it as the driver has it stored somewhere. Better: Code:
SplashState::~SplashState(void)
{
driver->removeTexture(splash);
splash = NULL;
}
__________________
...at what speed must I live.. to be able to see you again?... Win money while playing Kitten Cannon! Check out all my work on my new site - from Kitten Cannon to Boxhead to Light Cycle 3D |
|
#5
|
||||
|
||||
|
hi . i know your busy probably for Homebrew idol but is this (LTE) a different sdk for psp or its something like oslib ? how can it use oop with C?
|
|
#6
|
||||
|
||||
|
http://www.ltestudios.com/
Read up on it there, if you still don't understand I don't think it's worth your time figuring it out.
__________________
...at what speed must I live.. to be able to see you again?... Win money while playing Kitten Cannon! Check out all my work on my new site - from Kitten Cannon to Boxhead to Light Cycle 3D |
|
#7
|
||||
|
||||
|
thanks i did . i guess i have to do that in summer . is there a way to download Doxygen's doc from the site ?
Last edited by MTN; 05-05-2009 at 07:36 AM. |
|
#8
|
||||
|
||||
|
Download the engine from the site (or anywhere really) and it will come with the documentation.
__________________
...at what speed must I live.. to be able to see you again?... Win money while playing Kitten Cannon! Check out all my work on my new site - from Kitten Cannon to Boxhead to Light Cycle 3D |
|
#9
|
||||
|
||||
|
You probably want to download the version I uploaded, or the version that Brick is working on if they ever release it. Since the version on the LTE site is messed up. It also has a steep learning curve. You should stick with OsLib until you find that it is not robust enough for what you are wanting to do, such as making a 3D game.
__________________
A wise man once said "...what was I saying..." |
|
#10
|
||||
|
||||
|
Think you can give me a link to the post containing either ?
Would love to get the one with the PSPGL texture memory leak fix, sliding fix and falling through the floor fix heh. Oh and hey - as an update lokaire - why not use a GUI in-out fader? It adds polish to the game as well as is your timer to tell when it's time to transition to the next state ![]() For instance.... Add this to existing GameState.h as 'protected': Code:
// Used for fading in out of this gamestate IGUIInOutFader* fader; GameState::GameState() Code:
// add fader to this gamestate fader = guienv->addInOutFader(); fader->setColor(SColor(0,0,0,0)); fader->fadeIn(4000 /* 4 seconds */); Code:
// Remove fader fader->remove(); fader = NULL; Run() - NOTE: after the scene Code:
if (fader->isReady())
{
if (fader->getColor() == SColor(0,0,0,0))
{
printf("Done fading In, Fading out now\n");
fader->setColor(SColor(255,0,0,0));
fader->fadeOut(4000 /* 4 seconds */);
}
else
{
EndState(200); // end your state (go to next state)
}
}
__________________
...at what speed must I live.. to be able to see you again?... Win money while playing Kitten Cannon! Check out all my work on my new site - from Kitten Cannon to Boxhead to Light Cycle 3D |
![]() |
|
|
|||
|
|||
|
|
| Thread Tools | |
| Display Modes | |
|
|