Page 1 of 1
Handling non-uniform sprite animations
Posted: Sun Feb 05, 2012 9:46 pm
by jaybee
So up until this point I've mostly been using a box as a placeholder for the platformer I've been casually working on. I finally decided to add some animations just to keep my motivation up. I had no problem implementing some basic animations but another problem has popped up along the way. As I cycle through the frames of the animation, the bounding box for the character changes to fit the dimensions of the new animation frame. This isn't a huge deal when the dimensions are relatively similar but tends to pose problems with my collision detection and a few other things when bigger changes and/or visual effects are added into the player's sprite.
For example, one of the jumping animations I have used causes a collision on frame 2 because the Y coordinate of the character hasn't changed enough for the new dimensions to fit within the space between the top of the character and the top of the tile he was standing on. Sometimes this will cause the player to fall through the floor and gravity pulls him down into the abyss. What is the best way to go about handling animations. Am I going to have to create loads of meta data for each animation defining where the origin should be? Right now the character is aligned by the top left and not by the center; Is that how it is normally done or are characters generally aligned by their origin?
Any help on this would be much appreciated. I had hoped to stay away from parsing XML files and creating a bunch of meta data but if that's the only way then so be it.
Re: Handling non-uniform sprite animations
Posted: Tue Feb 07, 2012 8:22 am
by Van-B
It's a tricky one huh!
I've recently had to deal with irregular sprite sizes, but luckily it was quite easy to adapt to, as it was a whole band of sprites, so some simple logic solved the issue. If I had to have different bounding and pivot for each sprite, then I'd store it as a variable, maybe an animation struct with the collision and pivot data, plus animation speed, transition modes, and whatever else the engine demands.
It's never as easy as just storing or hacking the details though, because your collision box is probably needing some extra care. If you change a collision box size, then it will affect it's current collision state - if it's sitting on the floor, and you enlarge the collision box, then it's now sitting inside the floor, which as you know causes all sorts of problems.
It's like rotation - not sure if your using sprite rotation - I'm guessing not seeing as your sprites are offset to the top left. Usually, I'd offset the sprite onto their pivot point, typically the dead centre of the sprite, depending on how your engine handles them. But with rotation and scaling, you have to qualify your collision. So it might need a little rethink - like maybe your collision code can be really simple, waiting for a collision then adjusting to previous values per axis, quick and simple sliding collision. But with the added headache of scaling (or rotation), you have to really check the next state of your collision, and check that, so you can return to the current state if the collision registers. So, if you characters ducking sprite is shorter than the standing sprite, you have to check for head space when standing up, otherwise he'd get jammed. So instead, you walk up to a low ceiling and can only get under once the character is ducking, then once under the low ceiling, your character has to check to see if there's space to stand up - by checking the next sprite for collision and returning to the current one if the collision registers. Imagine the sprite ducking the whole time, dissalowing standing and jumping.
A lot of this has to be done on a game logic level - very difficult and time consuming to make a sprite class that can cope with all the specifics by itself for all cases. I think it's a logic problem, and you should spend time on a character animation system, linked animation actions, flags for standing, ducking, and jumping to keep a leash on animation transitions, offsets, and collision boxes.
Thing is though, it's a great place to expand on game polish - smooth and reliable character animation can make a big difference - look at what it did for the original Prince of Persia - that's a franchise because it had such cool animation. I think it's always worth going to these lengths... Hell, I'd even consider having a 'stood up and banged head' animation, just in case the character does manage to stand up in a low ceiling area - at least it can be overridden and the character forced into a ducking action.
Re: Handling non-uniform sprite animations
Posted: Tue Feb 07, 2012 12:46 pm
by jaybee
Van-B wrote:It's a tricky one huh!
If I had to have different bounding and pivot for each sprite, then I'd store it as a variable, maybe an animation struct with the collision and pivot data, plus animation speed, transition modes, and whatever else the engine demands.
This makes sense. As it stands my animation class is parsing an xml file for the basic data for each animation. What exactly do you mean by "pivot data"? Excuse my ignorance, I'm just picking this stuff up on my own in my spare time. I hadn't really considered making any kind of transition modes, but that sounds like a good idea.
Van-B wrote:
It's like rotation - not sure if your using sprite rotation - I'm guessing not seeing as your sprites are offset to the top left. Usually, I'd offset the sprite onto their pivot point, typically the dead centre of the sprite, depending on how your engine handles them. But with rotation and scaling, you have to qualify your collision. So it might need a little rethink - like maybe your collision code can be really simple, waiting for a collision then adjusting to previous values per axis, quick and simple sliding collision.
Yeah, I'm really not doing any type of rotation or scaling. I'm using SDL's rendering so I can't afford the speed. What I'm wondering is what exactly is the benefit of offsetting the sprite from the center? I've seen a lot of code that does it this way but I can't find a sufficient explanation of why this is done. I'm orienting my sprites at the center to detect and resolve collisions but in terms of movement and animation they are offset by the top left.
Van-B wrote:
But with the added headache of scaling (or rotation), you have to really check the next state of your collision, and check that, so you can return to the current state if the collision registers. So, if you characters ducking sprite is shorter than the standing sprite, you have to check for head space when standing up, otherwise he'd get jammed. So instead, you walk up to a low ceiling and can only get under once the character is ducking, then once under the low ceiling, your character has to check to see if there's space to stand up - by checking the next sprite for collision and returning to the current one if the collision registers. Imagine the sprite ducking the whole time, dissalowing standing and jumping.
Right now my collision is resolving after detection. Would it be better if I checked collision before the sprite is moved?
Re: Handling non-uniform sprite animations
Posted: Tue Feb 07, 2012 2:13 pm
by Van-B
The pivot is the point on the sprite that it rotates around, but besides rotation, it means that the sprite is centered on the position you specify. Also means that scaling is from the center as well, you wouldn't want to scale from the top left usually.
I think that detecting collision before moving makes sense, for one thing it's far less likely to bug out - jumping collision can be especially tricky without collision response. For instance, what would happen if there was a collision in the corner, like on both axis at the same time. It can be tricky to resolve collision like that without pre-movement checks. You could store whether or not the sprite is touching the ground, then adjust the Y position to suit that before checking X axis collision.
Re: Handling non-uniform sprite animations
Posted: Tue Feb 07, 2012 7:18 pm
by THe Floating Brain
Just throwing it out there, you could use a "mask":
You could have a sprite you do not render follow the player and make a bounding box around it,
then when the player changes to a different basic position change the box. If needed you could check if the
player's box is inside the ground then adjust the "mask"(the invisible sprite with box) accordingly
Code: Select all
//Adjustment pseudo code.//
maskY += groundTopY - playerBottomY;