by Midnight
Last updated june, 14, 2009, 12:22am est.
(known issues update & removed windows inclusion and sleep function)
Current Version 1.0.1
Previous Version 1.0
Features:
Time offset.
Progressive time warping.
Class based design with separated timer class.
Known Issues:
You can not set clock offset before 1am on the first day.
You can not exceed c++ variable type limits for progressive time warping.
If you want the proper Delta time you can't increase the speed of the animations aka you can not use setClockSpeed(). You either can not base your animation effectors on internal timer or you must add a delta time feature to irrlicht's timer. Without checking irrlicht source I can't know if delta is accurate or not. it depends on render time not the timer I would hope and that's what irrlicht would need to handle. I'll update this once I've had a chance to see how animation effectors are done in irrlicht.
Planned Features:
Integrated calendar class for days of the week, months of the year, and leap year offset.
Alarm System based on Calender dates and times.
12 Hour GameClock class code:
First the modified version of monkeycracks timer class
Timer.cpp
Code: Select all
#include "Mytimer.h"
MyTimer::MyTimer() : TotalSeconds(0), TotalMinutes(0), TotalHours(0), TotalDays(0), Delta(0),
NewTime(0), OldTime(0), Elapsed(0), OldRealTime(0), NewRealTime(0), SecondCounter(0)
{
}
MyTimer::~MyTimer()
{
}
void MyTimer::init(irr::ITimer* t)
{
timer = t;
OldTime = timer->getTime();
OldRealTime = timer->getRealTime();
}
void MyTimer::update()
{
NewTime = timer->getTime();
Elapsed = (NewTime - OldTime);
OldTime = NewTime;
// this seperates delta time from the timer incase we changed the speed
NewRealTime = timer->getRealTime();
if(NewRealTime - OldRealTime)
Delta = (NewRealTime - OldRealTime)/1000;
OldRealTime = NewRealTime;
SecondCounter += Elapsed;
if(SecondCounter >= 1000)
{
SecondCounter -= 1000;
++TotalSeconds;
}
if(TotalSeconds != 0)
{
TotalMinutes = TotalSeconds/60;
TotalDays = ((TotalSeconds/60)/60)/24;
TotalHours = (TotalSeconds/60)/60;
}
}
irr::u32 MyTimer::getSecondsElapsed()
{
return TotalSeconds;
}
irr::f32 MyTimer::getMinutesElapsed()
{
return TotalMinutes;
}
irr::f32 MyTimer::getHoursElapsed()
{
return TotalHours;
}
irr::f32 MyTimer::getDaysElapsed()
{
return TotalDays;
}
irr::f32 MyTimer::getDeltaTime()
{
return Delta;
}
Code: Select all
#ifndef TIMER_H_INCLUDED_
#define TIMER_H_INCLUDED_
#include "ITimer.h"
class MyTimer
{
public:
MyTimer();
~MyTimer();
void init(irr::ITimer* t);
void update();
irr::u32 getSecondsElapsed();
irr::f32 getMinutesElapsed();
irr::f32 getHoursElapsed();
irr::f32 getDaysElapsed();
irr::f32 getDeltaTime();
protected:
irr::u32 TotalSeconds;
irr::u32 TotalMinutes;
irr::u32 TotalHours;
irr::ITimer* timer;
private:
irr::u32 TotalDays;
irr::f32 NewRealTime;
irr::f32 OldRealTime;
irr::f32 Delta;
irr::f32 NewTime;
irr::f32 OldTime;
irr::f32 Elapsed;
irr::s32 SecondCounter;
};
#endif
Code: Select all
#include "GameClock.h"
GameClock::GameClock() : ClockOffset(0), ClockSecs(0), ClockMins(0), ClockHours(0), ClockDays(0), DayNight(0),
TCycleCounter(0), NewHours(0), OldHours(0), ElapsedHours(0)
{}
GameClock::~GameClock(){}
void GameClock::update()
{
MyTimer::update();
// Adjust for twelve hour timecycle
NewHours = MyTimer::TotalHours;
ElapsedHours = (NewHours - OldHours);
OldHours = NewHours;
TCycleCounter += ElapsedHours;
if(TCycleCounter >= 24)
{
TCycleCounter -= 24;
++ClockDays;
}
if(TCycleCounter < 11 || TCycleCounter > 22)
{ DayNight = "AM"; }
else
{ DayNight = "PM"; }
ClockSecs = (MyTimer::TotalSeconds%60);
ClockMins = (MyTimer::TotalMinutes%60);
ClockHours = ((TCycleCounter%12)+1);
}
irr::core::stringw GameClock::getClockDisplay()
{
irr::core::stringw str(" ");
str.append(irr::core::stringw(ClockHours));
str.append(":");
if(ClockMins < 10)
str.append("0");
str.append(irr::core::stringw(ClockMins));
str.append(":");
if(ClockSecs < 10)
str.append("0");
str.append(irr::core::stringw(ClockSecs));
str.append(" ");
str.append(DayNight);
return str;
}
void GameClock::setClock(irr::u32 hours, irr::u32 minutes, irr::u32 seconds, irr::core::stringw timecycle)
{
//don't accept invalid times
if(!hours || minutes >= 60 || seconds >= 60)
{
// report error invalid clock offset
// clock currently starts no earlier then 1:00:00AM
}
else
{
// Convert everything to seconds and advance the timer
ClockOffset = ((hours*60)*60) - 3600 + (minutes*60) + seconds;
MyTimer::TotalSeconds += (ClockOffset);
if(timecycle == "PM")
{
MyTimer::TotalSeconds += 43200; //aka 12 hours in seconds
}
}
}
void GameClock::setClockSpeed(irr::f32 factor)
{
// max factor can not be more then float values without changing irrlicht
MyTimer::timer->setSpeed(factor);
}
irr::core::stringw GameClock::getTimeCycle()
{
return DayNight;
}
irr::u32 GameClock::getClockSeconds()
{
return ClockSecs;
}
irr::u32 GameClock::getClockMinutes()
{
return ClockMins;
}
irr::u32 GameClock::getClockHours()
{
return ClockHours;
}
irr::u32 GameClock::getClockDays()
{
return ClockDays;
}
Code: Select all
#ifndef GAME_TIMER_H_INCLUDED_
#define GAME_TIMER_H_INCLUDED_
#include "Mytimer.h"
#include "irrString.h"
//MyTimer timer;
class GameClock : public MyTimer
{
public:
GameClock();
~GameClock();
void update();
void setClockSpeed(irr::f32 factor);
void setClock(irr::u32 hours, irr::u32 minutes, irr::u32 seconds, irr::core::stringw timecycle);
irr::core::stringw getClockDisplay();
irr::core::stringw getTimeCycle();
irr::u32 getClockSeconds();
irr::u32 getClockMinutes();
irr::u32 getClockHours();
irr::u32 getClockDays();
private:
irr::u32 ClockOffset;
irr::u32 ClockSecs;
irr::u32 ClockMins;
irr::u32 ClockHours;
irr::u32 ClockDays;
irr::core::stringw DayNight;
irr::u32 TCycleCounter;
irr::u32 NewHours;
irr::u32 OldHours;
irr::u32 ElapsedHours;
};
#endif
Main.cpp
Code: Select all
#include "GameClock.h"
#include "Reciever.h"
#include "globals.h"
#define USE_3D_SCENE
ISceneNode* Skybox;
int main(int argc, char** argv)
{
int ResX = 800, ResY = 600;
device = createDevice(EDT_OPENGL, dimension2d<s32>(ResX, ResY), 16, false, false, false, 0);
MyEventReceiver receiver;
device->setEventReceiver(&receiver);
device->setWindowCaption(L"GameClock Example");
IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* guienv = device->getGUIEnvironment();
// set a font
IGUISkin* skin = guienv->getSkin();
IGUIFont* font = guienv->getFont("fontModern.bmp");
if (font)
skin->setFont(font);
#ifdef USE_3D_SCENE
ISceneManager* smgr = device->getSceneManager();
IAnimatedMesh* EarthMesh = smgr->getMesh("earth.x");
//The Camera
// smgr->addCameraSceneNodeFPS(0);
irr::scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, vector3df(0,0,0), vector3df(0,0,0));
camera->setTarget(vector3df(0,0,50));
if (EarthMesh)
{
//create mesh copy with tangent informations from original earth.x mesh
IMesh* tangentSphereMesh = smgr->getMeshManipulator()->createMeshWithTangents(EarthMesh->getMesh(0));
//scale the mesh by factor 20
smgr->getMeshManipulator()->scaleMesh(tangentSphereMesh, vector3df(13,13,13));
//create mesh scene node
ISceneNode* Sphere = smgr->addMeshSceneNode(tangentSphereMesh);
Sphere->setPosition(vector3df(0,0,50));
/* if(driverType == EDT_DIRECT3D9 || driverType == EDT_DIRECT3D8)
{
//load heightmap, create normal map from it and set it
ITexture* EarthNormalMap = driver->getTexture("earthbump.bmp");
driver->makeNormalMapTexture(EarthNormalMap, 20.0f);
Sphere->setMaterialTexture(1, EarthNormalMap);
Sphere->setMaterialType(video::EMT_PARALLAX_MAP_SOLID);
}
*/
//add rotation animator
ISceneNodeAnimator* anim = smgr->createRotationAnimator(vector3df(0,0.10f,0));
Sphere->addAnimator(anim);
anim->drop();
//drop mesh because we created it with a create.. call.
tangentSphereMesh->drop();
}
//Light
smgr->addLightSceneNode(0, vector3df(5,3,5),SColorf(0.5f,0.5f,0.80f,1.0f), 1000.0f);
//Skybox
Skybox = smgr->addSkyBoxSceneNode(
driver->getTexture("stars3.jpg"),
driver->getTexture("stars3.jpg"),
driver->getTexture("stars3.jpg"),
driver->getTexture("stars3.jpg"),
driver->getTexture("stars3.jpg"),
driver->getTexture("stars.jpg"));
// Skybox = smgr->addSkyDomeSceneNode(driver->getTexture("stars.jpg"), 30, 30, 1, 2);
#endif
for(s32 i=0; i<gui::EGDC_COUNT; ++i)
{
SColor col = device->getGUIEnvironment()->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
col.setAlpha(255);
device->getGUIEnvironment()->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
}
gui::IGUIToolBar* bar = guienv->addToolBar();
gui::IGUIStaticText* fpstext = guienv->addStaticText(L"", core::rect<s32>(ResX-700,4,ResX-620,23), true, 0, bar);
gui::IGUIStaticText* deltatext = guienv->addStaticText(L"", core::rect<s32>(ResX-800,4,ResX-700,23), true, true);
gui::IGUIStaticText* speedtext = guienv->addStaticText(L"", core::rect<s32>(ResX-350,4,ResX-220,23), true, true);
gui::IGUIStaticText* timetext = guienv->addStaticText(L"", core::rect<s32>(ResX-120,4,ResX-20,23), true, true);
// timetext->setToolTipText(L"%i,", gameclock.getClockDays());
guienv->addButton(rect<s32>(200, 5, 230, 25), 0, 101, L"<-");
guienv->addButton(rect<s32>(240, 5, 290, 25), 0, 102, L"Pause");
guienv->addButton(rect<s32>(300, 5, 340, 25), 0, 103, L"Play");
guienv->addButton(rect<s32>(350, 5, 380, 25), 0, 104, L">");
guienv->addButton(rect<s32>(390, 5, 420, 25), 0, 105, L">>");
// initiate the timer class
timer = device->getTimer();
gameclock.init(timer);
// you can't set the clock before 1:00am on the first day
// I'm still thinking how I could change that
gameclock.setClock(11,42,0,"AM");
while(device->run() && driver)
{
if (device->isWindowActive())
{
driver->beginScene(true, true, video::SColor(0,10,50,130));
#ifdef USE_3D_SCENE
smgr->drawAll();
#endif
guienv->drawAll();
driver->endScene();
//switched to irrlicht sleep
//device->sleep();
}
else
{
device->yield();
}
// update the timer after the window active statement to keep current
gameclock.update();
core::stringw str(L" FPS: ");
str.append(core::stringw(driver->getFPS()));
fpstext->setText(str.c_str());
core::stringw str3(L" Delta: ");
str3.append(core::stringw(gameclock.getDeltaTime()));
deltatext->setText(str3.c_str());
core::stringw str4(L" Speed: ");
str4.append(core::stringw((int)gamespeed));
speedtext->setText(str4.c_str());
// the game clock
timetext->setText(core::stringw(gameclock.getClockDisplay()).c_str());
}
device->drop();
return 0;
}
Code: Select all
#ifndef GLOBALS_H
#define GLOBALS_H
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
IrrlichtDevice *device = 0;
GameClock gameclock;
irr::f32 gamespeed = 1.0f;
irr::ITimer *timer;
#endif
Code: Select all
#ifndef RECEIVER_H
#define RECEIVER_H
#include "globals.h"
class MyEventReceiver : public irr::IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
device->getGUIEnvironment();
switch(event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
if (id == 101)
{
gameclock.setClockSpeed(1.0f);
gamespeed = 1.0f;
return true;
}
if (id == 102)
{
gameclock.setClockSpeed(0.0f);
return true;
}
if (id == 103)
{
gameclock.setClockSpeed(gamespeed);
return true;
}
if (id == 104)
{
if(gamespeed < 65535.0f)
{
gamespeed += 1.0f;
gameclock.setClockSpeed(gamespeed);
}
return true;
}
if (id == 105)
{
if(gamespeed < 32768.0f)
{
gamespeed *= 2.0f;
gameclock.setClockSpeed(gamespeed);
}
return true;
}
if (id == 106)
{
return true;
}
if (id == 107)
{
return true;
}
break;
default:
break;
}
}
return false;
}
};
#endif
I'm looking forward to hearing about bug reports, feature requests, and code optimizations or improvements.
You are free to do whatever, whenever you like with this code. Enjoy!