PDA

View Full Version : Help needed with sprite class design



ianatwork
12-12-2007, 11:41 AM
I have a design question and am interested in your views. In my game I use images as tiles to display the background and all the bits that move around and attack you. I have created a base class call TBaseImage which just contains a few properties such as the SDL surface, the size of the image and if its visible. I then have a TBaseSprite class that derives from TBaseImage which adds a few properties and methods such as a virtual Update method and methods to kill and Resurrect it. I then come to the various game specific sprites that derive from TBaseSprite. For example, I have an "Alien" sprite which overrides the update method and modifies its x,y position (NB: Update is called every frame on visible/alive sprites). I then realised that some sprites that can be shot should provide the following functionality: GetScore, HitCount, Rewards etc. I then created a class called "TDestructibleSprite" which derives from TBaseSprite. I could then derive my "Alien" sprite from TDestructibleSprite and get the extra functionality. If I have a tile that can't be destroyed I just derive it from TBaseSprite. Then I realised that some sprites need to be animated so I started to think about creating a class called TAnimatedSprite which would contain functionality so that each Update the image would change to show the animation. But what if I wanted a sprite that was both animated and destructible ? Delphi doesn't support multiple inheritance so some of this functionality is going to have to be added into one of the existing classes. My question is, should I look into using interfaces ? Can anyone recommend which classes should contain which functionality. Should I look into Subclassing / Composition ?

Shown below is my current sprite class structure:


TBaseImage
|
TBaseSprite
| |
TDestructibleSprite TAnimatedSprite
| |
TAlienSprite TAlienSprite



Ian

VilleK
12-12-2007, 12:14 PM
Although interfaces would work, I always try to go for an simpler approach with little use of inheritance. Perhaps a TSprite class with members such as IsDestructable, IsAnimatable, GetScore (just return 0 when not applicable). I find this keeps my code simpler and easier to change when trying out new features, and I can always refactor into a class inheritance tree later if that solution becomes attractive later on when I have written code and used the classes. Less risk over early over-design that way.

jdarling
12-12-2007, 01:48 PM
Instead of sub-classing all over the place have you thought about using a class tree that supports sprite types?

Here is an example:
TSprite
|
----------------------------------------
| |
TControlledSprite TStaticSprite
| |
---------------------------- ... TRock ...
| | |
TPlayer TAIMOB TNPCMOB

Now in addition to this you would have another set of classes for actions, examples would be; WalkNorth, WalkSouth, Die, TakeObject. You then link the action types into a list of TActionClassType in the parent sprite. Thus to expand a sprite you simply create a new action type class and add it to the root class type that affects the most child types properly. When you process an interaction you will actually process it at the action level, so if you have a collision you would fire the TAction.OnCollision handler instead of the sprites collision handler. The action collision handler could fire the sprites if necessary.

This is just another way to look at a state machine, as you can also check and change state on any frame if your TAction has a frame handler.

Or, you could always use a scripting language such as Lua and just use Multi-Inheritance by scripting the link.

PS: I wouldn't tie a sprite to an image, I'd tie the image to the action. Thus allowing you to break the images for actions/animations into separate files if you need.

chronozphere
12-12-2007, 01:51 PM
I think interfaces could be a nice option here, but it might make your code quite complex, while this is not nessecary. I noticed that you are trying to make your application REALLY abstract, by using quite a large inheritance hierarchy. I think you don't need to do that.

How much functionality would a "Destructable" sprite have, compared to the "Undestructable"? Is that difference bigger than between "Animated" and "non-animated" sprites. These questions might help you choose which class you want to inherit from TBaseSprite.

How many different sprites are you going to use in this project. If you don't use very much of them, i would suggest you just program the "destructable behaviour" inside the TAlienSprite class, instead of making a seperate class/interface.

You can also include "destructable behaviour" in TBaseSprite. You can then add a boolean, indicating whether to enable destructable behaviour for a sprite. You could make a protected IsDesturctable property and do this:


constructor TAlienSprite.Create;
begin
inherited Create;

IsDestructable := True;
end;


This way, you don't have the mess around with tons of classes for ton's of different functionality. Just include it into an abstract class, and add some protected properties, to enable/disable it.

Plenty of options eh?... Hope to have helped you ;)

arthurprs
12-12-2007, 02:11 PM
I have only 2 type of sprites

TImage
|
|------- > TStaticSprite
|--------> TSprite


very simple and works well, in case of destructable sprites just derivate it from TSprite

ianatwork
12-12-2007, 04:37 PM
As someone pointed out, there is a lot of abstraction going on by using all these classes. A lot of the problems came about because I had developed a library to make writing games easier. The base sprite class was an almost empty framework allowing users to add all the extra functionality by building classes on top. Look through all your comments it soon became clear that I could add so extra functionality to the base class without that being specific to a particular game type.

I've just moved some code about and everything still compiles so nothing has broken (yet :D ). Thanks for all you comments and helpful advice.

Andreaz
13-12-2007, 06:07 AM
I'm using the version described at the following page in the upcomming version of the Phoenix entity system, its really good as it seperates the behaviour from the rendering of the enitys (sprite could be considered as a representation of an entity)

http://www.gamasutra.com/features/20050414/rouwe_pfv.htm

Mirage
13-12-2007, 05:56 PM
It's a very good design approach to separate entities itself (game objects) and their representation (sprites).
I'd be using separate class hierarchies for sprites and objects.