🔒 Locked
code organization
Advertisement
Original Post
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
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?
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.
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.
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.
Quote: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.
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.
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.
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.
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).
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.
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.
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?
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.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement