Sign in to follow this  
Madster

generalizing game classes

Recommended Posts

Hi. I've been having trouble organizing my game classes. My latest attempt involved several Actor classes for a simple Space Invaders clone: PlayerActor, AlienActor and ProjectileActor. a World class held instances of them and was responsible for calling AI and Update functions according to the elapsed time (World::Update(unsigned int dt);), and also for calling each Actor's render function from World::Render(screen). Now, the thing is that each Actor had its private data but for calculating interactions between them, World needed access to them. Everyone became friends with the world (each Actor class had public: friend class World;) I assume there are a zillion ways to organize game classes and objects. What are the most common? what's yours? Direct messaging between actors? What about data ownership and game state to maintain consistency in a networked game? What about separating Actors by instance and type? (I just made the type bits static, but that meant the memory was held for the duration of the program.. sorta singletonish and kinda messy) Also... how do I get rid of passing a screen pointer (SDL_Surface*) around for each and every thing that needs to render itself? All opinions or clarifications (or explanations!) are welcome :) thanks

Share this post


Link to post
Share on other sites
I used to have the same problem with organizing my classes. When I started writing a design document I was amazed at how quickly things started to clear up and come together. If you don't know UML diagrams you should learn them, as they are very helpful for organizing your classes. Here is an example of my UML class organization diagram that I pulled from the latest version of my design doc.

Share this post


Link to post
Share on other sites
Quote:
Original post by Madster
My latest attempt involved several Actor classes for a simple Space Invaders clone: PlayerActor, AlienActor and ProjectileActor. a World class held instances of them and was responsible for calling AI and Update functions according to the elapsed time (World::Update(unsigned int dt);), and also for calling each Actor's render function from World::Render(screen).

This is a very reasonable overall design. You might also want to split the actor type into a game object type and a renderable type, since AI/game-logic and rendering are (or should be) not related. However, that might be overkill for a simple game.

Quote:
Original post by Madster
Now, the thing is that each Actor had its private data but for calculating interactions between them, World needed access to them. Everyone became friends with the world (each Actor class had public: friend class World;)

The usual solution to handling interaction between objects is "double dispatch". Look it up. It is not simple, so it is not always the best solution.

In general, "friend" is a poor solution to getting at values in an object. It is like giving a friend access to your WOW account and telling her that she can only use it for certain things. If the World needs to get certain values, make accessor functions for them or make the values public. If that causes problems, then think about how you can improve the details of the design.

Quote:
Original post by Madster
Also... how do I get rid of passing a screen pointer (SDL_Surface*) around for each and every thing that needs to render itself?

While this may seem inconvenient, it is probably the right thing to do.

One alternative is using global variables, and you have here the classic convenience vs. maintainability/extensibility/complexity tradeoff.

Another thing you can do (as I wrote above) is to separate game logic from rendering so that only the rendering code has to deal with the SDL_Surface.

Another solution is for the Actor::Render function to simply call a function in the renderer saying "render me using this data". That way all the rendering details (such as the SDL_Surface) are only seen by the renderer. This is related to the Visitor pattern. Look it up.

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
In general, "friend" is a poor solution to getting at values in an object. It is like giving a friend access to your WOW account and telling her that she can only use it for certain things. If the World needs to get certain values, make accessor functions for them or make the values public. If that causes problems, then think about how you can improve the details of the design.


But also consider the possibility that the World is trying to do work on the Actor's behalf, that the Actor really should be doing by itself. This is IMX the most common reason people put in more accessors than they need, or have "design problems" that are actually quite trivial to get around once you are looking at things straight.

Quote:
Original post by Madster
Also... how do I get rid of passing a screen pointer (SDL_Surface*) around for each and every thing that needs to render itself?


(1) While this may seem inconvenient, it is probably the right thing to do.

(2) One alternative is using global variables, and you have here the classic convenience vs. maintainability/extensibility/complexity tradeoff.

(3) Another thing you can do (as I wrote above) is to separate game logic from rendering so that only the rendering code has to deal with the SDL_Surface.

(4) Another solution is for the Actor::Render function to simply call a function in the renderer saying "render me using this data". That way all the rendering details (such as the SDL_Surface) are only seen by the renderer. This is related to the Visitor pattern. Look it up.[/quote]

(Numbers added for reference)

(4) is often just a way of accomplishing (3), though. :)

Related to (2) is (5): store the thing (or a handle thereto) as a member variable. However, this is unlikely to be a good fit for SDL_Surface*s and Actors. It's designed to handle the case where any given Actor is always rendered to the same Surface (or the target Surface rarely changes), but different Actors need to be rendered to different Surfaces in general. (If you had more than one particularly important Surface - i.e. the screen area; possibly a few buffers - then I imagine you wouldn't be asking the question in the first place, right? ;) )

Share this post


Link to post
Share on other sites
Cool.

I see, I'd just have to throw the pointer around once.
I used to do that on creation, but now I see that if I had separated the renderer I'd only need to 'inject' once.

Also, now I understand how to separate the renderer, lack of this knowledge is what got me into the mess in the first place :P

Creating a full actor using parts (renderable, AI, gamedata) makes a lot of sense.

thanks!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I wouldn't suggest making data in classes accessible in the public interface. This just breaks OO principles. Like others have said, you're liking having the World do a lot more work on actors then it needs too.

Also remember to take into account things that cannot be rendered, like triggers.

Another idea is to have your scene graph determine what is to be rendered and give the renderer access to the objects data (via reference I'd say). This way it gets a link to the mesh, material, etc.

UML is a great skill to learn and use. I am not a fan by far of flow charts, but to get ideas out quickly they're great for higher level things (I dislike fine detail ones).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this