• Advertisement
Sign in to follow this  

code organization

This topic is 4216 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to make a simple game using SDL with c++, and I know how to do everything that I want to do with it, but... I just can't figure out how to organize it and keep it manageable. All it is is a tilebased two player game. And I'm trying to do it all OOP, but I dont see how it can all fit together. I was trying to do it with a few different classes, a 'game' class, 'map' class, a 'tile' class, and a 'player' class. The only problem is that I'm trying to keep it spread out across files, so I can keep track of whats going on, but everything starts to bunch up in the main loop of the 'game' class, because its the class that has access to the main surface i draw to the screen.' Anyways, I'll describe what i'm trying to do in a little more detail in case anyone wants to give me some ideas as how to put it together. I want to have two viewports, and each player controls a little avatar and moves around the map, can fight with guns, and then after one wins the round is over, and the winner has can buy some upgrades from a different screen, and then they go at it again. It's really not that complicated, and I have a shell of it working already, but with everything the way it is, i'd have to rewrite the whole thing to add on a feature or whatever. Any help or comments would be welcomed, -bender

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
I hope your name really isn't Bender.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Thanks for clearing that up.

Share this post


Link to post
Share on other sites
There's no right or wrong way to do this, just readable and un-readable and efficient and inefficient :)

How about moving the drawing stuff into its own class and providing an interface for some common functionality?

Share this post


Link to post
Share on other sites
Ok, it seems i'm incapable of writing a post that has a point, so forget that first post and give me some advice on this instead. In SDL i have a main class that has the handle to the screen i'm rendering, what is the best way of allowing member classes to draw to the screen too, pointers?

Share this post


Link to post
Share on other sites
thanks for the reply light bringer, that kind of goes right into my question :)

Share this post


Link to post
Share on other sites
I don't know much about SDL (or C/C++ for that matter), sorry. I'd ask for some code to look at but I'm going to bed right now. If the functionality is exposed by an sdl object and there is only one, passing a pointer is probably a good idea.

Share this post


Link to post
Share on other sites
Quote:
Original post by glBender
Ok, it seems i'm incapable of writing a post that has a point, so forget that first post and give me some advice on this instead. In SDL i have a main class that has the handle to the screen i'm rendering, what is the best way of allowing member classes to draw to the screen too, pointers?


Personally, I would say don't allow other classes to draw to the screen - instead, allow them to tell your main class what they want to be drawn. In other words, in each frame your main class asks the other classes "what do you look like at the moment, and where in the game world are you?" They can return a pointer to an SDL_Surface and x,y coordinates, and the main class can draw them.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
Quote:
Original post by glBender
Ok, it seems i'm incapable of writing a post that has a point, so forget that first post and give me some advice on this instead. In SDL i have a main class that has the handle to the screen i'm rendering, what is the best way of allowing member classes to draw to the screen too, pointers?


Personally, I would say don't allow other classes to draw to the screen - instead, allow them to tell your main class what they want to be drawn. In other words, in each frame your main class asks the other classes "what do you look like at the moment, and where in the game world are you?" They can return a pointer to an SDL_Surface and x,y coordinates, and the main class can draw them.


Erm, I'd say that's exactly backwards. You want to push responsibility out of main classes/functions and closer to the leaf classes. That's pretty much the point of encapsulation - everything knows how to do its own thing, rather than requiring central classes to know how to do everything.

In the case of a global resource like a screen handle (keeping in mind that I haven't even looked at SDL, so I don't know the specifics there), it's one of the rare cases where it generally makes sense to have it available to all code that's going to be doing any drawing.

Share this post


Link to post
Share on other sites
Quote:
Original post by JasonBlochowiak
Erm, I'd say that's exactly backwards. You want to push responsibility out of main classes/functions and closer to the leaf classes. That's pretty much the point of encapsulation - everything knows how to do its own thing, rather than requiring central classes to know how to do everything.

