Jump to content

  • Log In with Google      Sign In   
  • Create Account

is there a better design for this interface?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 xDan   Members   -  Reputation: 193

Like
0Likes
Like

Posted 25 May 2010 - 11:57 PM

Hi. I'm making an interface for things that are "pausable" in my game. Originally I had this -
class IPausable
{
public:
	virtual ~IPausable(){}
	
	virtual void Pause() = 0;
	virtual void Resume() = 0;
	virtual bool IsPaused() = 0;
};
But now I've realised I need a kind of pause counter system, so that for example if Pause is called twice from different areas of code, then two calls of Resume should be required to un-pause the object. Now I'm thinking about this design -
class IPausable
{
	u32 pauseCounter;
	
public:
	IPausable()
	{
		pauseCounter = 0;
	}
	
	virtual ~IPausable(){}
	
	void Pause()
	{
		if (pauseCounter == 0)
			OnPause();
		
		pauseCounter ++;
	}
	
	void Resume()
	{
		pauseCounter --;
		
		if (pauseCounter == 0)
			OnResume();
	}
	
	bool IsPaused()
	{
		return pauseCounter > 0;
	}
	
private:
	virtual void OnPause() = 0;
	virtual void OnResume() = 0;
};
So now pause/resume logic in derived classes must be implemented in the OnPause, OnResume methods, and the top level IPausable interface handles the pause counting. However, this approach feels a bit wrong and hackish, to have the implementation code in the interface. I feel that perhaps I should have a separate PauseCounter class, which owns an IPausable class, or something, so pause counting is separated. Having said that, the solution above will work very nicely. Perhaps I am just being silly? :)

Sponsor:

#2 DarkZoulz   Members   -  Reputation: 106

Like
0Likes
Like

Posted 26 May 2010 - 12:47 AM

The above solution will work nicely. However, it is no longer a interface. It's an abstract class. I would (as you mentioned) create a base class implementation that inherits the interface and let the other classes derive from that.

#3 Captain P   Members   -  Reputation: 1092

Like
0Likes
Like

Posted 26 May 2010 - 12:48 AM

Quote:
Original post by xDan
But now I've realised I need a kind of pause counter system, so that for example if Pause is called twice from different areas of code, then two calls of Resume should be required to un-pause the object.

That would make your class very unpredictable to use. Calling resume might just happen to resume an object - or perhaps not. Yet the name clearly says 'resume'. Stick to the first design, unless you have very specific reasons not to.

Then again, how often will you really need pausable objects? What sort of game are you working on?
Create-ivity - a game development blog Mouseover for more information.

#4 DarkZoulz   Members   -  Reputation: 106

Like
0Likes
Like

Posted 26 May 2010 - 01:42 AM

Quote:
Original post by Captain P
Quote:
Original post by xDan
But now I've realised I need a kind of pause counter system, so that for example if Pause is called twice from different areas of code, then two calls of Resume should be required to un-pause the object.

That would make your class very unpredictable to use. Calling resume might just happen to resume an object - or perhaps not. Yet the name clearly says 'resume'. Stick to the first design, unless you have very specific reasons not to.

Then again, how often will you really need pausable objects? What sort of game are you working on?


I agree. Reference counting many times result in unpredictable behaviour. Wouldn't it be better if each pausable object just implemented it's own pause code. Why do you need the reference counting?

#5 xDan   Members   -  Reputation: 193

Like
0Likes
Like

Posted 26 May 2010 - 02:52 AM

I have a "World" object, that is pausable, which contains all 3D in game objects, and I have a top level "Engine" object that is also pausable. The world can get paused by pressing escape to view the typical game pause menu. The entire Engine gets paused when minimising or alt+tabbing from the app. Pausing the entire engine also calls pause on the World.

So I can have the situation where someone pauses the World by pressing escape, and then they alt+tab away from the app. Coming back to the app, engine.Resume() will also call World.Resume, and the world will be resumed when in fact it ought to remain paused until the user decides to leave the pause menu.

So that's the specific situation reference counting would resolve.

..

