Trevor Dunbar
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« on: January 04, 2009, 12:00:23 PM » |
|
Can someone help me cook up a animation class for C++?
An animation needs to consist of frames, which can be added dynamically- thus frames would be it's own struct/class. Then frames would consist of time per frame shown, sprite frame to use, character offset, etc.
|
|
|
Logged
|
Toucantastic.
|
|
|
Gravious
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #1 on: January 04, 2009, 12:10:29 PM » |
|
I'm working on one of these at the moment, I'd show you what i have so far, but its not tested yet! ![Sad](https://forums.tigsource.com/Smileys/derek/sad.gif) When its running, if you still need help I'll let you look, see if what I'm doing is any use
|
|
|
Logged
|
One day I'll think about doing something to stop procrastinating.
|
|
|
J.G. Martins
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #2 on: January 04, 2009, 12:24:57 PM » |
|
I'm no expert, but further separation might be a good idea.
First off, simple images (no actual X,Y positioning, just the image data) should be in one class. Then you could have an animated sprite class that defined sequences of images.
And finally, your displayable on-screen class, that would have position coordinates and a pointer to an animated sprite class, or possibly several, if you want your character to have multiple animations (walking, running, etc). This way, all the information regarding animations only exists in one place.
The animated sprite could be as simple as an array of Image* and a counter (where in the animation you are), along with nextImage() and previousImage() calls.
I hope this helped!
--- edit ---
When you say dynamically, do you mean that an animation will have a variable amount of frames at different times? Or can you know before-hand how many frames each animation will have? Typically, I presume, you'd know how many frames an animation has. In that case, like I said, I suggest a normal array, which you can access directly.
If you plan on modifying the animation itself by adding or removing sprites in mid-game, I suggest using STL's List. I haven't touched STL in a long time, but I know it's a bit more complicated than the above array suggestions, only it avoids creating new arrays all the time to minimize unused space or increasing space.
Watch how you access it though, because using list.get(i) has to perform i iterations, while an array uses a single operation. I suggest looking up iterators (those ugly things, eesh). Java is so much prettier!
But anyway, again, I hope it helps a little, even though it's a little off-topic!
|
|
« Last Edit: January 04, 2009, 12:31:17 PM by Anvilfolk »
|
Logged
|
Gold is for the mistress -- silver for the maid -- Copper for the craftsman cunning at his trade. "Good!" cried the Baron, sitting in his hall, "But iron, cold iron, is the master of them all." --- Rudyard Kipling
|
|
|
|
Trevor Dunbar
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #4 on: January 04, 2009, 01:11:55 PM » |
|
I already have a sprite class set up- it's part of rendering TO the direct x scene. The animation class should just tell the sprite what frame to use during our current game loop
I wanted an animation class where you can do this: psuedo code-
Frames class- SpriteCell, TimeInFrames, offset, nested CollisionBox class -end
Create animation blahblah: Animation comes with : -frames[0]
ANIMATION *Ani = &blahblah;
//Class function AppendFrame Ani.AppendFrame(&blahblah, SpriteCell, TimeInFrames, offset, &CollisionBox) Ani.AppendFrame(&blahblah, SpriteCell, TimeInFrames, offset, &CollisionBox) Ani.AppendFrame(&blahblah, SpriteCell, TimeInFrames, offset, &CollisionBox)
now blahblah animation looks like this: Animation now has: -frames[3]
Then do the same thing with an animationSet, which just stacks animations together in a nice container
|
|
« Last Edit: January 04, 2009, 01:19:13 PM by Draco9898 »
|
Logged
|
Toucantastic.
|
|
|
Javilop
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #5 on: January 04, 2009, 01:17:36 PM » |
|
It is really necessary to set the frames on real time? Why not having them in an XML file in which you can define as many sequences as you wish (like I showed you)?
|
|
|
Logged
|
|
|
|
Trevor Dunbar
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #6 on: January 04, 2009, 01:20:55 PM » |
|
I suppose that makes sense. Adding frames doesn't have to be during run-time. But can the animation have a variable number of frames once created I don't want every animation to take up 50 frames by default
I'm also going to need to create a crappy animation tool that creates something like an encrypted animations file.
|
|
|
Logged
|
Toucantastic.
|
|
|
Javilop
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #7 on: January 04, 2009, 01:37:49 PM » |
|
I suppose that makes sense. Adding frames doesn't have to be during run-time. But can the animation have a variable number of frames once created I don't want every animation to take up 50 frames by default
I'm also going to need to create a crappy animation tool that creates something like an encrypted animations file. Have you check out the link I provided to you? http://www.indielib.com/wiki/index.php?title=Tutorial_04_IND_AnimationOk, I'll put an example here: <?xml version="1.0" encoding="utf-8"?> <animation> <!-- frames declaration --> <frames> <frame name="Rock1" file="..\resources\animations\advance\Rock_Avanza_01.png" offset_x="2" offset_y="2" /> <frame name="Rock2" file="..\resources\animations\advance\Rock_Avanza_02.png" offset_x="2" offset_y="2" /> <frame name="Rock3" file="..\resources\animations\advance\Rock_Avanza_03.png" /> <frame name="Rock4" file="..\resources\animations\advance\Rock_Avanza_04.png" /> <frame name="Rock5" file="..\resources\animations\advance\Rock_Avanza_05.png" /> <frame name="Rock6" file="..\resources\animations\advance\Rock_Avanza_06.png" /> <frame name="Rock7" file="..\resources\animations\advance\Rock_Avanza_07.png" /> <frame name="Rock8" file="..\resources\animations\advance\Rock_Avanza_08.png" /> <frame name="Rock9" file="..\resources\animations\advance\Rock_Avanza_09.png" /> <frame name="Rock10" file="..\resources\animations\advance\Rock_Avanza_10.png" /> </frames> <!-- sequences declaration --> <sequences> <sequence name="rock_advance"> <frame name="Rock1" time="150" /> <frame name="Rock2" time="150" /> <frame name="Rock3" time="150" /> <frame name="Rock4" time="150" /> <frame name="Rock5" time="150" /> <frame name="Rock6" time="150" /> <frame name="Rock7" time="150" /> <frame name="Rock8" time="150" /> <frame name="Rock9" time="150" /> <frame name="Rock10" time="150" /> </sequence> <sequence name="rock_2"> <frame name="Rock5" time="150" /> <frame name="Rock4" time="150" /> <frame name="Rock3" time="150" /> <frame name="Rock1" time="150" /> </sequence> </sequences> </animation>
First you define all the frames (the sprites) (as many as you want). Later you can define as many sequences as you want too. Using references to the frames. You can also set a collision per frame. Here it is the tutorial: http://www.indielib.com/wiki/index.php?title=Tutorial_08_CollisionsExample: <?xml version="1.0" encoding="utf-8"?> <animation> <!-- frames declaration --> <frames> <!-- Sword Master 1 --> <frame name="sword1" file="..\resources\animations\sword_master\sword_master01.png" collision="..\resources\animations\sword_master\sword_master01_collisions.xml" /> <frame name="sword2" file="..\resources\animations\sword_master\sword_master02.png" collision="..\resources\animations\sword_master\sword_master02_collisions.xml" /> <frame name="sword3" file="..\resources\animations\sword_master\sword_master03.png" collision="..\resources\animations\sword_master\sword_master03_collisions.xml" /> <frame name="sword4" file="..\resources\animations\sword_master\sword_master04.png" collision="..\resources\animations\sword_master\sword_master04_collisions.xml" /> <frame name="sword5" file="..\resources\animations\sword_master\sword_master05.png" collision="..\resources\animations\sword_master\sword_master05_collisions.xml" /> <frame name="sword6" file="..\resources\animations\sword_master\sword_master06.png" collision="..\resources\animations\sword_master\sword_master06_collisions.xml" /> <frame name="sword7" file="..\resources\animations\sword_master\sword_master07.png" collision="..\resources\animations\sword_master\sword_master07_collisions.xml" /> </frames> <!-- sequences declaration --> <sequences> <!-- character 1 --> <sequence name="sword_attack"> <frame name="sword1" time="1000" /> <frame name="sword2" time="1000" /> <frame name="sword3" time="1000" /> <frame name="sword4" time="1000" /> <frame name="sword5" time="1000" /> <frame name="sword6" time="1000" /> <frame name="sword7" time="3000" /> </sequence> </sequences> </animation>
And a collision file is something like this example: <?xml version="1.0" encoding="utf-8"?> <bounding_areas> <circle id="rocket_boy_head" x="120" y="65" radius="65" /> <triangle id="rocket_head" ax="352" ay="152" bx="300" by="127" cx="300" cy="175" /> <rectangle id="engines" x="20" y="187" width="106" height="30" /> <rectangle id="engines" x="20" y="105" width="40" height="30" /> </bounding_areas>
You have all the sourcecode for doing this on IndieLib repository. Or you can directly use IndieLib engine, this would be easier and faster: you will be able to focus on game logic and I'll be able to help you better in this and in future tasks
|
|
|
Logged
|
|
|
|
Hideous
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #8 on: January 04, 2009, 02:02:27 PM » |
|
Man, you pimp IndieLib everywhere.
|
|
|
Logged
|
|
|
|
Javilop
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #9 on: January 04, 2009, 02:12:43 PM » |
|
Man, you pimp IndieLib everywhere. What a pity it is free and I'm not earning anything... wait! It is worse this way, if it is free and nobody uses it the it would be a total disaster. I think I pimp it everywhere because that ![Durr...?](https://forums.tigsource.com/Smileys/derek/derr.gif)
|
|
|
Logged
|
|
|
|
J.G. Martins
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #10 on: January 04, 2009, 02:21:24 PM » |
|
Just for the record, I'm OK with Loover ![Hand Money Left](https://forums.tigsource.com/Smileys/derek/hand-money-l.gif) pimpin' ![Hand Money Right](https://forums.tigsource.com/Smileys/derek/hand-money-r.gif) his engine everywhere. Sure, I've seen him do it several times (been a lurker), and so have plenty of regulars around here, but hey, until it takes on a following and essentially "promotes itself", there's nothing wrong with trying to get people to use your hard work for free.
|
|
|
Logged
|
Gold is for the mistress -- silver for the maid -- Copper for the craftsman cunning at his trade. "Good!" cried the Baron, sitting in his hall, "But iron, cold iron, is the master of them all." --- Rudyard Kipling
|
|
|
mirosurabu
Guest
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #11 on: January 04, 2009, 02:37:35 PM » |
|
I tend to use two classes. One called Animation and one called AnimPlayer. The first one provides interface for loading and locating frame bitmaps. The name is kinda misnomer and names such as "AnimatedBitmap" or "BitmapSequence" are perhaps more appropriate. class Animation { private: std::vector <ANIMFRAME> aframes; // Animation frame public: // Used for adding new animation frames to class instance void Add ( BITMAP *bmp ); void Add ( BITMAP *bmp, int d ); // Returns bitmap of animation frame specified by f BITMAP *GetFrameBitmap ( int f ); int GetFrameDuration( int f ) { return aframes[f].duration; } void SetIntervalToAll( int d ); int FrameCount() { return aframes.size(); } }; In order to play animation you will have to keep information on what's current frame, the rate at which animation is played, is it paused or not and such. AnimPlayer class provides this functionality. This is what you use for actual animation. class AnimPlayer { private: Animation *animation; bool paused; // If set to true, calls to FrameTick() will have no effect int rate, // Frame-count rate (4-bytes precision) frame_counter, // Keeps the number of logical frames passed since last animation frame current_aframe; // Keeps the information about current animation frame std::string anim_name; public: AnimPlayer(); AnimPlayer(Animation *a, char *name); // Sets animation void SetAnimation( Animation *a ) { animation = a; } // Frame bitmaps BITMAP *FrameBitmap( int f ) { return animation->GetFrameBitmap(f); } BITMAP *CurrentFrameBitmap() { return animation->GetFrameBitmap(current_aframe); } // Skips to specific animation frame void GoToFrame( int f ) { current_aframe = f; } // Updates animation for one logical frame void FrameTick ( void ); void Pause() { paused = true; } void Unpause() { paused = false; } void SetRate(int r) { rate = r; } const char *GetAnimName() { return anim_name.c_str(); } }; To animate you just make call to FrameTick method each frame/tick. To draw, just simply get the current frame bitmap by making call to CurrentFrameBitmap and draw that bitmap onto the screen. That's how I do it. Maybe not the best solution, but it's fine for my needs.
|
|
|
Logged
|
|
|
|
handCraftedRadio
The Ultimate Samurai
Level 10
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #12 on: January 04, 2009, 02:52:35 PM » |
|
If you are just looking for a simple way to do animations, that looks way too complicated to me. The way I do it is with one sprite class who has one image (a sprite sheet). The height and width of each frame are defined when created, and you can tell it which frame to start and stop before the animation is played in the code. The sprite class has an update method that cycles the frames after a certain delay and draws the part of the sprite sheet that is the correct frame.
This may be too simple of a solution than what you are looking for, but it's how I do it, I can provide code if you'd like.
|
|
|
Logged
|
|
|
|
Gravious
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #13 on: January 04, 2009, 02:53:16 PM » |
|
Man, you pimp IndieLib everywhere. Haha, i was going to say the same :D nothing wrong with that at all mind you...
|
|
|
Logged
|
One day I'll think about doing something to stop procrastinating.
|
|
|
Mr. Yes
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #14 on: January 04, 2009, 03:02:22 PM » |
|
I do it more or less exactly how HandCraftedRadio just explained it (except that mine asks for the width of one sprite and divides the image by that, which actually is pretty dumb since it limits you to one animation per image, SO DON'T LISTEN TO ME).
|
|
|
Logged
|
|
|
|
J.G. Martins
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #15 on: January 04, 2009, 03:21:53 PM » |
|
HandCraftedRadio, what you said fits perfectly within these ideas. Why can't you have a subclass SubImage of the Image class that does exactly what you say? All it does is keep a pointer to the real image, and the rectangle defining the sub-image. As far as I know, most gamedev/graphics API's already allow this, so all that changes is the draw() method, or its equivalent! ![Grin](https://forums.tigsource.com/Smileys/derek/grin.gif) It's not that much more work for a system that is so much more expressive and extensible. You can define all sorts of stuff based on this, like centers of mass/pivot points for each sprite, how many ticks each frame will get so you get variable-duration frames, etc etc!
|
|
|
Logged
|
Gold is for the mistress -- silver for the maid -- Copper for the craftsman cunning at his trade. "Good!" cried the Baron, sitting in his hall, "But iron, cold iron, is the master of them all." --- Rudyard Kipling
|
|
|
handCraftedRadio
The Ultimate Samurai
Level 10
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #16 on: January 04, 2009, 03:50:01 PM » |
|
That would work, but I tend to do that sort of thing outside of the sprite class. Within the game, if I have some class that has a method, Walk, I would set the walk animation whenever that method is called. void Walk() { if (!walking) { sprite->SetLayer(2); // the animation is on the 3rd layer down from the top sprite->SetAnimation(0,4); // animation ranges from frame 0 to 4 sprite->SetAnimationDelay(5); // slows down animation sprite->StartAnimation(); } walking = TRUE; }
Like I said before, this is just a very simple way to do this. I have never had the need for using anything more complicated than this (like pivot points and center of mass, but I would probably keep that away from the image data too). I just like to keep my stuff simple if I have no use for more complicated things. All this stuff could be done in the Sprite class or SubImage class as well, it's just a matter of preference I guess.
|
|
|
Logged
|
|
|
|
Reiss
Level 1
|
![](https://forums.tigsource.com/Themes/tigsource/images/post/xx.gif) |
« Reply #17 on: January 04, 2009, 07:17:52 PM » |
|
If you are just looking for a simple way to do animations, that looks way too complicated to me. The way I do it is with one sprite class who has one image (a sprite sheet). The height and width of each frame are defined when created, and you can tell it which frame to start and stop before the animation is played in the code. The sprite class has an update method that cycles the frames after a certain delay and draws the part of the sprite sheet that is the correct frame.
This may be too simple of a solution than what you are looking for, but it's how I do it, I can provide code if you'd like.
I generally do that too, except instead of an update() method an update_at(int x, int y) method (actually, more like update_at(unsigned int time_passed, int x, int y), but how you decide to pass around the updated time doesn't really matter). That way I can paint the sprite in a different location on the screen without changing it's coordinates, to allow for an imaginary "camera" in the scene, the advantage of which is performance: in games where the player's character stays centered at some location onscreen, and everything else scrolls, instead of iterating through a list of sprites and moving each one you just change the camera coordinates (and move the player's character back to wherever it's centered) and you're done. Although if you're doing a non-scrolling game, like the Knytt games, there's no real point using an imaginary camera, so you can disregard everything I said. HandCraftedRadio, what you said fits perfectly within these ideas. Why can't you have a subclass SubImage of the Image class that does exactly what you say? All it does is keep a pointer to the real image, and the rectangle defining the sub-image. As far as I know, most gamedev/graphics API's already allow this, so all that changes is the draw() method, or its equivalent! ![Grin](https://forums.tigsource.com/Smileys/derek/grin.gif) It's not that much more work for a system that is so much more expressive and extensible. You can define all sorts of stuff based on this, like centers of mass/pivot points for each sprite, how many ticks each frame will get so you get variable-duration frames, etc etc! Sounds cool - I've never done that before. Must be especially good for dealing with things like clothing in an RPG-type game, although it sounds like you also use it for physics? Nice idea. Although HandCraftedRadio's got a point, if you're just trying to get a simple animation up onscreen, that might be a little much at first.
|
|
|
Logged
|
|
|
|
|