In the case of a global resource like a screen handle (keeping in mind that I haven't even looked at SDL, so I don't know the specifics there), it's one of the rare cases where it generally makes sense to have it available to all code that's going to be doing any drawing.


I don't agree. I don't think rendering code should be scattered across all your objects. Instead I think it should be centralised in one class. It's a matter of personal preference though.

Share this post


Link to post
Share on other sites
I've tried it both ways and I prefer the scattering right now (with a centralized interface that delegates after sorting). Something to keep in mind though is that it's more difficult to switch out the renderer if the rendering code is all over the place.

Share this post


Link to post
Share on other sites
Quote:
Original post by JasonBlochowiak
Erm, I'd say that's exactly backwards. You want to push responsibility out of main classes/functions and closer to the leaf classes. That's pretty much the point of encapsulation - everything knows how to do its own thing, rather than requiring central classes to know how to do everything.
It encapsulates, yes; but it violates another fundamental principle of object orientation, which is focused responsibility. What you've now got is a class that handles both logic/AI and rendering. You might add sound or physics, and by the same approach it'd handle those as well. What you get is a class that does a great many different things, which is dangerous, because it becomes harder to keep track of exactly what it does and does not handle.

If you want to preserve encapsulation, then you can use a third object - a 'RenderableToken' that contains coordinates, an SDL_Surface*, and any other data that the renderer object needs to do its job for a particular game object.

Taking the concept to its logical conclusion gives you a client-server model for rendering. You create your Renderer object - the server - and have it store a list of pointers to RenderableTokens. When a new game object - a client - is created, it requests a new RenderableToken from the server, who creates it and adds it to the internal list before returning it to the client. Now, all the client needs to do is update the data in the RenderableToken as it moves and animates, and the server can just pass through all the current RenderableTokens each frame and render them all. Nobody needs to know anything about the internals of anyone else, so it's all encapsulated, and it keeps the objects in the system focused in their responsibilities: The game object is responsible for game object behaviour, the Renderer is responsible for rendering, and the RenderableToken is responsible for storing the information needed to render one game object.

Share this post


Link to post
Share on other sites
In case you don't know, there is a function SDL_GetVideoSurface which returns the current display surface. With this, you can avoid passing the screen pointer around all the time or using a global.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
Quote:
Original post by JasonBlochowiak
Erm, I'd say that's exactly backwards. You want to push responsibility out of main classes/functions and closer to the leaf classes. That's pretty much the point of encapsulation - everything knows how to do its own thing, rather than requiring central classes to know how to do everything.


I don't agree. I don't think rendering code should be scattered across all your objects. Instead I think it should be centralised in one class. It's a matter of personal preference though.


Hmm, in re-reading what I posted, I don't think it quite reads like I meant it to, and there's probably more agreement here than we initially thought.

What I meant to get across is:

1) Central game management classes shouldn't have knowledge about the specifics of individual game components.

2) Responsibility should be pushed as far away from central classes as makes sense. So, my game class shouldn't know the details of how to draw any of the game elements. The game elements shouldn't know the details of how they get rendered, but they should know how to specify (at a fairly abstract level) how they want to appear. Game specific render components know how to translate the game objects' appearance requests into a combination of requests to base render objects. The base render objects know the specifics of the rendering API they're using, such as DirectX or OpenGL.

Heh, I wrote this before reading superpig's post. Although his and my terminology differ some, we're pretty much saying the same thing. I completely agree that game objects shouldn't contain the details of their subcomponents - they should aggregate the subcomponents as self-contained units, and make requests of those subcomponents.

For what it's worth (and especially for anyone wondering if this is viable In The Real World), this approach has shipped SKUs on a high-performance, cross-platform engine, including targeting systems with weak CPU performance, and multiple core rendering APIs (custom PS2 API, DX on XBox, and the GL-ish API on GameCube).

Share this post


Link to post
Share on other sites
Simple game organization will typically end up with lists of different objects ordered by functionality.

Thus, you'll have a list of "things that want to be rendered" and a list of "things that want to play sounds" and a list of "things that want to update game state N times a second" etc.

