Object/sprite animation

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Object/sprite animation
by on (#72068)
Hi, I have a question about animation of objects. In my simple one screen game I have a main character that consist of 4 sprites. I want him to walk across the screen. I'm also going to have more objects with some animation. I was thinking to make an engine for general handling of all objects animation.

How are you guys doing this sort of thing? what data do you have in ROM/RAM? what is the structure of the data in ROM? how are you handling objects generally?

The following is what I have come up with so far.

In ROM the tiles that make up the object needs to be defined:
Code:
WalkLeft:
;frame1
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
;frame2
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
;frame3
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr
   .byte tile#, x-pos, y-pos, attr

WalkRight:
;frame1-3
   ... and so on


Somewhere in RAM each object need to have a place where the object is represented with an ID, adress to the frames in ROM and so on...

Is what I have described a smart or good approach. Do you have something better or smarter or easier way of doing animations, please share.

by on (#72076)
Super Mario Bros. just assumes that all enemy critters' cels will be 16x24 pixels (a 2x3 grid) and stores one attribute and six tile numbers. (One of the tile numbers means "no tile here".)

by on (#72080)
Tables like that are a decent way to do it, in fact I had released my code that does exactly that: http://www.parodius.com/~memblers/nes/animate.asm (edit: URL gone, attached below). The example has 2 different sized objects with their own animations.

The main addition to my tables is that I have it list the number of tiles used in each frame, and in the table of frame pointers I have a number between each pointer that is used a fixed-point delay value between each frame.

Also, since the tile placement is relative (from the first sprite), I also did some hackery that instead of using the usual offsets(0, 8, etc.), on some frames for the squid animation it adds 1 or 2, and that will make the animation itself propel the object forward by 1 or 2 pixels on those frames. That can be used to handle movement and animation at the same time, if it's appropriate. Otherwise, you just move the 'base' sprite with some code like normal before calling the animation.

by on (#72087)
Okay, I will look at that code and try to understand it. It always takes alot of time to understand someone else's code when it's not very well documented, especially when you are a beginner like me. :D so if you have some documentation it would be great, but I'm sure I will learn more if I have to figure it out myself.

by on (#72103)
Nope, not any extra documentation other than what is in that source. The labels weren't named very well either. And yeah it is kinda confusing to follow that code. If you look at run_anim: though, that is the example of how it's called. explosion_follow is supposed to point to the 'base sprite' for the others to be placed around.

by on (#72120)
I don't get it, I mean I know that run_anim label is called first, then within that subroutine you check whether to run animation or not but then variable names get me confused, could you explain what these are?

anim_offset
animspr_offset
squidtime
anim_delay
anim_timer
anim_number
anim_addr

Maybe the code is too advanced for me at this point. It's only my first game, I mean I could implement animations later. But if you could explain these variables I could take another look and then decide what to do.

by on (#72161)
anim_offset needs to be sized to one byte per (concurrent) animation. These bytes keep track of the current frame (to step through and index it in the table)

animspr_offset seems to be used like explosion_follow, it's the base sprite for the animation. Not sure why it's different from explosion_follow though.

squidtime appears to be a counter I used to retrigger the animation periodically. I could have used the loop function in the animation, but I probably did this to make it easier to tweak (since I did that weird thing of making the animation itself move the sprite). These 2 animations had one of them sorta chasing the other, but were moving in different ways, so some tweaking was needed.

anim_delay is the fixed-point counter that is used to make the delays between frames. The frame changes to the next when anim_delay rolls over (generates a carry, and partial value is kept). There is one of these per concurrent animation.

anim_timer is the value added to anim_delay every frame. This byte is in the data between the addresses that point to the frames. If you look at the squidmove table you can see it's used pretty stupidly - the value is 255 which will overflow the counter on almost every frame. As with the others, the size of this is 1 byte per animation.

anim_number is how you select which animation/object to process. This is used directly to index some of the previous bytes (that are arrays in RAM), so for concurrent 2 animations you'd set it to zero, call the animator, set it to one, call the animation, and so on.

anim_addr is what it uses to point to the actual frame data. Such as quid0: for example, where there is the size followed by the sprite data.

Hopefully that makes a little more sense, it did seem pretty complicated when I wrote it and I've managed to use it in a few projects since then. But if it's not directly usable hopefully some of the methods will help with whatever you do.

by on (#72186)
I have again tried to grasp the code with these variable explanations you gave me, and it makes a lot more sense now, thanks. I don't understand everything that is happening but it doesn't matter. Maybe I could get your code to play along, maybe not, but I have decided to write my own code instead of using code I don't fully understand. I will base it on your solution/idea though and the concept will be the same so let's see how it ends up... I thank you for your help.