I don't know if I'm doing this correctly, but I just added my sprites.chr file to my program, but when I run my code, it won't appear in the PPU viewer (I'm using FCEUX for testing). I added both font.chr (contains background tiles) and sprites.chr files with .incbin"<file-name-here>", but only the background tiles appear in the PPU viewer.
This is how it is in the code:
Code:
.bank 2
.org $0000
.incbin "Font.chr"
.incbin "Sprites.chr"
Here is full code if you need it:
http://pastebin.com/qkBqk2y9
Make sure your two .chr files don't add up to be over 8kb, because on the NES, the background uses 4kb, and the sprites use 4kb.
Drag wrote:
Make sure your two .chr files don't add up to be over 8kb, because on the NES, the background uses 4kb, and the sprites use 4kb.
The background has 31 tiles and sprites has 2 tiles. No way either of those would be more than 4kb.
Make sure your background .chr file is 4kb. If it is smaller, then sprites .chr file might be simply included right after background. See PPU viewer if you can find your sprite tiles on the background "side" of the viewer.
To avoid this you can either(in your case, since you are using NROM+CHR ROM):
-Make background file excatly 4kb. It have to have 256 tiles, even if latter are empty.
-Changing the end of the assembly file to:
Quote:
.bank 2
.org $0000
.incbin "Font.chr"
.org $1000
.incbin "Sprites.chr"
Did you set the palettes correctly at $3F00-$3F1F? FCEUX will not show anything if the palette isn't set (you can cycle through the palettes in the viewer IIRC).
Did you select the correct pattern tables for each side through bits 3 and 4 of register $2000 (PPUCTRL)? If both are pointing to the background pattern table that's all you'll see.
I think Denine's got it right. I downloaded the file from pastebin, changed nothing inside. I supplied two different 4 KB CHR files and it displayed both in FCEUX's PPU viewer just fine.
Alternatively Font.chr is actually 8 KB. The number of tiles used doesn't necessarily correspond to the size of the file. Which version of NESASM are you using?
I use NESASM 3. I'm also using YY-CHR for making the graphics if that matters.
You have to set the palette to see them in fceux's viewer.
I did set all 8 palettes. I'll have to see if I can limit the chr file sizes to see if that fixes this problem. Looking at the earlier messages, it's very well possible that my chr files are over 4kb
Should be 8KB exactly. YY-Chr should save that normally, using 2 pages. At least from what I remember.
I just checked my chr files, and it seems like they both are 16kb. Maybe it's best that I put all graphics to the same file, but just start sprites with 4kb offset to get them right after the first background table.
Save to the right file format, too. If your settings aren't right on the editor, then it won't output right file format/size for the file, no matter the extension.
What are the correct settings then? I attached image of the settings that appear on the main editor screen, but I don't know if that's what you meant. Anyway, I got the sprite to appear on the PPU viewer by adding it to the font.chr with a 4kb offset. Now I just need to make it appear on screen.
Attachment:
yychr.png [ 32.63 KiB | Viewed 2828 times ]
Here is a blank 4KB file. If your YY-CHR is like mine (yours is newer than mine), YY-CHR will save a file that is the exact same size as it was when it was opened. So open this and paste your background tiles in. Save it as font.chr. Open it again and put your sprite tiles in. Save it as sprites.chr.
I'd say your file is still too big, because YY-CHR shows 256 tiles in its left window. 256 tiles is 4 KB. You can scroll down which means your file is bigger than 4KB. And it looks like you can actually scroll quite a bit which means your file is probably still 16 KB and not even 8KB.
Edit: Actually I learned a new thing about YY-CHR today. The filesize is at the top in hex. 000000/004000. $4000 is how big your file is. $4000 is 16KB.
Edit2: I'll attach a blank 8KB file as well in case that's your preferred method.
I'll have to leave that for later. I got a new problem. I was trying to set up a proper code for updating either background and/or sprites if necessary and I messed something up. The screen is black now, but I can see stuff on the Nametable Viewer just fine.
Here is the code:
http://pastebin.com/sAee4cD3
Looks like it's because the code to reenable rendering (under FlagClear) is literally impossible to access. Directly above it is a jmp that skips ahead of that write to $2001, and nothing branches to FlagClear.
You don't have to guess how big your files might be. Right-click on the file and select Properties, and it will let you know.
Kasumi wrote:
Looks like it's because the code to reenable rendering (under FlagClear) is literally impossible to access. Directly above it is a jmp that skips ahead of that write to $2001, and nothing branches to FlagClear.
Got it working. I added a ORA between the two NMI flags, and if both are off, it will branch to FlagClear. Also, my sprite is shaking a little bit even though it's not moving. What's causing this? I did add some stuff to the code to fix some stuff. It removed most of the shaking, but the sprite still shakes a little bit occasionally. I also noticed that the program draws the left half of the sprite on the second background (during PAL emulation).
New code:
http://pastebin.com/mivk49CK
What's the deal with the TimeWaster routine? Did you put that in because the sprite was moving too fast? That's the wrong way to solve this problem (because it may completely throw off the alignment between game logic and VBlank handler, and your NMI doesn't look prepared to handle lag frames), and could very well be causing the stability issues you described.
The correct thing to do is only run your main loop once per frame. This is commonly achieved by polling a variable once the game logic is done, and only jumping back to repeat the main loop once that value changes, which only happens in the NMI handler, so you know that a new frame has started:
Code:
MainLoop:
JSR MoveSpr
LDA FrameCounter
WaitFrame:
CMP FrameCounter
BEQ WaitFrame
JMP MainLoop
Then, anywhere in your NMI (preferably at the end, so as to not steal any precious VBlank time), you increment that variable:
Code:
INC FrameCounter
tokumaru wrote:
What's the deal with the TimeWaster routine? Did you put that in because the sprite was moving too fast? That's the wrong way to solve this problem (because it may completely throw off the alignment between game logic and VBlank handler, and your NMI doesn't look prepared to handle lag frames), and could very well be causing the stability issues you described.
That was just temporary solution to see that the sprite was moving correctly on x and y axis. It was good that I tested it, since my sprite was moving the opposite direction I pressed. I had no idea that wasting time with a loop would cause sprite shaking and other side effects (which I probably haven't seen yet). The way you suggested makes sense now that I think about it. I guess I didn't even think that wait function was possible on NES. But since NMI happens once per frame, you could increment wait counters during it to get the wait counters to a consistent timing and not having to time the main loop with loops that do nothing. I guess I've been avoiding to add too much stuff to the NMI to make sure it always finishes in time.
Tsutarja wrote:
I guess I've been avoiding to add too much stuff to the NMI to make sure it always finishes in time.
That's why we do all the VBlank stuff first (everything related to the PPU), and then we do the rest of the periodic tasks, like updating counters, running the sound engine, reading the controllers, and so on. There's nothing wrong with your NMI taking longer than VBlank to finish, as long as the PPU stuff finishes before the VBlank does.
What you really must pay attention to is not letting your main loop take longer than a frame. That hardly happens in simpler games, but in games with a lot of action there's a big chance that the game logic will be prematurely interrupted by an NMI, and if you aren't prepared to handle such interruptions all kinds of bad things can happen.
Quote:
I had no idea that wasting time with a loop would cause sprite shaking and other side effects (which I probably haven't seen yet).
I can't say for sure that this was the cause, but think about it: you are constantly updating the sprites and waiting an arbitrary amount of time, over and over, and the NMI will interrupt that process at any time. Can you guarantee that the NMI handler will always find a consistent game state for its updates? What if the NMI hits when you've updated the coordinates of one sprite but not the other? The character represented by the sprites will look distorted for a frame. Depending on the task that's interrupted when the NMI fires, all kinds of side effects can result from using an inconsistent game state for a video update, and the program could even crash.
With the method I suggested, after your game reaches a consistent game state, which is ready for a video update, the engine patiently waits for such updates to happen before messing with the game state again.
I just added the counter for the NMI. Now I just need to find out why a duplicate of the left half of the sprite appears on the top left corner of the screen. It's not visible in the nametable viewer, so it's definitely a sprite. It's not moving along with the "real" sprite though. Like I said earlier, it's only visible during PAL emulation (I use it because I live in Finland and it's in the PAL region). The latest code I posted should work in finding the issue because all I have changed since I posted it is that I added the counter, removed the time waster loop and fixed some labels that I forgot to do before (though it doesn't affect to the execution of the code at all, I just fixed it so I won't get confused later). The issue did exist in that code too.
Tsutarja wrote:
Now I just need to find out why a duplicate of the left half of the sprite appears on the top left corner of the screen.
By any chance are you initializing your unused sprite RAM to $00?
Because if you are, then all of your "unused" sprites will appear at the top-left corner of the screen, and initializing them to $FF (or any value greater than or equal to $F7) should solve it.
Quietust wrote:
Tsutarja wrote:
Now I just need to find out why a duplicate of the left half of the sprite appears on the top left corner of the screen.
By any chance are you initializing your unused sprite RAM to $00?
Because if you are, then all of your "unused" sprites will appear at the top-left corner of the screen, and initializing them to $FF (or any value greater than or equal to $F7) should solve it.
So you mean that I should store #$FF to $0208-$02FF which is the unused portion of the sprite memory in my code.
Tsutarja wrote:
So you mean that I should store #$FF to $0208-$02FF which is the unused portion of the sprite memory in my code.
Correct.
Quietust wrote:
initializing them to $FF (or any value greater than or equal to $F7) should solve it.
Why $F7? I thought any value in $EF-$FF was good enough to put all sprites below the bottom of the picture.
tepples wrote:
Quietust wrote:
initializing them to $FF (or any value greater than or equal to $F7) should solve it.
Why $F7? I thought any value in $EF-$FF was good enough to put all sprites below the bottom of the picture.
Because I fail at math, apparently - the value I was looking for was 239, but I somehow translated that to $F7 ($F8 - 1) instead of $EF ($F0 - 1).
Initializing to $FF does something bad with the sprites on the next screen AFAIK. I forget what exactly, but #$F0 is the correct value to initialize to.
3gengames wrote:
Initializing to $FF does something bad with the sprites on the next screen AFAIK. I forget what exactly, but #$F0 is the correct value to initialize to.
No.
thefox wrote:
3gengames wrote:
Initializing to $FF does something bad with the sprites on the next screen AFAIK. I forget what exactly, but #$F0 is the correct value to initialize to.
No.
I forget what exactly, it had something to do with the rendering disable when sprites were found by the sprite logic, but there is a quirk with a certain off-screen value. I think $FF is right, I believe it was $EF that is bad to do.
3gengames: Please look it up and come back when you can actually explain what you're talking about. $EF-FF has been fine for my experience, and others' here.
By the way, you only have to set the Y component to $EF-FF, you don't have to set the whole unused sprite memory to it. For example, if you're done generating sprites for the frame and need to erase the rest of it, you can just write every 4th byte in the remaining space (i.e. the Y component) to hide them. The other 3 components to each sprite don't really matter in this case, once it's offscreen, it's offscreen.
viewtopic.php?t=4647#$EF would mean is screen is disables towards the bottom it could trigger the bug with some sprites since you can still disable the screen with those being "calculated"
After reading that thread, there is really nothing specific about that problem to $EF, but a problem with disabling rendering late in the frame? From what I could gather, it would only be a problem if you specifically disabled rendering on scanline $EF. Even if you were going to disable rendering late in the frame (a very advanced technique, not really pertinent to this thread), why on earth would you do it as late as scanline $EF?
Probably wouldn't, but yet better 100% sure it can't happen.
Got it working now. I changed my clear memory part of the reset routine.
Code:
ClearMem: ; Clear internal memory
LDA #$FF
STA $0200, x ; Set sprite memory to #$FF to render sprites off screen
LDA #$00
STA $0000, x ; Clear Zero Page
STA $0100, x ; Clear Stack
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
DEX
CPX #$00
BNE ClearMem
Next I'll be adding boundaries for the player's sprite so it won't screen wrap (should I just check coordinates or use hitbox?). I'm also adding a projectile function to see if I can despawn it once it leaves the screen. Though, I don't know how to make the sprite leave the screen smoothly. At least the player just "disappears" to the other side when the coordinates underflow. Is this a limitation in hardware or is there a way around this? I haven't actually paid attention to this when I have played NES games so I can't say for sure if I have seen this happening or not.
Quote:
Next I'll be adding boundaries for the player's sprite so it won't screen wrap (should I just check coordinates or use hitbox?)
Coordinates is fine. Edit: Well... I guess you do still need to add the width or height of the sprite to the coordinates so that going off each side is symmetrical.
Quote:
Though, I don't know how to make the sprite leave the screen smoothly.
For the right and bottom of the screen, add to the sprite's position. If the carry ends up set (adding 1 to 255 would wrap to 0 and set the carry), don't draw the sprite that frame and destroy the object.
For the top/left of the screen, subtract from the sprite's position. If the carry ends up clear, don't draw the sprite that frame and destroy the object.
Edit: With scrolling or other things that make detecting offscreen more complicated, the above alone can't be used by itself. But that should give you an idea of how to move things offscreen.
You cannot easily make the sprite visually leave smoothly from the top of the screen. The topmost coordinate you can supply is 0, and that still draws the entire sprite. Offscreen = not drawn at all, so all 8 pixels of the sprite would disappear in a frame when leaving from the top.
For the left of the screen, you can mask out the left most 8 pixels of sprites and the background with $2001. This means 0, the leftmost coordinate, is a fully masked sprite. 1 is the rightmost column of pixels in the sprite is drawn, the rest of it is not. Edit: Note that this just kind of makes the leftmost eight pixels a "border" with your background color for sprites to disappear into. The border still occupies screen space.
So... yes, it's a limitation, but only for twoish sides
.
Tsutarja wrote:
Code:
DEX
CPX #$00
BNE ClearMem
The CPX #$00 is redundant. Most instructions that change a value will set the zero flag if the result is zero, so the DEX instruction will set you up for BNE/BEQ already. It is very rare that you would ever need to explicitly compare against zero.