This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Sprite 0 hit flag to find out if character is grounded?

Sprite 0 hit flag to find out if character is grounded?
by on (#55473)
In paltformers can we use sprite 0 hit flag to find out if the character is grounded(on a platform) or not? What all can sprite 0 hit detection be used for?

by on (#55484)
You can, but it's a pretty dangerous thing to rely on Sprite 0 hits for such a thing; it's too limiting.

For one, your hit/polling loop might take up most of the screen time if your platform is near the bottom of the screen. Your code will be practically idle for much of the valuable processing time.

by on (#55485)
ccovell wrote:
You can, but it's a pretty dangerous thing to rely on Sprite 0 hits for such a thing; it's too limiting.

True. In practice, games make an internal model of an area map and then do collision between a sprite's hit box and that model. Super Mario Bros., for instance, uses a "metatile" grid, where each byte represents a 16x16 pixel area of the map, and keeps a 32x13-metatile sliding window of the map in RAM for collision purposes.

Quote:
For one, your hit/polling loop might take up most of the screen time if your platform is near the bottom of the screen.

Unless it runs during vertical blanking. Remember that the sprite 0 hit flag doesn't get turned off until the pre-render line; I seem to remember some demos relying on this for finding the end of vertical blank in order to turn on rendering late for greater VRAM bandwidth.

by on (#55495)
Sprite zero hit should NEVER be used as a form of logical collision detection.

Its only use is to split the screen at a specific point, or if you need to know when the vblank period ends, you can force a sprite 0 collision, but not directly poll it.

by on (#55496)
Another reason why it's not a good idea to use sprite 0 hits to detect the ground is that for a collision to happen the sprite must have opaque pixels, so you'd have to constantly worry about how to hide those pixels so nothing weird shows up below your character.

Also, you'd have to keep your player always 1 pixel into the ground, because you'd have no way to detect the collision before it happens. But what if your ground graphics do not have a plain surface, like usually happens with grass?

That being said, I have to agree that it's not a good idea to have the graphical side of the game affect the logical side. The best thing is to have your world completely modeled logically, so that all collisions are handled mathematically to later be represented with graphics.

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.

by on (#55501)
The main reason it wouldn't work is because you'd collide with everything. It would detect when Mario intersected with the hill in the background. I suppose you might use this to make a Worms/Scorched Earth sort of game, where you need pixel perfect collision on varied surfaces.

I would hesitate to say its only possible use it to split the screen or finding the end of vblank. Those are its most logical and common uses, but I'm sure a creative coder could come up with other good ways to take advantage of it. Platformer-style collision detection is probably not going to work well, though.

by on (#55506)
Seems to me that Sprite Hit 0 was just a cheap way of allowing raster effects on the base hardware rather than including some sort of built in scanline counter like they probably should have done. There really is no other use for it than attempting to time code to interact with rendering in some way. Logical game operations should never rely on that.

by on (#55510)
And remember that back in 1983 when the Famicom was designed, even basic operation of game consoles was a patent minefield. The whole sprite 0 madness might have just been Nintendo's way to work around patents.

by on (#55527)
tokumaru wrote:
That being said, I have to agree that it's not a good idea to have the graphical side of the game affect the logical side. The best thing is to have your world completely modeled logically, so that all collisions are handled mathematically to later be represented with graphics.

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.


I have tried to explain this so many times! Like when people do something like "INC $300" to move a sprite (assuming #3 is stored into $4014), I always tell them that it's a bad practice because of what you just said. So yeah, to all of you out there who hope to program a more complex game like a platformer, read what tokumaru just said because it is absolutely true. Well, the truth should never be deemed undeniable, I suppose, because if that were the case we would never think outside the box. However, in this case, I would say you shouldn't hard code things so that logic depends on what's displayed and the other way around. I would definitely stick with having a display engine that somehow displays what's going on inside the game world without the code in the game world being concerned with it. It shouldn't be the logic engine's responsibility to worry about what's displayed; the display engine should be the only code worried about that. It just makes cleaner, more logical, and more reliable code that is easier to modify should you decide to make changes.

EDIT: Also, relying on sprite #0 for collision is not a good idea, in my mind. Not only are you mixing display and logic code which makes a mess, you have to then figure out how you're going to make other objects collide with stuff. Not only that, you actually have to wait for the sprite #0 hit, wasting possibly dozens of scanlines in a loop. And the amount of time spent in this loop would probably range from not very long to the entire frame. What if sprite #0 is on the bottom of the screen? It's not THAT bad if it's on top, but you might as well just recode your game engine to be:

-
jmp -

If it's on the bottom, because you'll be wasting the whole frame waiting. And besides, once you find a way for other objects to collide with things, you might as well use that same method for the player (or whatever object would use the sprite #0 method). I also know from experience that using sprite #0 for collision is a bad idea; I've done it in a minigame I was working on.

Don't get me wrong, sprite #0 can be a life saver, and bazillions of NES games wouldn't be the same without it. I can't tell you how many games use it for something like displaying a status bar and having the rest of the screen scroll. I actually use it for that exact purpose in my platformer.

by on (#55531)
Celius wrote:
I would definitely stick with having a display engine that somehow displays what's going on inside the game world without the code in the game world being concerned with it. It shouldn't be the logic engine's responsibility to worry about what's displayed; the display engine should be the only code worried about that. It just makes cleaner, more logical, and more reliable code that is easier to modify should you decide to make changes.

Are you familiar with the Model-View-Controller design pattern? If you're not, take a look at it. This is a simple image that describes it:

Image

Look at how the controller can, well, control both the view and the model, and how the view watches the model, but the model is completely unaware of what surrounds it. Ideally, that's how games should be. The controller is a sort of manager, which handles inputs and things like that and modifies the view and the model as necessary. The view watches the model in order to draw a representation (or representations) of it, while the simulation keeps going indefinitely in the model. This allows for some cool things, like having different cameras watching different parts of a level and things like that.

Quote:
Not only that, you actually have to wait for the sprite #0 hit, wasting possibly dozens of scanlines in a loop.

That's not correct. Using sprite 0 for detecting game object collisions is very different from using it for raster effects. For raster effects, you know for sure that the hit will happen, and knowing exactly when it happens is the crucial thing, because that's when you have to modify some PPU register for the effect. But if you are trying to figure out if the player is touching the ground or not, there may be a possibility that the flag doesn't get set (when the player is jumping, for example), so if you wait for it in a loop your program will lock up when the character jumps. Also, it doesn't matter when in the frame the hit happened, you just want to know if it happened or not, so reading the flag once during VBlank will do the trick.

Still not a good idea by any means, but I felt like explaining this because it's not the first time that someone in this thread said that it would be necessary to wait for the sprite hit like it happens with raster effects.

Anyway, using sprite 0 to test collisions is a bad idea for several reasons: The background would have to be blank, because everything that wasn't would be solid; The player would have to be 1 pixel into the floor, because you wouldn't be able to predict the collision, you'd have to let it happen before detecting it; When going back to the ground after a jump the player would sink several pixels into the floor if moving at more than 1 pixel per frame before being ejected back; Since you would only read the flag during VBlank, you'd only have the previous frame's data; Since there's only 1 sprite 0 you could only do this for 1 character (what about the enemies?); There are probably dozens of other reasons I can't think of right now.

Quote:
Don't get me wrong, sprite #0 can be a life saver, and bazillions of NES games wouldn't be the same without it. I can't tell you how many games use it for something like displaying a status bar and having the rest of the screen scroll.

I don't know what the designers of the PPU had smoked when they came up with this feature. It's so limited! If at least it generated an IRQ or something... Or if it at least always set the flag when found to be in range... Seriously, doesn't every single game that uses sprite 0 hits make sure a hit will happen? Not a single game I know of is interested in knowing whether a hit happened, they are aways interested in when it happened, so Nintendo could very well have skipped the whole overlapping solid pixels bullshit.

I tend to disregard sprite 0 hits, much like I do with MMC3 IRQs. I know it may be a little extreme, but I can always think of several instances where those features would fail in my programs, so I'd rather design them without even considering those.

by on (#55533)
Oh, I see about what you were saying with the sprite #0 hit. I never thought about it that way. You mean reading the hit status of the previous frame in Vblank, right? That would definitely eliminate that whole dilemma I mentioned.

And I agree that the feature is terribly limited, but given nothing else it makes things a lot easier. What I think would be really great is even if they had a register you could read that gives the value of the current scanline being rendered in a byte. Like say they made it so you could read $2008 to get the value of the current scanline being rendered. You could have something like:

-
lda $2008
cmp #32
bne -

To wait until scanline 32 rather than having to put sprite #0 at that location. I think that would make things so much easier. And the whole solid pixel collision bit is SO DUMB. Why not just say the top-left corner? Well, if they were going to fix that, they might as well go the extra mile and make something better like an internal scanline counter.

Just curious: in what situations would your programs inevitably fail from MMC3 or sprite #0 hits? Too much processing time before the wait for the hit? I'd just like to know if there's something I'm overlooking in my game that would cause the game to freeze in an infinite loop waiting for a sprite #0 hit that won't work. The scanline counter for me, also, doesn't work so well because of what you have to sacrifice to use it. It's too much hassle.

Also, very interesting diagram. I'm glad you showed this to me. Now I can point to this model whenever I'm trying to explain the whole display/logic code separation. Thanks :)!

by on (#55536)
Celius wrote:
What I think would be really great is even if they had a register you could read that gives the value of the current scanline being rendered in a byte. Like say they made it so you could read $2008 to get the value of the current scanline being rendered.

That would be great, and probably much simpler to implement on hardware than the sprite 0 thing. You'd still have to wait for the scanline (an IRQ feature would be even better), but it's better than making sure the sprite hits the background, and could easily be used for multiple splits. I think the SMS has a scanline counter like this.

Quote:
in what situations would your programs inevitably fail from MMC3 or sprite #0 hits?

My problem with the MMC3 is that most of my projects have objects that can be drawn using either sprites or the background (like rings and monitors in my Sonic game), to compensate a bit for the sprites per scanline limit (it wouldn't be possible to have a row of 5 monitors if they were all sprites). To avoid wasting tiles, I want to put them on the BG side but use them as sprites too, but the extra fetches would break the scanline counter. I could even replicate the tiles if they weren't animated, but since they are (rings spin and monitors have static) it would be difficult, if not impossible, to update both sets of tiles in sync.

Quote:
Too much processing time before the wait for the hit?

Yeah, this is one of the problems with sprite 0 hits, if you miss the spot, you get corrupted graphics, there's no way out. I have considered sprite 0 in boss fights for example (to have huge background bosses), since the camera is locked to the "arena" I could disable the the row/column rendering system, which is one of the most intense things of the game. Also, the floor will always be pretty close to the bottom of the screen, so it's unlikely that I'll miss a sprite hit, but there is another problem: if the floor is not straight, or if I use the background color for parts of it I may accidentally cause the sprite to not hit solid background pixels, in which case results would be disastrous.

So I decided to not go through the trouble of working around these limitations and making things overly complex. I can do water without mid-screen palette changes, even if it means making water levels slightly less colored and not being able to move the water up and down. I can have background bosses if the floor is just made of horizontal lines (like in early Mega Man games or in Cocoron), because the floor can move sideways along with the bosses without anyone noticing (and a few sprites can be used to make the floor less dull, like in the intro of Darkwing Duck), even though I can only move them horizontally.

by on (#55537)
tokumaru wrote:

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.



Yes. It makes a lot of sense. The game logic can work on 1 color solid tiles both for background and sprites. Once the game logic is ready and working actual graphics can be put it to present the graphics in a better way.

Could you direct me to a game code(preferably small) where this has been applied?

by on (#55538)
Nadia wrote:
tokumaru wrote:

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.



Yes. It makes a lot of sense. The game logic can work on 1 color solid tiles both for background and sprites. Once the game logic is ready and working actual graphics can be put it to present the graphics in a better way.

Could you direct me to a game code(preferably small) where this has been applied?

I still don't know if you're quite understanding. You don't work on "1 color solid tiles," except in a logical/thematical sense. For example, you might program your logic to say, every tile with an ID less than 32 doesn't count as a collision (these are background tiles), and every tile with an ID greater that 32 counts as a collision. Or you might compress the map's data down to bitfields, so that a 0 is air and a 1 is solid ground:

00001111
00000111
11000000
00000000
10001111
11111111

You don't actually draw solid color tiles anywhere, you just treat your map as if it was. Some games do store the graphical map and data as above in separate areas; the data is known as a collision map. Collision data, solid ground data, is not drawn on the screen - it's just worked on by the engine.

As for examples, nearly every platforming game does it this way, in one form or another. I know that's not really much of an example...

An easy way to start programming this way is to first get your game showing one screen with background graphics and everything, and one character sprite. Lay out your map data in such a way that background stuff is all first in the PPU, and solid ground is last in the PPU. Then whenever the character moves, you can compare the character's coordinates on the screen with the background tile you are on top of at the moment (this will probably require some conversions depending on how you store your map data). If the sprite is on top of a solid tile, you don't allow that movement.

Think of button presses as a "request" to move, so that you check your map data and say, hmm, if the character moved one pixel forward he would be intersecting solid ground - I guess I'll stop that movement. This includes gravity. If you add to the character's y value each frame to make them fall, check where the character would be if his y was increased by that amount, and if it's inside something, then roll back the change. Put them back on their previous pixel coordinates.

Does that make sense? And yeah, it sounds complicated with lots of comparison, but you do have time in your engine to do it. The trouble is when you've got 10 enemies that also "request" to move in a certain direction as well. :)

by on (#55541)
tokumaru wrote:
My problem with the MMC3 is that [its scanline counter is really a sprite fetch counter, but] most of my projects have objects that can be drawn using either sprites or the background (like rings and monitors in my Sonic game), to compensate a bit for the sprites per scanline limit (it wouldn't be possible to have a row of 5 monitors if they were all sprites). To avoid wasting tiles, I want to put them on the BG side but use them as sprites too, but the extra fetches would break the scanline counter. I could even replicate the tiles if they weren't animated, but since they are (rings spin and monitors have static) it would be difficult, if not impossible, to update both sets of tiles in sync.

Here's a CHR ROM bank layout similar to that of SMB3 that allows sharing animated tiles between background and sprites:
  • Bank 0 ($0000-$07FF): level-specific tiles
  • Bank 1 ($0800-$0FFF): animated tiles, with spritable ones in the second half
  • Bank 2 ($1000-$13FF): player sprites
  • Bank 3 ($1400-$17FF): level-specific sprites
  • Bank 4 ($1800-$1BFF): common sprites
  • Bank 5 ($1C00-$1FFF): same bank number as second half of bank 1

Still doesn't solve replication though.

by on (#55555)
tepples wrote:
Here's a CHR ROM bank layout similar to that of SMB3 that allows sharing animated tiles between background and sprites:
  • Bank 0 ($0000-$07FF): level-specific tiles
  • Bank 1 ($0800-$0FFF): animated tiles, with spritable ones in the second half
  • Bank 2 ($1000-$13FF): player sprites
  • Bank 3 ($1400-$17FF): level-specific sprites
  • Bank 4 ($1800-$1BFF): common sprites
  • Bank 5 ($1C00-$1FFF): same bank number as second half of bank 1
Still doesn't solve replication though.

Yeah, a while ago I was thinking of the best way to do this... I don't remember if I got to the same layout as you just did, but I guess this would be the best way to do it. There would be a lot of replicated tiles, because level-specific background animations would have to animate the whole 2KB bank. Also, 2KB doesn't seem like enough to hold all level-specific tiles. Maybe the level animations could be synced to the constant animations and use the first half of the bank that goes in slot 1 instead, but then each level would have to have a copy of the constant animations.

Anyway, because of complications like this and the fact that the MMC3 wasn't cloned yet I decided to use CHR-RAM and a simpler mapper. A lot of cool stuff can still be done without CHR-ROM bankswitching or IRQs.

by on (#55583)
tokumaru wrote:
That being said, I have to agree that it's not a good idea to have the graphical side of the game affect the logical side. The best thing is to have your world completely modeled logically, so that all collisions are handled mathematically to later be represented with graphics.

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.

Well I 100% agree here, but I was wondering something.

When you want to change the attributes of only the top or the bottom metatile of the attribute block, is it okay to do a read-modify-write from $2007 ? I do that in my engine to split the attributes in lower and upper halves when I need to, so I have to read $2007 to do that. However it seems it breaks that rule, but it woks fine for me.

The other option would be to have a 128 byte copy of attribute tables in system RAM, and to read-modify-write it, and do a copy of it to $2007. Would that be the "better" option ? But it sounds like it wastes bytes of RAM since the exact same thing will be stored in VRAM anyway.

by on (#55588)
Bregalad wrote:
When you want to change the attributes of only the top or the bottom metatile of the attribute block, is it okay to do a read-modify-write from $2007 ? I do that in my engine to split the attributes in lower and upper halves when I need to, so I have to read $2007

Like reading the controller, reading $2007 is unreliable when playing sampled sound.

Quote:
The other option would be to have a 128 byte copy of attribute tables in system RAM, and to read-modify-write it, and do a copy of it to $2007. Would that be the "better" option ? But it sounds like it wastes bytes of RAM since the exact same thing will be stored in VRAM anyway.

You're already wasting 256 bytes for OAM unless you're doing what Hot Seat Harry does and overlapping your variables with $Fx-hidden sprites.

President, the side-scroller engine that I've put on a hopefully temporary hiatus, reads the map from the 32x12-metatile sliding window and then forms attributes based on that. The upper 2 bits of each metatile number hold the attribute, just as in SMB1. I don't think SMB1 even rewrites attributes when Mario interacts with tiles, which is why SMB1's "used ? block" is so simplistic.

by on (#55596)
Bregalad wrote:
The other option would be to have a 128 byte copy of attribute tables in system RAM, and to read-modify-write it, and do a copy of it to $2007. Would that be the "better" option ? But it sounds like it wastes bytes of RAM since the exact same thing will be stored in VRAM anyway.


Are you really that short on RAM though? Many games I've seen are great games and have plenty of untouched RAM. If it performs well you might decide it's worth it for the RAM cost, particularly if that RAM would have otherwise gone unused.

by on (#55598)
MottZilla wrote:
Are you really that short on RAM though? Many games I've seen are great games and have plenty of untouched RAM.

Storing what part of the environment has been destroyed can take a lot of RAM. M.C. Kids, for instance, had an extra PRG RAM chip just for this because the programmers didn't want to limit the engine to one destructible item per map column like I'm doing.

Quote:
If it performs well you might decide it's worth it for the RAM cost, particularly if that RAM would have otherwise gone unused.

Apart from ports from more powerful systems such as Hong Kong Originals, video games aren't developed in a pure waterfall model but in more of a spiral model because new requirements arise during play testing. Some of the RAM goes unused because it was reserved for future requirements.

by on (#55612)
Bregalad wrote:
When you want to change the attributes of only the top or the bottom metatile of the attribute block, is it okay to do a read-modify-write from $2007 ?

Do you mean when it comes to the logic-graphics separation? Reading-modifying-writing $2007 is perfectly fine IMO. I don't see any mixture of logic and graphics there... the whole $2007 operation is not necessary for the game to function, which means that it's purely graphic-related logic. The game objects will still "live" regardless of what you do with attributes.

But even if you needed the attribute data for deciding things in the game engine (like, all tiles using palette 3 are solid) you'd still be just fetching values from memory, but memory that's not accessible by the CPU so you have to do whatever the hardware requires you to do to access it.

Quote:
However it seems it breaks that rule, but it woks fine for me.

I guess that with limited machines like the NES you do have to break the rules sometimes, even though I don't think you are in this case. In a platformer I made for Flash I was able to follow the model-view-controller design pretty strictly, but on the NES I had to make my game objects themselves call the sprite drawing routine.

Ideally, the rendering engine would have to go through the active objects rendering whatever sprite each one pointed to, and the objects, aside from having a pointer to the sprite data that represents them, wouldn't give orders to the rendering system. On the NES that would mean looping through the sprites twice (once for running their AI and another for rendering them), having to decide whether they have sprites to render or not, and that would have taken too much time. So I've decided to let the objects themselves make decisions about how they'll be rendered, for performance reasons.

Quote:
The other option would be to have a 128 byte copy of attribute tables in system RAM, and to read-modify-write it, and do a copy of it to $2007. Would that be the "better" option ?

I don't think there is a better option for all cases... In my Sonic game I do this, but it's because of all the data I have to write to VRAM every frame. If I had to spend VBlank time reading values I'd have less time to write data, and I'd only be able to use what I read in one frame during the next frame, and that delay could have an impact on the scrolling speed.

But if I was scrolling in a single direction only, I'd probably not keep a copy of the AT. I'd compute the attributes as the screen scrolled, making use of the hidden NT, and in the eventual case of having to modify attributes in the visible portion of the screen I'd read-modify-write $2007.

MottZilla wrote:
Many games I've seen are great games and have plenty of untouched RAM.

I'd say that a Sonic game is fairly complex, and so far it seems I was able to map everything to the 2KB of RAM the NES offers, including the attribute table mirrors.

tepples wrote:
Apart from ports from more powerful systems such as Hong Kong Originals, video games aren't developed in a pure waterfall model but in more of a spiral model because new requirements arise during play testing.

Yeah, inspiring myself on existing games certainly made it easier to find a place for everything in the constrained memory space, since I know what "everything" is. But if you are coming up with something completely new, it really helps to think the whole thing through so that you can make better use of your RAM.

by on (#55625)
MottZilla wrote:
Are you really that short on RAM though? Many games I've seen are great games and have plenty of untouched RAM. If it performs well you might decide it's worth it for the RAM cost, particularly if that RAM would have otherwise gone unused.

You are right, I haven't been ever short of RAM yet. I think I have about $600-$7ff which are free.
Quote:
Do you mean when it comes to the logic-graphics separation? Reading-modifying-writing $2007 is perfectly fine IMO. I don't see any mixture of logic and graphics there... the whole $2007 operation is not necessary for the game to function, which means that it's purely graphic-related logic. The game objects will still "live" regardless of what you do with attributes.

I understand what you mean here. Reading modify-write $2007 is okay, because it's only graphics, and have nothing to do with game logic. Relying on $2007 reads to somehow affect the main engine in any way would NOT be okay (except when reading PRG data stored in CHR-ROM of course), altough never I'd do that.

Quote:


But even if you needed the attribute data for deciding things in the game engine (like, all tiles using palette 3 are solid) you'd still be just fetching values from memory, but memory that's not accessible by the CPU so you have to do whatever the hardware requires you to do to access it.

Oh my god this sounds like a very terrible idea. Never I'd do anything like that.
Quote:
Ideally, the rendering engine would have to go through the active objects rendering whatever sprite each one pointed to, and the objects, aside from having a pointer to the sprite data that represents them, wouldn't give orders to the rendering system. On the NES that would mean looping through the sprites twice (once for running their AI and another for rendering them), having to decide whether they have sprites to render or not, and that would have taken too much time.

In fact, this is exactly what my game engine does ! It don't take too much time.
However I have this annoying limitation 1 object = 1 metasprite.

I have ways to disable the sprite if I want to make an invisible object (like one which triggers the end of the stage if the player collides with it).
For a boss I'm developping, it has a huge armor and moving arm & legs, but wasn't big enough to be drawn with BG. Since defining the identical armor sprites for all frames was taking WAY too much space, I decided to split the boss in 2 objects, the armor "dumbly" follow the true boss (which is only made of arms and legs) and display always the same frame.
I'm still having major trouble with him (in fact he's the reason I haven't made any progress since 5 months) so I hope it will be as much a pain to players that it was a pain to me to code :twisted:

by on (#55640)
tokumaru wrote:
Ideally, the rendering engine would have to go through the active objects rendering whatever sprite each one pointed to, and the objects, aside from having a pointer to the sprite data that represents them, wouldn't give orders to the rendering system. On the NES that would mean looping through the sprites twice (once for running their AI and another for rendering them), having to decide whether they have sprites to render or not, and that would have taken too much time. So I've decided to let the objects themselves make decisions about how they'll be rendered, for performance reasons.


It's funny you guys are talking about this, because I recently had to code this part of my engine. I haven't yet reached the optimization stage of my project, but I'm pretty sure I'll be getting there really soon. With that said, I currently have AI and decisions about sprite drawing kind of separate. What I'm doing now is I have 7 bytes for each object set aside in RAM to handle animation. Each object can access 4 of these bytes. 2 point to the actual location of the animation "filmstrip", 1 gives some other commands, like whether or not to draw the sprite or to draw it flipped, and the other is used to specify with each bit which animation "number" is currently going on. By this, I mean I've basically allowed objects to only have 8 different animations, and I have a byte for each object in RAM where each bit represents one of these animations. It's mainly for the purpose of switching animations without glitches happening. Anyways...

After objects specify what animation they want to have play for them, and whether or not they're flipped, the animation handler that comes after takes care of the rest. The animation handler looks at all these values that the objects put in RAM, and picks the appropriate sprite map out of the animation specified, and uses that object's X/Y coordinates to draw them. I know it's not good to use the object's physical coordinates to draw them on the screen all the time, but my game is simple enough where that's not a big deal. I think it is a terrible idea, actually, to leave animation up to the objects themselves. Well, with the way I handle objects it would be. In my AI code, I have to use pretty much all indirect addressing, since when an object is spawned it is given the next available section of AI RAM (if there is one. If there's not, which I will always try to prevent by designing levels intelligently, then the object doesn't get spawned. That's just so nothing catastrophic happens in a situation like that like the game crashing). In my animation handler, I've unrolled the loop so that it handles the animation for each object by directly reading from the animation RAM, while each object accesses it indirectly. All the indirect addressing + a million INYs or DEYs would add up very quickly.

Also, I found myself pretty much having one metasprite and animation per object, though I can easily defy this limitation in the AI code itself. Only if I use the standard/universal animation handler will I have such limitations. I can push sprite maps onto my sprite stack from AI code if I needed to. I think I might have to do this for some more complicated looking enemies, if I see that I have them.

EDIT: As for available RAM, I think I have about 242 bytes left. That's not including the stack, which I never touch besides with PHP/PHA/PLP/PLAs. I find it adds up pretty quickly. Zero Page is almost gone, but not yet. I think I have $23 bytes available. But let's see what I've dedicated to what:

Code:
Not Available:
-----------------
$00-$AE         Misc. important variables, PPU buffers, Temp Vars, Temp Adds
$D2-$D7         Important variables relating to the level map
$D8-$DD         Temporary variables for AI stuff
$DE-$DF         Temp address for standard animation handler.
$E0-$FF         Character information

$100-$1FF      Stack
$200-$2F8      Buffers of 8x2 and 2x2 tiles for map decoding purposes. AI RAM.
$300-$3FF      OAM Page
$400-$481      Object Graphics Stack
$482-$4C0      Standard Animation RAM
$500-$56F      Sound Engine RAM
$570-$576      Tiny PPU Buffers for updating ammo, lives, and health information.
$600-$7FF      Tile Type Map for 2 screens (half behind and half ahead + current stuff on screen).

Available:
------------------
$AF - $D1      $23 bytes of ZP
$2F9 - $2FF      $07 bytes of non-ZP
$4C1 - $4FF      $3F bytes of non-ZP
$577 - $5FF      $89 bytes of non-ZP


But I find dedicating huge chunks of RAM to things like AI, sprite drawing, animation handling, sound, map decompression, the OAM page, etc. Adds up incredibly fast. As you can see I need to do some rearranging here, but for the most part that's what I'm looking at being left with. I actually don't know if I'll be needing to use any more RAM though. I've already got all the RAM I need to use set aside. So I used most of it, but not all of it.

by on (#55758)
UncleSporky wrote:
Nadia wrote:
tokumaru wrote:

Ideally, games should be able to run even if not displaying anything, because the game world is completely modeled and the simulation can happen even if nothing is shown. Graphics should just be visual snapshots of moments of the simulation. What I mean is, the graphics engine of your game should be as independent from the game logic as possible.



Yes. It makes a lot of sense. The game logic can work on 1 color solid tiles both for background and sprites. Once the game logic is ready and working actual graphics can be put it to present the graphics in a better way.

Could you direct me to a game code(preferably small) where this has been applied?

I still don't know if you're quite understanding. You don't work on "1 color solid tiles," except in a logical/thematical sense. For example, you might program your logic to say, every tile with an ID less than 32 doesn't count as a collision (these are background tiles), and every tile with an ID greater that 32 counts as a collision. Or you might compress the map's data down to bitfields, so that a 0 is air and a 1 is solid ground:

00001111
00000111
11000000
00000000
10001111
11111111

You don't actually draw solid color tiles anywhere, you just treat your map as if it was. Some games do store the graphical map and data as above in separate areas; the data is known as a collision map. Collision data, solid ground data, is not drawn on the screen - it's just worked on by the engine.

As for examples, nearly every platforming game does it this way, in one form or another. I know that's not really much of an example...

An easy way to start programming this way is to first get your game showing one screen with background graphics and everything, and one character sprite. Lay out your map data in such a way that background stuff is all first in the PPU, and solid ground is last in the PPU. Then whenever the character moves, you can compare the character's coordinates on the screen with the background tile you are on top of at the moment (this will probably require some conversions depending on how you store your map data). If the sprite is on top of a solid tile, you don't allow that movement.

Think of button presses as a "request" to move, so that you check your map data and say, hmm, if the character moved one pixel forward he would be intersecting solid ground - I guess I'll stop that movement. This includes gravity. If you add to the character's y value each frame to make them fall, check where the character would be if his y was increased by that amount, and if it's inside something, then roll back the change. Put them back on their previous pixel coordinates.

Does that make sense? And yeah, it sounds complicated with lots of comparison, but you do have time in your engine to do it. The trouble is when you've got 10 enemies that also "request" to move in a certain direction as well. :)



Thanks for the detailed description. I am indeed using a collision map of 240 bytes for the whole screen(1 byte per 16x16 metatile). In my map a '1' is air and a '0' is solid.
I am applying gravity only if the character is not "grounded".

In my last comment I quoted about "solid blocks". By that I meant that game logic is the more important thing and it should be working ok in the first place. Graphics can be put in at a later stage to give everything on screen a better and sensible look. So far I have created a screen and placed a couple of platforms on it. The sprite character I am using is nothing but a 16x16 rectangle.

At the moment I am trying to get background collision detection work with walking and jumping of my character.