To pool game entities or to use an update loop

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

also, you have to keep this in mind and always carry this at the back of your ....

remember the good ol days? remember the time when they said model view controller (mvc) was fine-n-dandy?

well, mvc is still fine-n-dandy.

don't forget about it.
Image
Taymo
Posts: 55
Joined: Mon May 22, 2006 1:06 am
Location: Colorado Springs - CTU
Contact:

Post by Taymo »

So what would you provide as a practical solution to a message queue? Say I strike an enemy within my sword radius; how do I tell the enemy that it got hit? This type of approach?:

Code: Select all

bool Update()
{
if(physics.collision(this))
{
    EntityID id = physics.getIntersecter(this); //er, whatever you do..
    CEntity* hero = entityPool.getObject(id);
    hero.doDamage(this->attackPoints);
}
return true;
}
So I guess it depends on if I want to update the hero directly or save messages in a queue to be read on the next frame?

P.S. My idea for a message system wouldn't use a queue but more like the code above, where:

Code: Select all

void sendMessage(Message m){
    CEntity* entity = entityPool.getObject(m.receiver_id);
    entity.readMessage(m);
}
This code seems redundant, although.. but the message system could implement delayed messages and such features in itself which would increase robust-ness.
Ride the Spiral Development:
spiralride.blogspot.com
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

/wave at roger :)

@ taymo:

Theres a few things to consider when designing a message system:

1) should I use messages in the first place?
2) should I use a queue for my messages?
3) what does a message look like?

I'll discuss these in reverse, since understanding the last two will help you with the first.

3) what does a message look like?
In my experience there are three basic ways to encode a message, in increasing complexity.
* a simple integer, usually representing values from an enum
* a message 'type' and some parameters, usually kept together in a struct (see irr::SEvent)
* a bit stream (such as a string array)

Looking at your hero.doDamage(dmg) you might think, this is a message of the first type. However, doDamage() is not a message handler.. it only does one thing. If you had a function like hero.doCommand( TAKE_DMG ), that would be a message handler since you could also tell it hero.doCommand( MOVE_FORWARD ). Though in those cases, you might need extra parameters so you'd probably upgrade to the 2nd kind like this: hero.doCommand( TAKE_DMG, dmgAmmount ); or hero.doCommand( MOVE_FORWARD, speed, bWhileJumping );

One extra note here: a bit stream requires much more processing to handle than an integer. With an int, a simple switch() statement will suffice; however, with something like a character string, you have to do string compares and that gets very expensive very fast. On the other hand, using integers requires you to pre-define your type enumeration in a header file somewhere where both the sender and the receiver can include it, and requires re-compiles to handle new types of messages.

2) should I use a queue for my messages?

A queue does not make your messages better or worse, it simply organizes when they are dispatched. Consider a system where sending a message to one object causes that object to generate several more messages and send them out, which in turn causes other objects to generate more messages. Suddenly, you've started an avalanche that is going to block the CPU and cause system lag. With a queue, you can organize how many messages get dispatched per frame and you can prioritize them.

A queue has a second organizational purpose, and that is helping determine who they get dispatched to. A physics event emitter should not have to know what objects are waiting for it to trigger, it should be a simple dumb object that senses an event and then sends a message. By sending that message into a queue, and having listeners register to that queue, you ensure your message gets to the appropriate objects while keeping a layer of abstraction between a simple physics entity and whatever entities are trying to listen to it.

1) should I use messages in the first place?

Finally the real question! Hopefully by now you've realized that some portions of your game should use messages and some should not. People tend to go too far once they have implemented a message system and use it everywhere.

If you have a piece of code that should send a short signal to a known object for immediate processing, don't use a message system.

If you have a piece of code that should be modular, needs to send one of several possible messages, and to an undisclosed type of object or series of objects -- use a message system.

As to whether or not to use a queue, or what your messages should look like; see the above. Just remember not to try and shoot a fly with a cannon.
a screen cap is worth 0x100000 DWORDS
Taymo
Posts: 55
Joined: Mon May 22, 2006 1:06 am
Location: Colorado Springs - CTU
Contact:

Post by Taymo »

Thanks keless for the lengthy and informative post. I think I have enough background to get something runnin'. Also, thanks to everyone who provided input, appreciate it.
Ride the Spiral Development:
spiralride.blogspot.com
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