The central renderer just needs to traverse the list of things to render (which might be a list of sprite object instances in a 2D game), and render them. For greater effect, make this list into some snazzy datastructure like a quad- or octree. The sprite class knows how to actually render stuff (or, more likely, add rendering requests to your graphics core, which then batches by texture and blats data out at the end of the frame).

The central world simulation core just needs to step through the objects added to its "object that wants to simulate" list, and make all the objects collide/simulate. For bonus points, use a physics simulation package for implementing the simulatable objects (like ODE, PhysX, etc).

The game objects, then, become responsible for creating the right kinds of objects (renderable, simulatable, user-input-reader, etc), registering them with the right central systems, and then plumbing information between them (simulation position outputs to rendering position input, etc).

The trick is to use narrow interfaces for each concept within your game, so that each subsystem doesn't need to know about anything else, except the entity class needs to know (in its implementation) about the other interfaces it manages -- the public entity interface, however, probably doesn't expose any of the other interfaces, so it's still fairly well isolated.

Some of this was already said, but I figured I'd put it all into one collected post, to show the main thread of how orgniazation falls out.

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
Simple game organization will typically end up with lists of different objects ordered by functionality.

Thus, you'll have a list of "things that want to be rendered" and a list of "things that want to play sounds" and a list of "things that want to update game state N times a second" etc.

The central renderer just needs to traverse the list of things to render (which might be a list of sprite object instances in a 2D game), and render them. For greater effect, make this list into some snazzy datastructure like a quad- or octree. The sprite class knows how to actually render stuff (or, more likely, add rendering requests to your graphics core, which then batches by texture and blats data out at the end of the frame).

The central world simulation core just needs to step through the objects added to its "object that wants to simulate" list, and make all the objects collide/simulate. For bonus points, use a physics simulation package for implementing the simulatable objects (like ODE, PhysX, etc).

The game objects, then, become responsible for creating the right kinds of objects (renderable, simulatable, user-input-reader, etc), registering them with the right central systems, and then plumbing information between them (simulation position outputs to rendering position input, etc).

The trick is to use narrow interfaces for each concept within your game, so that each subsystem doesn't need to know about anything else, except the entity class needs to know (in its implementation) about the other interfaces it manages -- the public entity interface, however, probably doesn't expose any of the other interfaces, so it's still fairly well isolated.

Some of this was already said, but I figured I'd put it all into one collected post, to show the main thread of how orgniazation falls out.


I was wondering would you have a generic entity class which contains all the information about an entity and the functions like add_to_render_list() or somthing? If so would you need to call the functions to add to different lists each time you wanted it drawn etc? Would you have a general list of the entity's too?

Share this post


Link to post
Share on other sites
Thanks for all the reading guys, got me thinking. And thanks simian for pointing out that function. I've got a simple version of the game going in a console with chars isntead of tiles, and it seems to fit together, keeping code seperated and stuff. Thanks again

Bender

Share this post


Link to post
Share on other sites
Quote:
Original post by kzar
I was wondering would you have a generic entity class which contains all the information about an entity and the functions like add_to_render_list() or somthing? If so would you need to call the functions to add to different lists each time you wanted it drawn etc? Would you have a general list of the entity's too?


The way I do this is to insert the aggregated subsystem component into the relevant list. For example, if a game object has a physics component, it gets added to the physics simulation; if it has a renderable component, that gets added to the "stuff to render" list, etc. The game object itself gets added to the game's list of, well, game objects.

In my implementation, the lists are persistant. For example, you don't have to repeatedly say game.AddToRenderList(myRenderObject) every frame - just once when you create the render object. How you handle destructor functionality and the implications of list auto-removal are very dependent on your development philosophy. In my current codebase, destructing an object that's still in an active list is considered A Bad Thing, and I throw an assert - my leaning is to require that client code properly dispose of their components at destructor time. The pain of that requirement is eased considerably by my use of reference counted smart pointers.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement