#10831 - Ruiner - Wed Sep 17, 2003 4:35 pm
Everything I have read in gba development says avoid virtual like the plague. But I have always used this kind of algorithm for state machines in my game.
Code: |
// Class GameState
{
public bool m_Active;
public GameState()
public virtual void Update()
public virtual void Close()
}
// Init game state
GameState CurrentState;
CurrentState = InventoryScreen.GetInstance;
// Game loop
{
ProcessInput();
CurrentState.Update();
Flip();
}
|
My question is that if this is as bad as everyone makes it sound then what is the efficient way of getting around it?
#10832 - niltsair - Wed Sep 17, 2003 4:40 pm
Use function pointers.
http://forum.gbadev.org/viewtopic.php?t=1459&highlight=void%2A+function+pointer
http://forum.gbadev.org/viewtopic.php?t=1734&highlight=void%2A+function+pointer
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#10833 - tom - Wed Sep 17, 2003 6:02 pm
uhh...you know, basically a virtual function results in a call via a pointer, which is pulled out of the object's virtual function table - the difference is, you don't have to mess around with function pointers yourself, instead the compiler will do it for you.
#10834 - sajiimori - Wed Sep 17, 2003 6:13 pm
tom,
If I recall correctly, the concern was that some compilers for gba do not handle virtuals correctly. Not sure which ones, as I haven't used C++ on gba...
#10835 - tom - Wed Sep 17, 2003 6:25 pm
sajimori: can't tell neither, i usually use c too, simply because i like it. if there was a bug with virtual functions, this would be a reason not to use them.
anyway, another reason people often bring up is that virtual function calls are slower than normal element function calls, which is of course true, but then replacing them with handcoded function pointers wouldn't give you anything (except more work=)
#10836 - niltsair - Wed Sep 17, 2003 6:48 pm
No, the problem with virtual function is that is has to look it up in a table first. To my knowledge, function pointer don't generate slowdown (correct me if I'm wrong).
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#10837 - Sweex - Wed Sep 17, 2003 6:55 pm
I've been using virtual functions throughout my code and haven't noticed any problems with them yet. As Niltsair pointed out the "problem" with virtual functions is that it will take a little bit of time to look up the correct function from the vtable before calling it. The impact of this is only minimal but you might want to avoid it when you have a lot of calls to virtual functions.
(Personally I don't care too much about the minimal vtable overhead as it makes programming a lot easier!)
_________________
If everything fails, read the manual: If even that fails, post on forum!
#10839 - sajiimori - Wed Sep 17, 2003 7:26 pm
niltsair,
You're wrong. ;-) The added indirection of a function pointer vs a regular function call usually adds 1 or 2 instructions, depending on the architecture.
Virtuals are usually the same as function pointers, speed wise. They are the same on x86 when using gcc 3.x, but I don't know about ARM7.
#10841 - niltsair - Wed Sep 17, 2003 7:47 pm
sajiimori -> Yeah, I guessed that there was 1 indirection overhead, which shouldn't lower performance badly. Also, I was hoping that the arm achitecture supported jump statement with one indirection :-)
But the problem with virtual is that you have to add one step over pointers, to find the actual pointers. Don't know how much of a slow down it is though.
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#10842 - torne - Wed Sep 17, 2003 8:30 pm
It depends where your vtable is. Remember, a 32-bit read from ROM takes 8 cycles with default wait state settings, thus, the additional indirection could take that long.
#10847 - col - Wed Sep 17, 2003 10:57 pm
Ruiner, the speed comparison between virtual functions and pointers is a bit of a red herring IMO.
I would suggest that you don't use classes to represent your states.
A simpler and more efficient way is to have each state represented by a function !
the active state is a pointer to function (or member function depending on the design)
Code: |
// Class GameState
{
public bool m_Active;
public GameState()
public virtual void Update()
public virtual void Close()
}
// Init game state
GameState CurrentState;
CurrentState = InventoryScreen.GetInstance;
// Game loop
{
ProcessInput();
CurrentState.Update();
Flip();
}
|
instead use something like:
Code: |
class Game{
private:
//declare state as a pointer to member function
(void)(Game::*state)();
//state funcions
void inventoryScreen(){
.....
};
void inGame(){
....
if(pressed inventory key){ //switch state
state = &Game::inventoryScreen;
}
};
void someOtherState(){
....
};
public:
update(){ this->*state(); }; //call via pointer to member func
Game() : state(&Game::inGame){
};
}
// Game loop
{
ProcessInput();
Game.Update();
...
}
|
[edit]
I forgot to mention, to use pointers to member functions, you need the latest devkitadv.
Its just as easy to do the same thing using static member functions and explicitly passing an instance pointer to the state function - you just need a slighlty different pointer syntax.
[/edit]
cheers
col
#10875 - Darkain - Thu Sep 18, 2003 8:36 pm
there is nothing rong w/ using virtual functions. the only problem is in some versions of GCC, it cant handle overriding multiple virtual functions. what this means is if you got virtual a() in class x and y, and then z inherits from both x and y, and you try to override virtual a(), it would only override it for one, but not both.
my entire game engine is all based around a class structure with a nice sound vitual table and inheritance. upon object creation, its base pointer is added to a pointer list, and from there, every instance of the said class is called upon when needed. this is a great way to handle multiple animations at one time, or multiple classes all accepting key input. :)
_________________
-=- Darkain Dragoon -=-
http://www.darkain.com
DarkStar for Nintendo DS
#10877 - sajiimori - Thu Sep 18, 2003 10:26 pm
Sounds like the "Listener" pattern from the GoF. I really liked using it, but I had some design issues regarding object ownership.
For instance, if I have Animation objects that "subscribe" to an Animator, who is in charge? When an Animation is deleted, does it need to unsubscribe, and thus know about Animator? If so, there's a co-dependency that causes ambiguities in object ownership.
Maybe that doesn't sound like much of a problem, but it starts getting hairy when the Animation is dependent on a Sprite, and the Sprite has to stop it's Animations when it's destroyed or else the Animation will have a dangling pointer, etc.
It sort of ruins the whole "encapsulation" part of OO, so I end up making Manager classes (to disambiguate ownership), which just means more code that's unrelated to what I want to do. Class explosions, maintenance nightmare...
That's not to say OO doesn't work, but I've definitely stopped trying to adhere to one particular design philosophy. Now I'm ranting, so I'll leave it at that ;-)
#10919 - KashinKoji - Sat Sep 20, 2003 10:55 am
col took the words right out of my mouth. My entry for the compo is designed in a way that looks almost exactly like his example.
I used not just function pointers for game states, but also for individual object states as well, which let me manage the object instantiations really easily with great autonomy and interaction. It was intuitive for me, and the OO approach definitely helps when the project you are working on keeps expanding, but it certainly isn't the only way to go about it I'm sure.