Sprite Animation Example

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
samwise970
Posts: 24
Joined: Tue Oct 17, 2017 12:13 am

Sprite Animation Example

Post by samwise970 »

Hey All,

I apologize for a newbie question. I'm working through the Nerdy Nights tutorials, using NESASM (I know people like ca65 or whatever but for now using NESASM). I can understand how to build meta-sprites, move them around, all of that.

I'm having a bit of trouble understanding how to animate sprites.

I've gone through the forums, I've found topics here (viewtopic.php?f=2&t=14852) and elsewhere, like here (http://nintendoage.com/forum/messagevie ... adid=33378)

It's just a bit hard going through posts or pastebin files without an example to also work through. I enjoy the Nerdy Nights tutorial because I can take the example ASM files and fiddle around with them until I completely understand them. It's more difficult to create new ones from scratch.

Does anyone have an example file that I could use to take a look at a simple animation in action? I'm sure that'd be a huge help.

Thanks for any help, this seems like an awesome community.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Sprite Animation Example

Post by pubby »

I'm pretty sure tepples's nrom example contains animation code: https://pineight.com/nes/nrom-template-0.05.zip
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Sprite Animation Example

Post by dougeff »

Each animation frame should be an array of tile numbers and relative position of each tile.

Then you have an array of pointers to each frame.

Then, use a bunch of define statements, to enumerate the array. Like

HeroWalk1= 0
HeroWalk2= 1
HeroWalk3= 2

Etc, through every animation. (You could use null = 0, if you want that to = no animation)

Then you can reference HeroWalk1 in your code. Ie. HeroAnimation = HeroWalk1.
LDA #HeroWalk1
STA HeroAnimation


Your code (at the end of each frame's code) should build the OAM buffer, based on the current animation definitions of each object.

Try using NES Screen Tool's metasprite tool. And find the bits in Shiru's neslib for drawing a metasprite to the OAM buffer.


Edit, sorry for the 'should' statements. You are free to plan your own game your own way.
Last edited by dougeff on Mon Oct 23, 2017 7:21 am, edited 1 time in total.
nesdoug.com -- blog/tutorial on programming for the NES
samwise970
Posts: 24
Joined: Tue Oct 17, 2017 12:13 am

Re: Sprite Animation Example

Post by samwise970 »

dougeff wrote:Edit, sorry for the 'should' statements. You are free to plan your own game your own way.
Don't apologize! I'm an assembly n00b and I'm posting a basic question. I really appreciate the advice on the best way to structure my programs.

Also, pubby, thank you so much for that link! That's basically what I'm looking for. I should probably learn ca65 anyways, seems that's the most popular assembler.

This will still take some work, but I'm going to crank on it tonight, will post when I run into trouble. Thank you guys so much.

EDIT: After a few hours of tinkering, I think I'm finally starting to get it! I'm not there yet but I understand what needs to be done.
User avatar
Sumez
Posts: 919
Joined: Thu Sep 15, 2016 6:29 am
Location: Denmark (PAL)

Re: Sprite Animation Example

Post by Sumez »

It's very difficult to tell you "how to animate", as there is no end to the different ways you can do it. Your imagination is really the limit.

dougeff's example is a traditional way to do it, and a good way to start. But other approaches could be simply using algorithms to change out sprite references, etc.

When you make your first animation, I would suggest you just hard code the data you'll be changing.

Here's a very simple example - let's say you have your player character which has an X position and an Y position somewhere in RAM. You'll want to add a timer that counts down every frame so you can time your animation (eg. dec AnimationTimer), and then every frame you'll write your character's sprite to your frame buffer, simply write it the way you'd normally add a sprite (ie. first byte is the Y position, second is the sprite index, third is the attributes, and fourth is the X position), but when you're writing the sprite index, make a branch based on the value of the animation timer (eg. and #$4 and then bne/beq) - on one condition you write one frame of animation, on the other condition you write the other frame.

Once you have that working, you can expand your code to read which sprites to write from a data array similar to the ones dougeff mentioned, and you'll probably want to have multiple animations, with multiple frames of animations in each. On top of that, each frame of animation will probably have to include multiple sprites, too, unless none of your objects are bigger than 8x16 pixels. :P With stuff like this, I'd think you just need to add these features one at a time, to make sure everything works as it should. If you just start out making a complete animation framework for your game, it'll be much harder figuring out where things break (because they definitely will)
samwise970
Posts: 24
Joined: Tue Oct 17, 2017 12:13 am

Re: Sprite Animation Example

Post by samwise970 »

Sumez wrote:When you make your first animation, I would suggest you just hard code the data you'll be changing.

Here's a very simple example - let's say you have your player character which has an X position and an Y position somewhere in RAM. You'll want to add a timer that counts down every frame so you can time your animation (eg. dec AnimationTimer), and then every frame you'll write your character's sprite to your frame buffer, simply write it the way you'd normally add a sprite (ie. first byte is the Y position, second is the sprite index, third is the attributes, and fourth is the X position), but when you're writing the sprite index, make a branch based on the value of the animation timer (eg. and #$4 and then bne/beq) - on one condition you write one frame of animation, on the other condition you write the other frame.

Once you have that working, you can expand your code to read which sprites to write from a data array similar to the ones dougeff mentioned, and you'll probably want to have multiple animations, with multiple frames of animations in each. On top of that, each frame of animation will probably have to include multiple sprites, too, unless none of your objects are bigger than 8x16 pixels. :P With stuff like this, I'd think you just need to add these features one at a time, to make sure everything works as it should. If you just start out making a complete animation framework for your game, it'll be much harder figuring out where things break (because they definitely will)
Thank you for your response!

You're right, I wasn't making it easy on people with such a general question.

And I think your explanation is one of the best ones I've actually seen, thanks for using less technical language.

You say to hardcode the data I'll be changing.. that's exactly what I did last night (stayed up all night hah)! I feel like I've got a really good handle on what I need to be changing, how to index metasprite arrays properly, what variables I need to implement. I'm currently using 8x8 sprites, but am starting to realize 8x16 may have been a better idea. No matter!

I think I've got it from here, hopefully. At least for this subject.

Really appreciate everyone here. Crazy that I got three great responses in less than a day. Thanks guys.
User avatar
mikejmoffitt
Posts: 1353
Joined: Sun May 27, 2012 8:43 pm

Re: Sprite Animation Example

Post by mikejmoffitt »

If you can tolerate my shitty newbie code, here's the animation scheme I used for a project I got started on.

I drew a bunch of my animations separately, first being kind of greedy with space used up. Then I realized I can shift over some parts of animations to better pack into tiles. Finally, I made note of tile re-use, and removed even more tiles. I ended up with this CHR layout, which clearly isn't complete, but has a lot of the animation in almost half the space it originally had:

Image

For the animation system, this code snippet describes individual animation frame layouts, the "metasprites". Each line more or less maps to a single sprite's attributes, but the positions are relative to a position specified during drawing. This is for the player's first standing frame:

Code: Select all

pl_mapping_stand1:
	.byte   <-32, $00, %00000000, <-8
	.byte   <-32, $01, %00000000, 0
	.byte   <-24, $10, %00000000, <-8
	.byte   <-24, $11, %00000000, 0
	.byte   <-16, $20, %00000000, <-8
	.byte   <-16, $21, %00000000, 0
	.byte   <-8,  $30, %00000000, <-8
	.byte   <-8,  $31, %00000000, 0
	.byte   MAP_END
MAP_END is a "magic number" which I use to indicate the end of a mapping, as there is no predefined size for the mapping. I think I use $80 for it.

Following that, the different mappings are sequenced as animations:

Code: Select all

pl_anim_stand:
	; Animation total frame count
	.byte 	2
	; Animation repeat frame #
	.byte 	0
	; Pointer to first mapping
	.addr	pl_mapping_stand1
	; Number of frames to display this mapping, and pad byte
	.byte 	32, 0
	; Pointer to second mapping
	.addr	pl_mapping_stand2
	; Number of frames to display this mapping, and pad byte
	.byte	28, 0
And finally, a lookup table for animations, so I may refer to them by number:

Code: Select all

pl_anim_num_map:
	.addr	pl_anim_dummy
	.addr	pl_anim_stand
	.addr	pl_anim_run
	.addr	pl_anim_jump
	.addr	pl_anim_fall
metasprite.asm takes a pointer argument to a metasprite mapping (the first table I defined) and will draw it at the specified X and Y coordinates. I won't paste the whole thing here since that will make the post rather large.

If you follow player_render.asm you can see how animations are sequenced, and how calls to metasprite.asm are made based on it (several levels of indirection used for the animations).

I hope maybe this is a helpful reference, though there will certainly be room for improvement (as there always is).
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Sprite Animation Example

Post by Memblers »

I had shared my animation code, I just noticed the link was broken though so now it's an attachment. It's not a complete example that you can just build, though.
viewtopic.php?f=10&t=7331
samwise970
Posts: 24
Joined: Tue Oct 17, 2017 12:13 am

Re: Sprite Animation Example

Post by samwise970 »

Hey guys!!

I want to thank you all for your help again.

I've had this working for a little while, wanted to show what I've got so far. I loved seeing all of the examples you shared, but I ended developing my own, undoubtedly inferior method, because I'll learn more from my own code even if it's not as good.

Anyhoo, here's what I've got!

Image
The method I use animated both the player and an NPC (although theres an error and the NPC standing frame isn't correct), using the same code. It changes the sprite based on whether it is moving or not, and depending on the direction. It can also change the palette depending on the frame, but that isn't shown here. I'm fairly proud of this, had to put it into a jump table because my branch loop got too long.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Sprite Animation Example

Post by dougeff »

how did you get those variables to show up on the bottom right? is that a lua script?
nesdoug.com -- blog/tutorial on programming for the NES
samwise970
Posts: 24
Joined: Tue Oct 17, 2017 12:13 am

Re: Sprite Animation Example

Post by samwise970 »

dougeff wrote:how did you get those variables to show up on the bottom right? is that a lua script?
I'm ashamed to say I've never used lua before! The only languages I know are Basic derivatives (QBasic as a kid, VBA for work), GML (Game Maker Language), some Java, and R. I don't even know C! Once I finish an NROM game 6502 will be added to that list :)

To actually answer your question, it's just some hacky assembly right before my RTI. In the CHR file I put 0-F in the last row for sprites, put them in a db directive to look up from. That's why you actually see a character sprite appear for temp_z, cause it goes higher than 16.

Code: Select all

  LDA temp_x
  LDA sprNumbers, x
  STA $0281
  LDX temp_y
  LDA sprNumbers, x
  STA $0285
  LDX temp_z
  LDA sprNumbers, x
  STA $0289
  LDX player_moving
  LDA sprNumbers, x
  STA $028D

;PPU clean up code goes here

  RTI 

;;;;;;;;;;;;;;;;;;;;;;;;
sprNumbers:
  .db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF
Again, I'm a bad programmer, sure there's a way better way to do this. Just my simplest solution.
Post Reply