Hi, I noticed there wasn't a step-by-step on this anywhere, or even how to do it in a NES Maker-specific way, so I'll share how I did it. The problem is that it's very project specific, what you actually need it to do, but getting it going at all is the hardest part. If you can follow along with this guide you'll be able to do basically whatever you want with it. In the zip I've included my DoScreen16.asm, but it's better to follow along.
Aims:
- Load our own CHR graphics files rather than using up the pre-assigned tilesets NES Maker sets up
- Animate the top row of the main tileset on a screen with an additional two frames. We will set it up for the Main + Screen x 3 tileset loadout for my example.
Things you need to have done first:
- Follow my guide to move half of doLoadScreen to Bank 16 - most of this will take place in the new Bank 16 routine. Link
- Download the attached zip and put the SwitchCHRBank macro in your BASE_4_5\System\Macros folder.
- Setup user screenbytes. This method by chronicleoflegends is great.
- Add a new temp variable in NES Maker's user variables, I'm using tempj in this example. This is so I know there isn't a macro messing with my temp variable.
- Add variables animTimer and animFrame. Set animTimer to a default value of 16.
- Set up the Handle Game Timer script. Basically just make a blank asm file and assign it to Handle Game Timer in script settings. It's included by default in NES Maker.
- Make sure the tile layout for the screen you're trying it on is set to No Path (Main + Screen x 3)
Part 1 - Sideloading more graphics
This part isn't entirely necessary, you can use graphics NES Maker allows you to by default, but you'll quickly run out of room and it's kind of awkward to reference them.
Bank 17 is pretty much empty, so I've been including extra CHR files there. CHR files are the color indexed BMP files that can actually be used by the system.
I've included some graphics as an example in the attached zip, so I'll refer to those specifically. Move BckCHR_17.bmp to your project's graphics assets folder. This will be the base graphics set that we'll animate the top row of. Create a subfolder in your graphics folder called Animated Tiles. Here you can put the animated tile .bmps that are in the zip.
Now we convert them to .chr so that the NES can actually use them. This is easy:
Load each of the AnimTiles bmps up in the pixel editor. At the top of the window, click the Pixel Editor menu and hit Export CHR.
View attachment 4841
Save this in GameEngineData\Routines\BASE_4_5\Graphics as AnimTiles01.chr. You'll need to create the graphics folder, it's not there by default. Do the same with AnimTiles02.bmp.
Now that the graphics are in the right format, we can include them in our code. Open Bank 17 (easy to find from Script Settings) and at the top, add:
Code:
AnimTiles01:
.incbin ROOT\Graphics\AnimTiles01.chr
AnimTiles02:
.incbin ROOT\Graphics\AnimTiles02.chr
So now we have the two new graphics files included with our game, and two labels set up so we can reference them. Next is to make a reference table for them in Bank 16 where the CHR loading actually takes place.
Open up Bank 16 and find a spot near the top. We're going to add two tables for the addresses of the new tilesets:
Code:
AnimTiles_Lo:
.db #$00, #<AnimTiles01, #<AnimTiles02
AnimTiles_Hi:
.db #$00, #>AnimTiles01, #>AnimTiles02
This stores the addresses of the high and low bytes of the new tilesets, references that will be needed when loading them into RAM.
And that's it for part one. Extra graphics are loaded, and references are set up. Now the fun part, actually loading them into CHR-RAM during doLoadScreen.
Part 2 - Loading the graphics into CHR-RAM
Mapper30 has 4 CHR-RAM banks, by default NES Maker only loads the first one. Since we have two additional frames of animation, we're going to load up two more banks, and then do a timed switch between them to make the tiles animate.
This will all take place in DoLoadScreen16.asm.
First, at the top of the script under DoLoadScreen16:, add:
To make sure we always start in CHR bank 0. Weird things will happen if your animation timer causes screenload to start in a different bank.
Scroll down to LOAD_MSSS:, which is around line 118. We're going to loop through this three times to fill three banks.
Set your temp variable to #$00, and add a label for the loop:
Code:
LOAD_MSSS:
----
LDA #$00
STA tempj ;;added code
MSSS_CHR_LOAD_LOOP:
-----
LDA backgroundTilesToLoad
LSR
LSR
LSR
LSR
We're going to use userScreenByte7 to tell each screen which animated tiles it should load. If you leave it at zero, it won't load anything. Since we're using AnimTiles01, we set userScreenByte7 to 1, on the screen info settings in NES Maker.
At the end of the LOAD_MSSS section, we're going to check for two things. First, is userScreenByte7 equal to zero? If it is, we won't bother looping and load more CHR. If it's not, we switch to the next CHR bank, loop back through the CHR loading routine, then do it again until we have banks 0, 1 and 2 loaded up. What bank we're in is tracked by tempj. This is what that looks like (around line 181):
Code:
LDA userScreenByte7
BEQ +noAnimatedTiles
INC tempj
LDA tempj
CMP #$03
BEQ +noAnimatedTiles
SwitchCHRBank tempj
JMP MSSS_CHR_LOAD_LOOP
+noAnimatedTiles
JMP doneLoadingChrs
As a progress check, you can compile it and check the PPU viewer in Mesen. On the second tab you can switch between CHR-RAM banks and make sure that they're loading (the fourth one should still be black).
Now we have three sets of identical background tiles loaded, we have to load the sprite graphics as well. These are loaded separately further down the script, so we'll do basically the same thing for them.
Find doneLoadingChrs: at the bottom of the script, and add these four lines under it:
Code:
doneLoadingChrs:
SwitchCHRBank #$00
LDA #$00
STA tempj
Load_Sprite_CHR_Loop:
and at the end of the script, right before the RTS, add (almost) the same check as the last one:
Code:
LDA userScreenByte7
BNE +hasAnimatedTiles
JMP +noAnimatedTiles
+hasAnimatedTiles
INC tempj
LDA tempj
CMP #$03
BEQ +loadAnimatedTiles
SwitchCHRBank tempj
JMP Load_Sprite_CHR_Loop
+loadAnimatedTiles
;;animated tile loading code will go here
+noAnimatedTiles
SwitchCHRBank #$00
Now the last part in this script, actually loading in the extra frames of animation to banks 1 and 2. Replace the comment in the last code with this:
Code:
SwitchCHRBank #$01
LoadChrData #$17, #$10, #$00, #$20, AnimTiles_Lo, AnimTiles_Hi, userScreenByte7
jsr doWaitFrame
INC userScreenByte7
SwitchCHRBank #$02
LoadChrData #$17, #$10, #$00, #$20, AnimTiles_Lo, AnimTiles_Hi, userScreenByte7
jsr doWaitFrame
SwitchCHRBank #$00 ;;switch back to the first bank
For reference, the first argument for LoadChrData is the bank where the graphics are stored (we included them in Bank 17 at the start of this), the second argument is what row to replace (#$10 is the first row), #$00 is what column to start the replacement at, and the last one to worry about is where we have userScreenByte7 - this is the position of the tileset we want to load in, relative to the start of our AnimTiles_Lo/Hi list in bank 16. That's why we set screenbyte7 to 1. The script then increases it to 2 so we load in AnimTiles02.
Set up the timer
In your handle game timer script, we want to decrement animTimer each frame, then when it hits zero, set it back to the starting interval, increase our animFrame variable, and switch CHR banks to the next frame. It's pretty simple and looks like this:
Code:
LDA userScreenByte7
BEQ +dontUpdateAnimatedTiles ;;making sure that this screen actually has animated tiles set up - thanks CGT
DEC animTimer
LDA animTimer
BNE +dontUpdateAnimatedTiles
LDA #$10 ;;i'm using 10 as a starting point for animTimer
STA animTimer
INC animFrame
LDA animFrame
CMP #$03 ;;has it gone over the number of banks we filled?
BEQ +resetAnimation
SwitchCHRBank animFrame
JMP +dontUpdateAnimatedTiles
+resetAnimation
LDA #$00
STA animFrame
SwitchCHRBank #$00
+dontUpdateAnimatedTiles
And done! The tiles should be animating now.
I wrote this as I went through on a fresh install of NES Maker so hopefully I haven't missed anything.
Extra stuff
Now that you know how to fundamentally do this, you should try customising it so that it fits your project better. Here are a couple of things I did:
- Make a four frame animation.
- Use a screenflag to make the loading routine load the animated tiles into one of the screen specific rows, rather than always the top row
- Make a table in bank 16 that tells the game how many frames individual animations have, so they don't need to be the same number of frames on every screen. You'll need to change the last part of the CHR loading script to be an arbitrary loop for that.