Dynamic Sprites and You!
Hey there everyone! This is a dynamic sprite tutorial, which I’m sure you know since you clicked on the link to get in here. So yeah, here we go into the exciting world of Dynamic Sprites!
What you need:
ASM experience
Spriting experience
Patience (found at your nearest virtue retailer)
What is a Dynamic Sprite?
There seems to be quite a stigma surrounding dynamic sprites, and most of that seems to stem from people having no idea what I dynamic sprite really is. So what is it? It’s just a sprite with an over glorified graphics routine. More specifically, it allows dynamic uploads to VRAM, allowing you basically as many frames in a sprite as you like.
What does this tutorial cover?
As the only difference between a dynamic sprite and a regular sprite is the graphics routine, I will only be covering the graphics routine. And, beyond that, I will only be covering the differences between a regular one and a dynamic one. This is why you need some spriting experience, or at least have a basic idea of how to sprite, because I won’t be explaining anything that is done in a normal sprite because that would get repetitive.
SO HOW DO I FREAKING MAKE ONE ALREADY!?
Well fine, settle down, just needed to get the semantics and warnings out of the way. Here’s the real tutorial:
DSX.asm:
The first thing you want to do is apply DSX.asm, available in the patches section. If you don’t, you are going to ask someone for help, they are going to get confused for about 20 minutes trying to figure out what is wrong with the code, and then you will finally remember that you hadn’t applied it yet, then you’ll feel real embarrassed. Yep.
GFX:
The most important part of dynamic sprites. Basically you want it laid out so that each frame takes up 1 32x32 square. You can also do less, but I’m sure you can figure that out for your self. In case you are too lazy to make your own GFX, here is a gfx file that works, and it is the one I will be using in my demonstration.
New library routines:
This is the hard part of dynamic spriting, but, luckily, it’s already been done for us. Thank smkdan and edit1754 for getting this out of the way for us, now all we need to do is copy and paste them. The new routines can be found here if you are assembling with xkas, or here if you are assembling with TRASM. (You are still going to want all the same library routines as you would have in a normal sprite). What you want to do is copy all of that code into your sprite and NEVER TOUCH IT AGAIN!
TO THE FREAKING CODE ALREADY!
Alright, here goes. A dynamic GFX routine starts out just like a regular one. You need tilemaps, offsets, etc. The difference mainly comes in the fact that you tile numbers will ALWAYS be the same, no matter what frame you are on or where you get your GFX from in the original file, they will always look like this:
(Obviously replace db with dcb if you are using TRASM)
00 is the top left of the dynamic sprite upload, 02 the top right, etc. If you want to grab less tiles just change this accordingly.
Offset tables are essentially the same as in a normal sprite, just set those up however you like. Telling it where to grab from is where it gets a bit weird. Instead of everything being 2 apart, it’s only 1 apart, since everything is apparently set up in 32x32 tiles. So the top left of the file is $00, 32 pixels to the right is $01, down 32 pixels is $11, etc., so a 16 frame sprite (like the one in the file I linked) would have a table like so:
(Once again, that’s Xkas, adjust accordingly for TRASM)
So, now that we’ve got the pesky tables out of the way, time to start writing the routine. It starts just like any other routine, as I’ve said before.
So that’s all pretty simple I would suppose, this is where it really starts being different:
And then we get into a normal sprite writing loop, just like in any other sprite, I’ll comment on what’s important:
Notice how the only difference really (Besides my few quirks I have going on), is that you load the tile that it finds for you? Yeah, that’s really it, it is that simple. Everything hard has been done for us. The only thing left for you to do is feed a value into !FrameNum and jump to the routine like normal. You can change it however you like it to be once you understand it.
To use this graphics routine:
The easiest thing to do is to make the sucker spin. To do that it’s just some simple code:
Oh and one more important thing, at the very bottom of the file you need:
The first two lines are unnecessary if you are using TRASM, and replace barrel.bin with the name of the gfx file you are using.
And the final product would be a little something like this (once again, it uses xkas, should be quite similar with TRASM though).
Oh, and all dynamic sprites need to use sp4, so set that up in the cgf.
And one more thing: Sprite graphics that take up more than 1 bank in ROM (over 64000 bytes), it takes a different dynamic sprite routine which you can get here, then follow these instructions for manual GFX insertion:
(Obviously create your own GFXADDR at the beginning of your sprite if you don't have one)
And that should basically be your first dynamic sprite right there. You have fun now.
Hey there everyone! This is a dynamic sprite tutorial, which I’m sure you know since you clicked on the link to get in here. So yeah, here we go into the exciting world of Dynamic Sprites!
What you need:
ASM experience
Spriting experience
Patience (found at your nearest virtue retailer)
What is a Dynamic Sprite?
There seems to be quite a stigma surrounding dynamic sprites, and most of that seems to stem from people having no idea what I dynamic sprite really is. So what is it? It’s just a sprite with an over glorified graphics routine. More specifically, it allows dynamic uploads to VRAM, allowing you basically as many frames in a sprite as you like.
What does this tutorial cover?
As the only difference between a dynamic sprite and a regular sprite is the graphics routine, I will only be covering the graphics routine. And, beyond that, I will only be covering the differences between a regular one and a dynamic one. This is why you need some spriting experience, or at least have a basic idea of how to sprite, because I won’t be explaining anything that is done in a normal sprite because that would get repetitive.
SO HOW DO I FREAKING MAKE ONE ALREADY!?
Well fine, settle down, just needed to get the semantics and warnings out of the way. Here’s the real tutorial:
DSX.asm:
The first thing you want to do is apply DSX.asm, available in the patches section. If you don’t, you are going to ask someone for help, they are going to get confused for about 20 minutes trying to figure out what is wrong with the code, and then you will finally remember that you hadn’t applied it yet, then you’ll feel real embarrassed. Yep.
GFX:
The most important part of dynamic sprites. Basically you want it laid out so that each frame takes up 1 32x32 square. You can also do less, but I’m sure you can figure that out for your self. In case you are too lazy to make your own GFX, here is a gfx file that works, and it is the one I will be using in my demonstration.
New library routines:
This is the hard part of dynamic spriting, but, luckily, it’s already been done for us. Thank smkdan and edit1754 for getting this out of the way for us, now all we need to do is copy and paste them. The new routines can be found here if you are assembling with xkas, or here if you are assembling with TRASM. (You are still going to want all the same library routines as you would have in a normal sprite). What you want to do is copy all of that code into your sprite and NEVER TOUCH IT AGAIN!
TO THE FREAKING CODE ALREADY!
Alright, here goes. A dynamic GFX routine starts out just like a regular one. You need tilemaps, offsets, etc. The difference mainly comes in the fact that you tile numbers will ALWAYS be the same, no matter what frame you are on or where you get your GFX from in the original file, they will always look like this:
Code
Tiles: db $00,$02,$20,$22
(Obviously replace db with dcb if you are using TRASM)
00 is the top left of the dynamic sprite upload, 02 the top right, etc. If you want to grab less tiles just change this accordingly.
Offset tables are essentially the same as in a normal sprite, just set those up however you like. Telling it where to grab from is where it gets a bit weird. Instead of everything being 2 apart, it’s only 1 apart, since everything is apparently set up in 32x32 tiles. So the top left of the file is $00, 32 pixels to the right is $01, down 32 pixels is $11, etc., so a 16 frame sprite (like the one in the file I linked) would have a table like so:
Code
Frames: db $00,$01,$02,$03 db $10,$11,$12,$13 db $20,$21,$22,$23 db $30,$31,$32,$33
(Once again, that’s Xkas, adjust accordingly for TRASM)
So, now that we’ve got the pesky tables out of the way, time to start writing the routine. It starts just like any other routine, as I’ve said before.
Code
SUB_GFX: JSR GET_DRAW_INFO LDA $157C,x ; $02 = sprite direction STA !TempDir ;Pretty simple, just like you would normally set a sprites direction. STZ !TilesTemp ;Used to keep track of the number of tiles drawn LDA !FrameNum,x ;You can also load a static value to here, ;this is used as an index for the frames ;table. This is freeRAM AND #$0F PHX ;\Get the place to grab from into the accumulator TAX ;| LDA Frames,x ;| PLX ;/
So that’s all pretty simple I would suppose, this is where it really starts being different:
Code
JSR GETSLOT ;This is that part we should thank smkdan for BEQ EndIt ;Don’t draw if there is no empty dynamic sprite slot STA !OneTileTemp ;Store the tile into scratch RAM, I use $07
And then we get into a normal sprite writing loop, just like in any other sprite, I’ll comment on what’s important:
Code
PHX LDX #$00 TileLoop: LDA $00 PHY LDY !TempDir BEQ right CLC ADC XOff,x BRA Flipped right: SEC SBC XOff,x Flipped: PLY STA $0300,y LDA $01 PHY LDY !TempDir BEQ down CLC ADC YOff,x BRA FlippedY down: SEC SBC Yoff,x FlippedY: STA $0301,y LDA !OneTileTemp ;remember the tile we stored earlier? ;Now we get it back and store it ;like we would a normal tile, except ;we add the value from the Tiles table to it. CLC ADC Tiles,x STA $0302,y PHX LDX $15E9 ;Get sprite index back LDA $15F6,x ;You know the drill here ORA $64 LDX !TempDir BNE left ORA #$C0 left: PLX STA $0303,y INC !TilesTemp INY INY INY INY INX CPX #$04 ;Tells it to draw 4 tiles, which is the max ;allowed. Less is fine though, ;just set up your tables accordingly. BCC TileLoop PLX LDA !TilesTemp ;The number of tiles drawn BEQ EndIt ;Don’t draw if we didn’t get any DEC ;\Yada, yada, normal drawing routine LDY #$02 ;|16x16 tiles JSL $01B7B3 ;/ EndIt: RTS
Notice how the only difference really (Besides my few quirks I have going on), is that you load the tile that it finds for you? Yeah, that’s really it, it is that simple. Everything hard has been done for us. The only thing left for you to do is feed a value into !FrameNum and jump to the routine like normal. You can change it however you like it to be once you understand it.
To use this graphics routine:
The easiest thing to do is to make the sucker spin. To do that it’s just some simple code:
Code
INC !FrameNum,x LDA !FrameNum,x AND #$10 ;Check if the 4th (from right, 0 indexed) is set LSR ;If it is, flip it, if not, don’t flip it, simple as that LSR ; LSR ; LSR ; STA $157C,x ;Store to the direction RAM LDA !FrameNum,x ;\Only allow 16 frames AND #$1F ;| STA !FrameNum,x ;/
Oh and one more important thing, at the very bottom of the file you need:
Code
GFXPointer: dw SPRITEGFX SPRITEGFX: INCBIN sprites\barrel.bin ;included graphics file
The first two lines are unnecessary if you are using TRASM, and replace barrel.bin with the name of the gfx file you are using.
And the final product would be a little something like this (once again, it uses xkas, should be quite similar with TRASM though).
Oh, and all dynamic sprites need to use sp4, so set that up in the cgf.
And one more thing: Sprite graphics that take up more than 1 bank in ROM (over 64000 bytes), it takes a different dynamic sprite routine which you can get here, then follow these instructions for manual GFX insertion:
Originally posted by edit1754
Steps to inserting GFX:
1. BACK UP YOUR ROM!!! You will always want an up-to-date copy if you corrupt it accidentally
2. Open your SMW ROM in translhextion
3. Keep scrolling down until you find a large blank area full of zeros.
4. Look for an address that ends in "0200" or "8200" (these are beginnings of ROM banks) ...or you can overwrite the old blowhard GFX. Also, make sure there are at least 8 zeros before that, for the RATS tag. (unless the space is used by the old RATS tag)
5. To make sure there is enough space, use the select block feature to select an area that is 0x7F80 (32640) bytes long. To do this, go to Selection > Select Block, click "number of bytes to select", and type the decimal value of the space required. (in this case, it's 40960, which is 1 and 1/4 ROM banks)
6. If there are only zeros in the space, go to the next step, otherwise repeat from step 3 to find another space.
7. Go back to the address at the start and write it down (the PC offset)
8. Open "blowhardgfx.bin" in another translhextion window and copy/paste the data into the starting address in the SMW ROM's blank space you found. When the paste dialog box comes up, make sure you select "overwrite" and NOT "insert".
9. go back 8 bytes before your starting address and type 53 54 41 52 00 A0 FF 5F for your RATS tag
10. Open Lunar Address and select "LoRom - PC". If it doesn't automatically say PC and SNES under the text boxes at the bottom of the window, clear out one or both until it shows the labels so you know which is which.
11. Type the first address you wrote down into Lunar Address where it says PC and write down the address it says in "SNES".
12. Open blowhard.asm in notepad and search for "GFXADDR", it should be near the top.
When you find it, you will see something like this:
GFXADDR = $XXXXXX
13. Go back to the last address you wrote down (the converted address), it should look something like this: $12:3456.
14. For the converted address, enter it in like this:
GFXADDR = $123456
15. save the ASM file and insert the sprite (yiblowhardv2.asm, yiblowhardv2.cfg) like you would any sprite.
1. BACK UP YOUR ROM!!! You will always want an up-to-date copy if you corrupt it accidentally
2. Open your SMW ROM in translhextion
3. Keep scrolling down until you find a large blank area full of zeros.
4. Look for an address that ends in "0200" or "8200" (these are beginnings of ROM banks) ...or you can overwrite the old blowhard GFX. Also, make sure there are at least 8 zeros before that, for the RATS tag. (unless the space is used by the old RATS tag)
5. To make sure there is enough space, use the select block feature to select an area that is 0x7F80 (32640) bytes long. To do this, go to Selection > Select Block, click "number of bytes to select", and type the decimal value of the space required. (in this case, it's 40960, which is 1 and 1/4 ROM banks)
6. If there are only zeros in the space, go to the next step, otherwise repeat from step 3 to find another space.
7. Go back to the address at the start and write it down (the PC offset)
8. Open "blowhardgfx.bin" in another translhextion window and copy/paste the data into the starting address in the SMW ROM's blank space you found. When the paste dialog box comes up, make sure you select "overwrite" and NOT "insert".
9. go back 8 bytes before your starting address and type 53 54 41 52 00 A0 FF 5F for your RATS tag
10. Open Lunar Address and select "LoRom - PC". If it doesn't automatically say PC and SNES under the text boxes at the bottom of the window, clear out one or both until it shows the labels so you know which is which.
11. Type the first address you wrote down into Lunar Address where it says PC and write down the address it says in "SNES".
12. Open blowhard.asm in notepad and search for "GFXADDR", it should be near the top.
When you find it, you will see something like this:
GFXADDR = $XXXXXX
13. Go back to the last address you wrote down (the converted address), it should look something like this: $12:3456.
14. For the converted address, enter it in like this:
GFXADDR = $123456
15. save the ASM file and insert the sprite (yiblowhardv2.asm, yiblowhardv2.cfg) like you would any sprite.
(Obviously create your own GFXADDR at the beginning of your sprite if you don't have one)
And that should basically be your first dynamic sprite right there. You have fun now.