There are a few other pausable objects: sounds, plus a general "Updatable" interface that defines an Update method, which I thought ought to inherit from IPausable. (because while simply suspending calling the Update method may pause the object, there may be some instances where it needs an explicit Pause, one example being where the object must call pause on a Sound that is managed by a third party lib in a separate thread). I have a hierarchy of updated things - engine updates world updates some other things - so even if one Updatable object doesn't need to implement any pause functionality, it still must have the method to forward the pause call to objects further down in the hierarchy.

#6 xDan   Members   -  Reputation: 193

Like
0Likes
Like

Posted 26 May 2010 - 03:04 AM

On thinking about it I guess a solution is to use the original simple interface and only have reference counting in the World's implementation.

#7 DarkZoulz   Members   -  Reputation: 106

Like
0Likes
Like

Posted 26 May 2010 - 03:20 AM

I would put the pause logic in the World object. If the game needs to be paused for any reason, it would have to go through the World object. If the game is paused while already paused, let the World object contain a simple boolean flag. This way you can ensure that the IPausable methods are only called once per object in the World.

Pseudo code:

class World
{
bool isPaused = false;

function pause()
{
if (!isPaused)
{
isPaused = true;

foreach (obj in worldObjects)
{
if (obj is IPausable)
{
obj.Pause();
}
}
}
}
}


So the Engine would do something like: world.pause() if it needs to pause the game. Is there any reason why the Engine needs to be able to pause objects? Why is it pausable?


#8 elFarto   Members   -  Reputation: 206

Like
0Likes
Like

Posted 26 May 2010 - 03:46 AM

Wouldn't it be better to have an Updatable interface, with a single method update(float dt).

That way, to pause your engine, you just don't call the update method. When you resume you can just fiddle your time-step to make it look like a regular time-step even if 5 minutes of real time has passed.

Regards
elFarto

#9 xDan   Members   -  Reputation: 193

Like
0Likes
Like

Posted 26 May 2010 - 04:45 AM

Yes, true, I do have that Updatable interface. I guess the key problem is that some things are not even updated, yet still need pausing. i.e. as I mentioned, sounds, which are managed + updated by an external library, so the only way to pause them is by calling sound.Pause. (I do wrap these sounds though, so I could incorporate my ref counting in the Pause method if I wanted to)

The Engine does call World.Pause to pause the game. The engine needs to be pausable since it manages other things than the 3D world. (e.g. there may be GUI, or 2D logic that should still run while the 3D World is paused). Yet everything must be paused (with Engine.Pause) when the app is minimised.

I've considered simply in the Engine.Pause, keeping a cache of all objects previous pause state, which can be restored to the correct state when un pausing.

This may work, however I've now realised that even pausing only the World has the same problem as when pausing engine: some world objects may be paused already, and should not be resumed by either the world.resume or engine.resume.

So logic to remember previous pause states would have to be duplicated in World as well as Engine. And who knows, in the future, I might have a deeper hierarchy again...

Right now, ref counting is still looking inviting.

#10 iMalc   Crossbones+   -  Reputation: 2314

Like
0Likes
Like

Posted 26 May 2010 - 08:25 PM

I'd certainly consider going with the refcounting.

Back in the days where I programmed on the 680x0 Mac I remember that the calls for hiding and showing the cursor were ref-counted like this. Any method could hide the cursor and then show it when done, and inside that another method could do the same. The refcounting made sure that the inner methods didn't re-show the cursor.
So yeah it makes sense to me.

#11 Acid-Chris   Members   -  Reputation: 500

Like
0Likes
Like

Posted 26 May 2010 - 08:34 PM


virtual bool IsPaused() = 0;

Just as a sidenote, you should really make the method 'const':

virtual bool IsPaused() const = 0;


#12 xDan   Members   -  Reputation: 193

Like
0Likes
Like

Posted 26 May 2010 - 09:45 PM

Ok. I am now using ref counting. I'm still interested if there is any better design for the ref counting class though. Possibly there isn't.

#13 AlexKhomich   Members   -  Reputation: 100

Like
0Likes
Like

Posted 27 May 2010 - 12:41 AM

I like option with interface IPausable, its implementation in class Pausable for further reuse.

Also there are a bit of correction for your second variant of IPausable. Events OnPause/OnResume should be protected in other way you can't inherit that class.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS