Sign in to follow this  

How do you design YOUR 2D sprite class?

This topic is 4835 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 am intent on writing my own sprite class from scratch, without any tutorials, but I thought I would cheat a bit and maybe ask around and see how others are doing is so that I can learn from their experiences. The problem I have is that there are so many types of animations! There are looping animations (walking, etc.), animations that play once and stop (explosions). A big part of animations is not only about flashing different pictures in a certain order, but also moving the entire sprites! Some sprites move back and forth, they fly in the air in circles and figure-8's, and so I figure I need a sprite class that encapsulates all of these properties. My basic idea so far is this. I have a class called cSprite that has the following properties: * A pointer to a surface where the frames are stored (all on one bitmap). * A "cells[]" array which contains the x,y,w,h of each animation cell on the bitmap. * An "animations[]" array that stores each of the animations that the sprite will do. * Member data to hold the x and y position of the sprite, r for rotation, v.x and v.y for velocity, and a.x and a.y for accelleration. * Functions to update the velocity (based on the current accelleration and time lapsed since last frame), and position (based on the current velocity and time lapsed since last frame). The cells[] array is an array of objects from my cCells class, the properties of which are simply x,y for the upper-left corner of the cell and w,h for the width and height of that animation cell. The animations class contains a frames[] array which basical is there to list the cells being used in the animation, and what order they should be in. The animations class also contains member variables to define whether the animation loops continuously, a fixed number of times, or not at all. The frames[] array is an array of objects of a cFrames class, and it basically has two main properties: a) which cell to display, and b) how long to display it.
GASP! That's a lot of work. I haven't even written the code yet and so I don't know how it will work out. One thing I haven't quite figured out yet is how to make the animations themselves affect the position, velocity, and/or acceleration of the sprite. If I want to have a boss character that flies in a figure 8 pattern during one if its animations, I need a way for the animation itself to update the sprite movement information. I'm thinking of adding some more arrays to the Animations class, like velocity[] and position[] and acceleration[], that each define what changes (if any) in these properties need to take place, and when. I fear I'm making this way too complicated though, especially for my first sprite class. Has anyone tackled a sprite class before? And if so, what do you think? Even if you haven't tackled a sprite class before, I'm sure you have some great ideas too. :o)

Share this post


Link to post
Share on other sites
heh, I was just happy to get a single image rendered to the screen.

Anyways, back to the question:

I don't. Anything that modifies the position, velocity, acceleration, content, or anything else of a sprite doesn't belong in the class. [in my design of course, my next design might be different, and your milage may vary...] Any modifications like that are done in my particle system class, not the simple image class.

Share this post


Link to post
Share on other sites
I would personally leave the animations out of the sprite class (the animations that involve moving the entire sprite, not the ones that just flip through frames). The overall movement of a sprite is going to be very dependent upon your specific game, and thus the functionality should be handled by your game, not by a general purpose sprite class. The movement of the sprite could be a prerecorded movement, could be based on AI code, could be based on physics code, could be based on user input, etc. 'Tis not the sprite's personal responsibility. All the sprite really needs to know is how to display a certain frame at a specified location on the screen.

Otherwise, at a glance, it looks good.

[edit]Telastyn beat me, but yeah, I [obviously] agree with him.[/edit]

Share this post


Link to post
Share on other sites
Ah, ok good insight. Thanks.

I tend to be to literal when designing classes (for example, "sprites move therefore movement should be part of the sprite class!") and so often I overlook things like this.

Share this post


Link to post
Share on other sites
i agree... i personally feel that a sprite should only care about what images it has and how to render those images and what images to render at a given time. movement and things like this should be seperate, at least in my opnion. a sprite is really just a graphic, not an actual moving entity. the moving thing should be a Player, Enemy, Npc, etc, which could have a Sprite object as a member of the class which controlled which frame to draw. the class could also have other members which took care of movement and things. thats just my opinion

Share this post


Link to post
Share on other sites
I designed a system very much like gimbal_lock's. I store the animation and frame information in the individual sprite class. I also have the sprite's position, velocity, and other attributes stored there as well. Personally I don't see a problem storing these inside of the sprite class. It's more of a mangement issue than anything else.

Take the sprite's position for example. By storing the position in the individual sprite object, drawing them at the right location becomes trivial. As you loop through each sprite, you get the position and draw. The alternative is to store the sprite's position elsewhere, say, an another array or data structure. If you have a large number of sprites, that may become hard to handle.

By encapsulating this type of data, each sprite object knows where is should be drawn, how fast is should move, which animation should be displayed, etc... Making management of the objects quite easy. It all depends on what you define as a "Sprite". If a "Sprite" to you is just an image, then this type of design is overkill. But, if a "Sprite" is a player-controllable object, then this design is a good place to start.

Share this post


Link to post
Share on other sites
Quote:
Original post by grasshopa55
Take the sprite's position for example. By storing the position in the individual sprite object, drawing them at the right location becomes trivial. As you loop through each sprite, you get the position and draw. The alternative is to store the sprite's position elsewhere, say, an another array or data structure. If you have a large number of sprites, that may become hard to handle.


If you do go down this road, though, it is best to ensure that the actual image is stored in a manager or external source to the sprite so that you don't have several copies of the same image floating around in memory. Personally, I keep position and movement and such outside of the sprite so that all entities using that sprite can use the same instance (via a Sprite Manager of course) and do the necessary calls to render itself (by calling a Draw() method on the Sprite with the according values).

Share this post


Link to post
Share on other sites
I definately agree with what's been said here. A Sprite class should just be responsible for managing the actual image data.

Think about it like this: If your sprite class does more than that, you'll have to duplicate image data for each instance of an enemy. have 10 baddies? you'll need 10 sprite classes if it stores things like position, velocity, etc and that means duplicating the images 10 times, thats a ton of memory wasted. Its only the position, velocity, frame, etc that change so it makes sense to to have that in some sort of entity class which references a sprite class.

My sprite class does nothing more than return a pointer to a frame of an animation as well as allocate/free the resources it used.

Share this post


Link to post
Share on other sites
and actually, I don't even keep velocity, or the image the sprite renders in the sprite either...

in basic terms:


sprite{
rect;
color;
*image;
}


Anything more complex then builds upon this [adding a velocity for instance]. The image is actually handled by my resource manager. No need to have 20 billion copies of 'armyman.png' in memory...

Share this post


Link to post
Share on other sites
Quote:
Original post by bL0wF1sH
If you do go down this road, though, it is best to ensure that the actual image is stored in a manager or external source to the sprite so that you don't have several copies of the same image floating around in memory. Personally, I keep position and movement and such outside of the sprite so that all entities using that sprite can use the same instance (via a Sprite Manager of course) and do the necessary calls to render itself (by calling a Draw() method on the Sprite with the according values).


I wholeheartedly agree here. My system is geared for a fighting game, so essentially there is a one-to-one ratio of images to object. In my case, the chances of having multiple copies of the same images in memory is very slim. But, say I was building an RTS, then creating a Sprite Manager would be ideal as my existing system would be problematic. So I guess it comes down to what you are going to use the system for.

If I was to start over and build a more generic sprite handling system, I would use the Manager concept, and it has proved quite flexible in other parts of my project.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by grasshopa55
I designed a system very much like gimbal_lock's. I store the animation and frame information in the individual sprite class. I also have the sprite's position, velocity, and other attributes stored there as well. Personally I don't see a problem storing these inside of the sprite class. It's more of a mangement issue than anything else.

Take the sprite's position for example. By storing the position in the individual sprite object, drawing them at the right location becomes trivial. As you loop through each sprite, you get the position and draw. The alternative is to store the sprite's position elsewhere, say, an another array or data structure. If you have a large number of sprites, that may become hard to handle.

By encapsulating this type of data, each sprite object knows where is should be drawn, how fast is should move, which animation should be displayed, etc... Making management of the objects quite easy. It all depends on what you define as a "Sprite". If a "Sprite" to you is just an image, then this type of design is overkill. But, if a "Sprite" is a player-controllable object, then this design is a good place to start.


i see your point. but this all comes down to preference i believe. i could easily still encapsulate it so that the the Sprite knows where it shouldbe drawn, how fast it should move, which animation should be displayed, etc. You could simply just make a function of this class which receieved those paramters. then you can look at it as though a sprite is a dummy object and his owner tells him what to do and when to do it. its just as easy to manage this way, too.

Share this post


Link to post
Share on other sites
ack, that AP was me ^^^^

Quote:
Original post by Ravyne
Think about it like this: If your sprite class does more than that, you'll have to duplicate image data for each instance of an enemy. have 10 baddies? you'll need 10 sprite classes if it stores things like position, velocity, etc and that means duplicating the images 10 times, thats a ton of memory wasted.


i dont see how this is an issue. why would you need to duplicate an image just because the sprite class owns it? there are many ways around this. you could have some sort of manager (std::map) which did a lookup to see if the image was already loaded, if so it just returns a pointer to the already laoded image. OR, you could make the image a static member of the class, and only load it once, when the first enemy who needs it is loaded.

Share this post


Link to post
Share on other sites
Another benefit to not including this information (velocity, position, frame, etc.) in a sprite class is that you can easily use that sprite class in many different programs or games, without having to rewrite portions of it. Some games won't need velocity. Some games will need more than velocity. The same with all the other values. Only put into a sprite what a sprite needs for just about any game you might make. At least, that's how I approach it.

Share this post


Link to post
Share on other sites
I too am currently designing my own Sprite class. I thought of a design where the animation would be stored in its own class. The Sprite would contain the image data( an instance of pixel class ) and the Animation class would call upon update the sprites ChangeImage( std::string to_what ) method and possibly the MoveBy( int x, int y ) methods.

This way the Sprite class would not have to worry about the different types of animation out there. And I could code new types of animation by simply derivating the animation class.

And the best thing is I get my sprite class running rather easily and I can add complex animations later.

Comments about this design are welcome.

Share this post


Link to post
Share on other sites
Quote:
Original post by Agony
Another benefit to not including this information (velocity, position, frame, etc.) in a sprite class is that you can easily use that sprite class in many different programs or games, without having to rewrite portions of it. Some games won't need velocity. Some games will need more than velocity. The same with all the other values. Only put into a sprite what a sprite needs for just about any game you might make. At least, that's how I approach it.


is code re-usability really that important? whats stopping you from simply selecting the int xVelocity variable and pressing backspace? [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by graveyard filla
is code re-usability really that important? whats stopping you from simply selecting the int xVelocity variable and pressing backspace? [smile]
That's where it starts, just one backspace... I can tell you from experience that it will likely add up andcause plenty of headaches in the end, as you have to sift through what lines/parts of lines need removal. I like code reusability. A lot. So I would say that it definitely is that important. Each to his own, though.

Share this post


Link to post
Share on other sites
Personally, I find that if I don't make my code very very generic and reusable, I tend to code myself into corners where a class only does a specified task. Then I need something else similar, but with a slight change. Now there's 2 classes that do almost the same thing, and changes need duplicated...

A big mess.

Share this post


Link to post
Share on other sites
3 classes.

CBasicSprite, CAnimatedSprite and CBaseEntity.

I used a basic sprite for thing's like HUDs, where they won't be moving / animated.

Animated sprite derives from basic sprite, and keeps named indexes of images (ie, "Running" runs at 25ms and uses so and so frames).

My base entity (which all entities derive from), has a pointer to an animated sprite, which is cached by a sprite manager. Base entity handles movement and position, sprite is merely a pointer to an image and some animations. The entity also handles what animations to play, I really don't see how you could do it any other way.

All sprite's images are cached by an image manager.

Very modular, very expandable, very easy to use. I like it.

Share this post


Link to post
Share on other sites
I'll mention how I've dealt with this, because it's somewhat different than most of what's been suggested here...

In games like this, I've avoided the concept of a sprite that publicly exposes its graphics data. The sprite object exposes where it is in terms of x-y coordinates, a rectangle that represents a platform used for collision, and a function WantsToMove that returns a vector (direction, velocity) and a Draw function that takes the graphics object that's drawn upon. There's a bit more to it than that, but that's the jist.

The World that contains all the sprite objects is responsible for moving them around. Each sprite gets polled where to move and the World is the one that actually relocates it. That way, the sprite updates its graphics internally based on how far and in what direction the World moved it, and the display information never needs to be exposed outside. The sprite always draws itself.

This way, the sprite instance is responsible for whether its animations loop, or are static, or explode. The class is reusable in any type of game that follows the same type of model.

Share this post


Link to post
Share on other sites
I guess it depends on who you define as owning the "movement" of an object. If you have a CGameObject that stores movement information, than that information should not be duplicated in the CSprite also. However, if you decide that CSprite should own the information than that is fine as long as it isn't duplicated in the CGameObject. I agree with graveyard that the issue of image management is easily solved regardless of where movement information is stored. Remember, in the development (and especially in game development), un-needed duplication is an evil that should be slain on sight.

I personally prefer to have my CGameObject equivalent "own" the movement information, and then for my sprite to be a simple Draw(...) call. This way, the sprite is extremely dumb. You simply tell it what frame to draw and where to draw it. That's just me though.

<Rant>

And on a different note, I will say this:

ReuseMethod.CopyAndPaste != Code.IsReusable;

Copy and pasting code is not reusing code. Anytime you catch yourself copying and pasting, STOP! Refactor your code. Do you need another abstraction? What is needed to prevent copying and pasting? Over time, your reuse-able library should be as simple as referencing your libraries (or dlls). If you need specific behavior, that's what polymorphism and encapsulation or for. Either inherit a new class from a reusable base class in your library, or create a new class that encapsulates the functionality of the class and extends it.

Remember, Design Patterns and Refactoring are your friends.

</Rant>

Share this post


Link to post
Share on other sites
I generally start by building a base sprite class that is nothing but a static, immobile image. From there, I will add features into child classes, like animation, then collision detection, with the intent that each individual class is useful in some purpose. The static base class is handy for background objects, the animated class is useful for background animations, and then the "solid" sprite is good for actual objects in the game.

But that's just me. It's not big deal of a component.

Share this post


Link to post
Share on other sites
This is a great thread. A lot of good ideas here. Judging the replies I think the consensus is:

1. Manage your image data appropriately. If you are planning on drawing the same image many times, store those images in a Sprite Manager and have your game objects request a reference from the Manager.

2. Be sure about object ownership. As bL0wF1sH mentioned, if your game object stores various common information like position, velocity, etc... don't store it in your Sprite object. It's just not necessary. But, if you treat your Sprite object as a game object, as I have done, it can be easier to manage. But don't forget point #1 in this case.

3. Design what you need. As with any project, the needs of one may differ from another. Choose the design that best fits your application and do your best to be as efficent as possible.

Please feel free to add if I've missed something!

Share this post


Link to post
Share on other sites
Quote:
Original post by graveyard filla
ack, that AP was me ^^^^

Quote:
Original post by Ravyne
Think about it like this: If your sprite class does more than that, you'll have to duplicate image data for each instance of an enemy. have 10 baddies? you'll need 10 sprite classes if it stores things like position, velocity, etc and that means duplicating the images 10 times, thats a ton of memory wasted.


i dont see how this is an issue. why would you need to duplicate an image just because the sprite class owns it? there are many ways around this. you could have some sort of manager (std::map) which did a lookup to see if the image was already loaded, if so it just returns a pointer to the already laoded image. OR, you could make the image a static member of the class, and only load it once, when the first enemy who needs it is loaded.


I agree. My previous post was based off the description the OP gave and what I had read into it. Sprite, as we've seen is a very vague term. It could be a simple reference to an image somewhere, or a complete entity within a game.

In my system a "sprite" is a container which contains one or more images comprising an animation. My manager class would manage said sprite objects. Perhaps "sprite" is a poor choice for a name in my case. "Sprite" carries alot of connotations with it, I'll probably change it to Graphic or something similar.

Manager classes are definately the way to go, especially in DDraw since you loose your resources when the game window looses focus and they have to be reloaded.

Share this post


Link to post
Share on other sites

This topic is 4835 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.

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