So then I just realizaded that my game is "message way" disigned. But without the queue.
So when should I have a queue?
In fact my game is alway adding new funtionalitys that makes the message system extremly useful. But should I add a queue?.
The reason that I maybe found for this is order in execution aber, maybe not, i don't know
:?

What do you think?

Another question but about OOP design:
Do you see my example?, well I use a enum type for Actions and only a function ("doAction(Action)")that handles with them.
You use (if undertood correctly) a function in your "door" object for every one of my "actions".

which is the better?

Thanks
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Answer: it depends on your requirements. Really, it does.

If you want to control when a given object reacts to messages, including limiting how often it can react to them, then implement queuing and action the messages during (e.g.) the once-per-frame processing for each object. You may want to do this if (e.g.) you expect messages frequently to spawn other messages, and you don't want to get caught up chasing long chain reactions of messages.

If you don't need that level of control or limitation, then just actioning them immediately is fine.


As regards whether to implement a generic message handler, or an explicit method per action, again you (and only you) can decide which one best meets your requirements.

You're using an enum for your messages. That's fair enough if it's all that you require, but a more generic method would to have a message type plus some parameters (like a Windows message), or a union, or a handler that accepts a base object type which might be a reference to a derived class that holds the full data for each action.

All of that wrapping and unwrapping adds complexity, and your handler has to have a big switch(), or function pointer array to decide how to actually handle each action. That adds some overhead, and at some point you have to actually nail down the full list of allowed actions, so it's not (ultimately) more flexible than just having one explicit method per action, unless your handler offloads the work to a scripting subsystem like Lua or Codemonkey - and even then, you still have to define the messages somewhere. You may prefer a clean interface with a single generic handler, or you may prefer an explicit interface that unambiguously expresses a well defined and limited design. It's largely a matter of choice, requirements and design.

I just waxedlyrical on the evils of getting too caught up in finding the 'perfect' design or implementation, so I'd suggest that if you think your current method is good enough, then it is good enough, or at least a better one can only be found through experience.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

you can also look into this page about the observer pattern.

http://en.wikipedia.org/wiki/Observer_pattern

i'm planning on using this pattern for sending updates to the observer, for example the progress bar observer. while the parser is the subject doing all the work.
Image
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Hi, thanks I didn't knew about queues on game development. It is rely usefull.

Yes, I have knolodge of desing patterns and have used when corresponds.
From Gamma I hava used Factory with facade for some implementation of interfaces (like the "managers" (physic, graphic, etc.). I try to even desacopling from irrlicht and rest of engines. (not a easy task at all!).
For this manager I have use too observer and singleton (both from gamma too).
But as the self Gamma remarck "patterns not should be used just becasue, even more, they must be used the lest posible".
But what I most use and I think the most important cause they are use all over the enter design of every software are the GOF and GASP patterns which people allways say "they are intuitive" "they are obvious", but they don't aply them, and most cases apply them are realy usefull.

But anyway I have some doubts that I have always had:
When you disging a "normal" software(information system sofware) you have rarely problem about the cpu uses. But with games you must "always" render, ask for physics, ia, etc. So it becomes critical this loop for updating every part.

Rodergord sing in one post about the obious of have a 100% busy cpu if whe have a while !end{ update}.
So, what are the techniques for making a game withoug having this problem?
Sorry about my english. I am in a hurry.
Thanks.
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

vsk:

if you don't write code for a living, you can ignore design patterns, it's ok. in fact, it's better staying away from it, like miles away, not a single pattern in sight.

but you know, i work for a company that reviews my code, i've been humiliated many times and burned at the stake twice, before being thrown in the river tied to a chair. yet, i survived to tell the tale.

when i write code, i do it not for satisfying myself, but for those who read and later conjure up hail-n-brimstone to fall on my head.

believe me, a lot of software developers like to read "fun" code. it's been proven to prolong life and stimulate brains to orgasm.

that's why i write code like that, it's the culture i'm in. they've been accustomed to the usage and verbiage that makes all apis look the same.

api design is pretty much approaching maturity because software developers have already chosen the look-n-feel of the perfect api.

you can be wild or civilized, it's your choice. i wish i could write wild code, but all this years of brain-controlled behavior, it's now locked-in to my system.

so be wary of this culture, if you want to stay wild.

;-)
Image
Taymo
Posts: 55
Joined: Mon May 22, 2006 1:06 am
Location: Colorado Springs - CTU
Contact:

