12 Hour Game Clock

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

12 Hour Game Clock

Post by Midnight »

12 Hour Game Clock
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;
}
Timer.h

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
GameClock.cpp

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;
}

GameClock.h

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
And now an example application. just replace the model file, the font, the texture, and the skybox image to anything you like and you should get a similar effect. I'll try to find some hosting and post mine in the future.

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;
}

Globals.h

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
Receiver.h

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!

8)
Last edited by Midnight on Sun Jun 14, 2009 4:35 am, edited 2 times in total.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

Here is the complete source, binary demo application, and resources.

http://www.filedropper.com/12hourclock

http://www.mediafire.com/?sharekey=5438 ... f6e8ebb871

One of these should work.. stupid file hosting sites.
MasterM
Posts: 128
Joined: Sat Oct 20, 2007 2:38 am
Location: netherlands antilles, Curacao

Post by MasterM »

Nice, this is one of the best clocks i seen in a while...
Will definitively use it in my project!
C++ is not the Magdalena...it takes patience...shes like the well aged prostitute, it takes years to learn her tricks! she is cruel...laughs at you when you are naked...
Life of a programmer == Const abuse
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

What nobody wants to criticize my nooby code this time?

Really? You know I'm going to assume it's just perfect then right? lol (not really I am smart enough to know I'm an idiot actually)

COMMENT! :roll:
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

just looked over it and saw:

MyTimer::Update()

obviously this is missing the object...first i thought oh he trpped me by making that method static....but no it just won't work and all other access points to MyTimer are used like that as well.....

but i guess that was intended to just get the people screaming at you again^^
anyway other than that i guess its good.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

Sudi wrote:just looked over it and saw:

MyTimer::Update()

obviously this is missing the object...first i thought oh he trpped me by making that method static....but no it just won't work and all other access points to MyTimer are used like that as well.....

but i guess that was intended to just get the people screaming at you again^^
anyway other than that i guess its good.
No, to be honest dorth is right I'm a noob. (to an extent)
I don't learn by reading books I learn by writting code and reading online articles and that's probably a nooby way to do it.

SO, that being said the reason why I did that is because trying to declare my class as a pointer in the program causes a segfault error and it doesn't work.

Keep in mind that the gameclock inherits the functions of timer.

So, you may know better then me. is that a bad thing? it actually does work btw at least for me.
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

Ha didn't see that it inherits from Timer....blubb just forget my comment^^

Btw i don't think that the other people here actually learn different^^

And no idea about your segfault but i guess u didn't init the pointer then?
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

Sudi wrote:Ha didn't see that it inherits from Timer....blubb just forget my comment^^

Btw i don't think that the other people here actually learn different^^

And no idea about your segfault but i guess u didn't init the pointer then?
try it yourself i have a premade binary & source with codeblocks project.

try declaring GameClock* gameclock; ( instead of without * in globals)

then change the accessor "." to "->" naturally and then compile with debugger if you're smart. bam segfault.

anyone know why??

Simply put why can't I declare and use my class as a pointer?

Do I need a callback in gameclock to timer to init() timer? is that why?
Sylence
Posts: 725
Joined: Sat Mar 03, 2007 9:01 pm
Location: Germany
Contact:

Post by Sylence »

Like Sudi said, you need to initialize your pointer with

Code: Select all

gameclock = new GameClock();
and delete it when you no longer need it with

Code: Select all

delete gameclock;
Software documentation is like sex. If it's good you want more. If it's bad it's better than nothing.
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

Sylence wrote:Like Sudi said, you need to initialize your pointer with

Code: Select all

gameclock = new GameClock();
and delete it when you no longer need it with

Code: Select all

delete gameclock;
ohh ho ho ho hmm, makes sense I'm just wondering why I've never seen this actually explained in tutorials before.

Anyways I took a long hard look at irrlicht source and some of the current issues with the clock and I've come to a conclusion. And that is altering the speed of the timer is a bad thing for several reasons. One reason is because the speed is limited by the frames per second. my counters will fall behind if the speed goes above the frames per second and this will cause it to overload and break at a certain point. a while loop caused problems.

Basing animators on the timer is bad also because the whole thing screws up your delta. Ok so maybe delta isn't that important or making a delta function isn't that difficult to do. But do you realise how difficult messing with svn patches and all that garb can be?

Imagine if I had an svn patch for all the different things I've tried to fix.. you'd have enough to just seperate from the main project and reading it from the official would become easier. Not to mention you could patch the official into your version.

I say screw that. Make a patch to alter the internal use of the timer itself for animators then base your animations on a seperate more efficiant timer built into something like the dusty engine. (a task engine)

So in final conclusion: I'm removing the setSpeed() and basing it purely on a clock this way the timer isn't compromised. the next step up from this junk would be a task engine and custom node animators.

... how was that for somebody without higher education?
netpipe
Posts: 670
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

Cool, was looking for this !!
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
netpipe
Posts: 670
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

what

Post by netpipe »

hmmm it seems to be wrong, my system says 2 am the clock on there says 11:53 am ...

http://www.xup.in/dl,20602954/12hour_clock.7z
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Well, just a guess (lazy to browse the code), but this clock may have nothing to do with the real time (your system time). It simulates virtual time. You`ll need to include some system headers and change it a bit, or find another clock, which does what you need.
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

at best it's some code you can work from, you have permission to do so. The general design of this clock was experimental and deemed to be basically worthless. the idea was to make a GAME TIMER which syncronized with irrlicht's internal timer, the problem was that it interfered with other parts of the timing and naturally had bugs.

there is another clock, or this being particularly simple compared to most things can be done in some custom fashion. good luck with your projects.
netpipe
Posts: 670
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

glad to see your still alive and kicking midnight ;) i found out the limitations of irrlicht's current timers using this code. submitted a patch hopefully we can get better time functions included in 1.8. the last epoch in seconds is a bit much to deal with haha!
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
Post Reply