SDL Game Engine: Friend Methods?

Started by
3 comments, last by GenuineXP 18 years, 5 months ago
Hello. I'm still working on an SDL game engine to use for a project I'm working on. It's a remake of the old DOS game called Jetpack. However, my game will be isometric. :-) Anyway, I'm having a bit of trouble organizing the classes used in my engine. I posted a week or two ago asking for some help with these classes. At this point, I have the following. GEngine is the main game engine class. It's used at the primary interface and ties all of the other engine classes together. Users of the game engine need only to create an instance of this class. AudioManager handles audio via SDL_Mixer. It allows for easy playback and minipulation of music and sound, providing easy to use methods and managing chunks and channels automatically. GraphicsManager is a new combination of two manager classes I originally created: SurfaceManager and PaintManager. It was suggested that I combine these classes, especially since SurfaceManager handled a lot of SDL specific details. This class handles SDL surface allocation, ensuring that files aren't loaded more than once or unloaded while still in use by game objects like Sprite. This manager class also handles drawing surfaces. Timer, which was previously called TimeManager, handles frame rates and timing, calculating averages, various cycle rates, and time factors used to produce frame rate independant motion and animation. These classes constitute the game engine. With this modular/manager approach, the engine can be organized neatly into components and each component can be updated independantly without having to worry about making changes throughout every class (unless the interface is altered). The cool thing about this is the modular setup. After a GEngine has been created, it's functionality can be accessed by specifying the system you need.
GEngine* pGame = new GEngine;

// INITIALIZE THE ENGINE...

pGame->Deactivate();                              // GENERAL ENGINE FUNCTIONALITY
pGame->Timer()->SetFrameRate( 30 );               // TIMER FUNCTIONALITY
pGame->Audio()->MusicPlay( "BGMusic.ogg", 5000 ); // AUDIO FUNCTIONALITY
pGame->Video()->RequestSurface( "MyImage.png" );  // VIDEO FUNCTIONALITY

//...

Anyway, here's what I want to ask about. Originally, the GEngine class provided almost all of the functionality of the game engine, including drawing objects to the screen. GEngine maintains a list of pointers to generic Obj objects. To draw these correctly (espcially in an isometrically projected world), these objects were sorted. Because GEngine maintains this list, I thought that that's where the sort method should stay. I have a problem though. It's now GraphicsManager's job to draw objects. I don't want to make the sorting method of GEngine public (accessible to the user of GEngine). What should I do? Does the sorting method belong in GraphicsManager? GEngine provides an accessor method to get a copy of the list of objects that it maintains, so this is possible. If the method should stay where it is (in GEngine), should I use friend functions? If so... how do those work? I've never used that capability of C++ before. Also... should the actual blitting of surfaces and the whatnot be handled within GraphicsManager? It seems to me that it should. This way, I can hide SDL specifics where they should be. After discovering problems with loading surfaces indiscriminately into memory (and creating a class to manage allocating SDL surfaces), I decided that my Sprite class should only worry about containing state information and not handling the surface it's associated with or actually drawing it. It should maintain information like the current frame, frames per row, total number of frames, etc., and pass this information to GraphicsManager to be drawn. Is this right? Sprite objects shouldn't have to worry about the specifics of how to draw themselves...? I'm sorry if this post is lengthy. Any help is greatly appreciated. I know that my questions are more conceptual than syntactic. In either case, knowing how to use friend functions would be nice too, so even if you don't have any suggestions for organizing my classes, some help with them would be excellent too. Thanks! :-D
Advertisement
Quick question: if Timer, Audio, and Video are already part of the engine...why not make a graphics manager a part of the engine? Each instance would probably want its own graphics manager, you know?

So, you could provide a private engine method to do the sorting, correct? There's no need for an end-user to touch the method, but it would be ideal to use it internally -- and, though I might argue that geometry sorting would belong to the graphics manager, if you must leave it in the engine...well, I've got to recommend using a private method.

Maybe I misread something in the post, but it seems that you want the engine to manage audio and timers at least, correct? I'd assumed that the engine's Timer(), Audio(), and Video() functions would act as pointers to the subsystems, so, in my mind, making the graphics manager a member of the engine and geometry sorting as a private method makes the most sense to me (again, if it must be a part of the engine and not the graphics manager).
Things change.
Thanks for the reply. :-)

Let me just clear this up a bit.

The Timer(), Audio(), and Video() methods of GEngine simply return pointers to the various engine classes. GEngine actually has a pointer to each of these classes which it instantiates and maintains.

I think I may have confused myself. I need GraphicsManager to be able to draw a sorted list of objects. The sorting method is part of GEngine, but because GraphicsManager is a member of GEngine, it should be able to use the sorting method even if it's private! :-P

My mistake. Sorry.

Still... does the sorting method really belong in GEngine? GEngine contains and maintains the list of game objects. However, GEngine itself has no use for sorting these objects (yet); they're only sorted so that they're drawn correctly.

My question about Sprite and GraphicsManager still stands as is.

Thanks again!
Quote:Original post by GenuineXP
I think I may have confused myself. I need GraphicsManager to be able to draw a sorted list of objects. The sorting method is part of GEngine
, but because GraphicsManager is a member of GEngine, it should be able to use the sorting method even if it's private! :-P
Why is the sorting method a part of the engine? It's like I mentioned several times above -- shouldn't managing graphics be left up to the graphics manager? I assume your manager is aware of some type of Sortable or Object type, but it doesn't know how to sort -- whereas your engine shouldn't actually be aware of this Object type. At the moment, I can't think of a time when it would directly need to deal with the objects, especially if it can directly retrieve a pointer to a class (GraphicsManager) that should be handling these objects anyway.

Quote:Original post by GenuineXP
My question about Sprite and GraphicsManager still stands as is.

Do Sprites need to know how to draw themselves? Maybe they shouldn't. I'd say, for the purpose of testing and reusability, you completely leave the actual handling of graphical types to the manager.

Use of "friend" classes or methods is often (but not always) a significant sign of a design flaw, whether it's in the code or in the way you're going about solving the problem. In this case, I don't see why you need to let a friend touch your privates (...), because your class already contains the would-be friend.

And now, I sleep. Night.
Things change.
Thanks for all the help, Boku San. :-)

I have a lot of recoding to do. I think I'll just gut my classes and start from scratch; they're very messy right now (and possibly unstable).

It'll be rewarding to see this run once I flesh out these classes again. Thanks again! Oh... and if anyone could elaborate on how friend functions/methods/classes work, that'd still be great. I don't think I'll be needing them, but I'd like to understand just how that works just in case.

This topic is closed to new replies.

Advertisement