Post by Taymo »

dlangdev wrote:vsk:

if you don't write code for a living, you can ignore design patterns, it's ok. in fact, it's better staying away from it, like miles away, not a single pattern in sight.

but you know, i work for a company that reviews my code, i've been humiliated many times and burned at the stake twice, before being thrown in the river tied to a chair. yet, i survived to tell the tale.

when i write code, i do it not for satisfying myself, but for those who read and later conjure up hail-n-brimstone to fall on my head.

believe me, a lot of software developers like to read "fun" code. it's been proven to prolong life and stimulate brains to orgasm.

that's why i write code like that, it's the culture i'm in. they've been accustomed to the usage and verbiage that makes all apis look the same.

api design is pretty much approaching maturity because software developers have already chosen the look-n-feel of the perfect api.

you can be wild or civilized, it's your choice. i wish i could write wild code, but all this years of brain-controlled behavior, it's now locked-in to my system.

so be wary of this culture, if you want to stay wild.

;-)
That brought a tear to my eye.. :cry:















P.S. Just kidding..
Ride the Spiral Development:
spiralride.blogspot.com
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Well I program for living too and must think about the rest of the one who are gonna check modify, extend, mantain my code. Thats why I try to do it in this way, but even if I have not to, I think I'd do it anyway, it is usefull for my self, I have reopen proyects with year of old that I have made and have put in action on it almos instantly thanks to the application of this desings. And believe me, my lecture compression of code (even mine) sucks :oops:
OF COURSE, it all depends what we do, if you are on team large sotware desing, it has been proove that this methods works (no matter what say the Extreme Programming experts :P (just kidding ;)).
Buf if you work on research and investigation (beatufull area) you must NOT close your mind to this approach like you correctly explained. You must have the "wildness" necesarry to success on this area.
But even on sotware development strict, you must not be so close, like the same Gamma in the first page of his book explain.
More else, writing more exactly the gamma words he says " patterns not must be use just becasue, even the less posible, not like some teacher force their studente to apply decens of patterns". I just laught when I read for first time the sentence, cause my teachers were doing the same thing :D .

But comming back to the other question, any idea how this is solved?
That our game doesn't consume 100% cpu?
Thanks.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Using a device->sleep() to achieve a target frame rate will reduce your CPU load. You could try something like this (which also skips rendering if the frame rate begins to lag badly - you don't need to do this unless you have something other than rendering going on that's sensitive to framerate). Note that because of the granularity of the timer and of sleep() that this will only ever give you an approximate frame rate, but it should bring down CPU load.

Code: Select all

	const s32 DESIRED_TIME_PER_FRAME = 1000 / 30; // e.g. 30 fps
	const s32 MINIMUM_WORTHWHILE_SLEEP_TIME = 10;
	s32 requiredSleepTime = 0;
	s32 lastFps = 0;
	u32 lastFrameTime = device->getTimer()->getTime();

	while(device->run())
	{
		// Only render if the game isn't lagging behind its required frame rate.
		if(requiredSleepTime >= -DESIRED_TIME_PER_FRAME)
		{
			driver->beginScene(true, true, SColor(255,100,101,140));
			smgr->drawAll();
			guienv->drawAll();
			driver->endScene();
		}
		else
		{
			// Don't skip more than every 2nd frame
			requiredSleepTime = 0;
		}

		s32 fps = driver->getFPS();
		if (lastFps != fps)
		{
			core::stringw str = L"FPS (should be ~30): ";
			str += fps;

			device->setWindowCaption(str.c_str());
			lastFps = fps;
		}

		u32 now = device->getTimer()->getTime();

		// Work out how much time we have to idle.  Note that this value can
		// go -ve, in which case we want to catch up rather than idle.
		requiredSleepTime += DESIRED_TIME_PER_FRAME - (now - lastFrameTime);

		// Only sleep if it's worthwhile
		if(requiredSleepTime >= MINIMUM_WORTHWHILE_SLEEP_TIME)
		{
			device->sleep((u32)requiredSleepTime);
			requiredSleepTime = 0;
		}

		lastFrameTime = device->getTimer()->getTime();
	}
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Thanks!.
But, should I take some cares if I have physic->updates and the rest of logic updates or not?

Thanks again.
Post Reply