Metatiles and Dynamic Nametable Management [SOLVED]
Moderator: Moderators
Re: Metatiles and Dynamic Nametable Management
Scrolling impacts collisions pretty much the same way it impacts graphics - you know how the NES only has enough VRAM to hold 2 name tables, and if you want to scroll over a map that is larger than that you need to progressively overwrite the parts that move off screen with new graphics that will scroll into view from the other end? You can do the exact same thing with collision data - if you don't have enough memory to hold the collision data for an entire level, you can reserve RAM for a conveniently sized buffer and update it on its leading edge as the camera moves.
A small buffer will obviously not work if you need large portions of the level to be destructible and these changes need to be permanent... For small changes you can use objects, but if the whole thing is editable, the easiest approach is to include enough extra RAM on the cartridge to hold entire levels at once.
Another point I'd like to comment on is the use of bitmaps for collisions - I often see beginners opting to handle collisions that way, but I personally have never seen an actual game (from back in the day at least) that has levels built with blocks do this, and IMO there are a few good reasons for that:
1- Maintaining the visual representation of a level separate from its collision properties can easily lead to inconsistencies. You can easily forget to mark certain spaces as solid or empty, and also fail to update the collision map accordingly after making visual changes. Maintaining two things will always be more error-prone and time-consuming than maintaining only one.
2- Players expect blocks with a certain appearance to consistently behave the same way. In SMB for example, the player expects all brick blocks to be breakable, but if that information is stored separately from the blocks, there's a chance that some instances of these blocks will be assigned the wrong properties, possibly confusing and frustrating players.
3- Even if no mistakes are made, and the collision data is in perfect sync with the graphics data, that approach is just not very space-efficient - say that an SMB level has 1359 breakable blocks that all look the same and behave the same, what do you think is more compact: storing this "destructible" attribute only once along with the metatile data, or 1359 times, once for each instance of that block?
4- If you're scrolling, it's easier to buffer and update only one type of map, that contains data for both graphics and interactions. If these are separate, you're gonna need more code and memory in order to manage 2 independent buffers.
These are my main points against separate collision maps, but there are always exceptions, of course. In games where levels are not mostly built out of blocks, there may not be much of that expectation that things that look the same will behave the same, since the whole point in those cases is to make the graphical repetition less obvious. In those situations, it might actually make more sense to use the separate bitmap approach.
A small buffer will obviously not work if you need large portions of the level to be destructible and these changes need to be permanent... For small changes you can use objects, but if the whole thing is editable, the easiest approach is to include enough extra RAM on the cartridge to hold entire levels at once.
Another point I'd like to comment on is the use of bitmaps for collisions - I often see beginners opting to handle collisions that way, but I personally have never seen an actual game (from back in the day at least) that has levels built with blocks do this, and IMO there are a few good reasons for that:
1- Maintaining the visual representation of a level separate from its collision properties can easily lead to inconsistencies. You can easily forget to mark certain spaces as solid or empty, and also fail to update the collision map accordingly after making visual changes. Maintaining two things will always be more error-prone and time-consuming than maintaining only one.
2- Players expect blocks with a certain appearance to consistently behave the same way. In SMB for example, the player expects all brick blocks to be breakable, but if that information is stored separately from the blocks, there's a chance that some instances of these blocks will be assigned the wrong properties, possibly confusing and frustrating players.
3- Even if no mistakes are made, and the collision data is in perfect sync with the graphics data, that approach is just not very space-efficient - say that an SMB level has 1359 breakable blocks that all look the same and behave the same, what do you think is more compact: storing this "destructible" attribute only once along with the metatile data, or 1359 times, once for each instance of that block?
4- If you're scrolling, it's easier to buffer and update only one type of map, that contains data for both graphics and interactions. If these are separate, you're gonna need more code and memory in order to manage 2 independent buffers.
These are my main points against separate collision maps, but there are always exceptions, of course. In games where levels are not mostly built out of blocks, there may not be much of that expectation that things that look the same will behave the same, since the whole point in those cases is to make the graphical repetition less obvious. In those situations, it might actually make more sense to use the separate bitmap approach.
Re: Metatiles and Dynamic Nametable Management
Thanks for the responses. Tokumaru, what approach would you use? I haven’t been able to come up with a solution myself that didn’t involve some sort of map, but I don’t have advanced knowledge in these types of techniques. So, what I did was: every time I write a metatile, I take the bit for solidity and copy it into the bitmask. Of course, considering that I write the horizontal pillars in the opposite nametable, this doesn’t give acceptable results. However, I thought about writing with an offset or with a delay relative to when it will show up on the screen. I don’t think it’s effective though because a) it needs too much synchronization to work and b) I then realized something: I write the metatiles every 16 pixels, but these scroll by one pixel. What happens if the metatile has moved down by 5 pixels? In that case, there wouldn’t be any collisions but you’d still be on the metatile. In short, I really don’t know how to manage this point and a new approach, if you have one, would be very welcome. Thanks.tokumaru wrote: ↑Sat Oct 28, 2023 8:49 pm Scrolling impacts collisions pretty much the same way it impacts graphics - you know how the NES only has enough VRAM to hold 2 name tables, and if you want to scroll over a map that is larger than that you need to progressively overwrite the parts that move off screen with new graphics that will scroll into view from the other end? You can do the exact same thing with collision data - if you don't have enough memory to hold the collision data for an entire level, you can reserve RAM for a conveniently sized buffer and update it on its leading edge as the camera moves.
A small buffer will obviously not work if you need large portions of the level to be destructible and these changes need to be permanent... For small changes you can use objects, but if the whole thing is editable, the easiest approach is to include enough extra RAM on the cartridge to hold entire levels at once.
Another point I'd like to comment on is the use of bitmaps for collisions - I often see beginners opting to handle collisions that way, but I personally have never seen an actual game (from back in the day at least) that has levels built with blocks do this, and IMO there are a few good reasons for that:
1- Maintaining the visual representation of a level separate from its collision properties can easily lead to inconsistencies. You can easily forget to mark certain spaces as solid or empty, and also fail to update the collision map accordingly after making visual changes. Maintaining two things will always be more error-prone and time-consuming than maintaining only one.
2- Players expect blocks with a certain appearance to consistently behave the same way. In SMB for example, the player expects all brick blocks to be breakable, but if that information is stored separately from the blocks, there's a chance that some instances of these blocks will be assigned the wrong properties, possibly confusing and frustrating players.
3- Even if no mistakes are made, and the collision data is in perfect sync with the graphics data, that approach is just not very space-efficient - say that an SMB level has 1359 breakable blocks that all look the same and behave the same, what do you think is more compact: storing this "destructible" attribute only once along with the metatile data, or 1359 times, once for each instance of that block?
4- If you're scrolling, it's easier to buffer and update only one type of map, that contains data for both graphics and interactions. If these are separate, you're gonna need more code and memory in order to manage 2 independent buffers.
These are my main points against separate collision maps, but there are always exceptions, of course. In games where levels are not mostly built out of blocks, there may not be much of that expectation that things that look the same will behave the same, since the whole point in those cases is to make the graphical repetition less obvious. In those situations, it might actually make more sense to use the separate bitmap approach.
Re: Metatiles and Dynamic Nametable Management
Sorry, maybe i misunderstood your answer, regarding bytes five it was not used yet at that time of that code, now i’m used it to compile the bitmask at runtime and of course for metatile attributes and works fine compiling the collisionmap. Still, like the answers up to tokumaru response, dealing with scrolling is something that i don’t fully understand and i’m blowing my mind with itdonato-zits- wrote: ↑Sat Oct 28, 2023 7:06 pm no, I already got to implement colisions with bitmask, for learn well that I recomend that video ,was where I learn all the stuuf about it... but my intention now is to make a lot os blocks that the player could destroy in a digger action, something like a cave ambient; to a great amount of destructible terrain blocks or for a scroll game the bitmask colision map do not work

Re: Metatiles and Dynamic Nametable Management
Tokumaru means that games normally include the collision information among the metatile data instead of having a separate collision map. You would still use a map in RAM for your metatiles (the metatile map, AKA level map as mentioned earlier in the thread).
The graphic drawing routine would look up metatiles to know what tiles to draw on screen and the collision routines uses the same tables to check how to handle collisions with the metatile (if it's non-solid, solid, water, spikes or whatever).
So you would need one metatile map (might just be a map with metatile IDs for each map metatile position) and one metatile data look-up table which contains the data for each type of metatile. The graphic drawing and collision routines would handle the rest, they can use the metatile ID to index into the metatile data table.
When scrolling you need to swap out metatiles in the metatile map that are off screen for new ones as the map wraps around. To know which ones to swap you would have to keep track of the camera's position on the metatile map, and the map should ideally be larger than the screen so you can swap them outside the camera's viewport.
Unless you have the whole level metatile map in RAM (in which case you probably will need 8 kB cartridge SRAM). In that case you wouldn't need to do anything with the map after it is loaded, unless a metatile is changed of course (like Mario destroying a brick).
The graphic drawing routine would look up metatiles to know what tiles to draw on screen and the collision routines uses the same tables to check how to handle collisions with the metatile (if it's non-solid, solid, water, spikes or whatever).
So you would need one metatile map (might just be a map with metatile IDs for each map metatile position) and one metatile data look-up table which contains the data for each type of metatile. The graphic drawing and collision routines would handle the rest, they can use the metatile ID to index into the metatile data table.
When scrolling you need to swap out metatiles in the metatile map that are off screen for new ones as the map wraps around. To know which ones to swap you would have to keep track of the camera's position on the metatile map, and the map should ideally be larger than the screen so you can swap them outside the camera's viewport.
Unless you have the whole level metatile map in RAM (in which case you probably will need 8 kB cartridge SRAM). In that case you wouldn't need to do anything with the map after it is loaded, unless a metatile is changed of course (like Mario destroying a brick).
Last edited by Pokun on Sun Oct 29, 2023 8:17 am, edited 1 time in total.
Re: Metatiles and Dynamic Nametable Management
You definitely need a map in order to know which blocks go where, but my suggestion is that instead of adding a second layer/map on top of the existing block map, you make the collision information part of the block definitions (along with the tiles and palettes they use), so you can use just this one map, no matter if you're writing new tile/attribute data to VRAM or testing the collision properties of the blocks the objects are making contact with.
Assuming that you have a working metatile system, with 5 separate arrays of metatile properties (top left tiles, top right tiles, bottom left tiles, bottom right tiles, palettes) as has been suggested before, the basic idea is that that you add another array of properties, this time for the collision data. The byte at index 0 of this array will define the collision properties of the first metatile, the next byte corresponds to the second metatile, and so on all the way to the 256th metatile (if you have that many). One advantage of dedicating an entire byte to each metatile is that you can do do much better than "solid or empty" (which is all you can do 1 bit per block), such as 1-way platforms, breakable blocks, water, and even a few angles of slopes. Use your imagination to make the best possible use of those 8 bits to describe all the possible variations of blocks you plan on adding to your game.
Then you just have to figure out a way to have the level map (or at least part of it) readily available so you can easily locate metatiles in it (according to the positions of the objects that are colliding with them) and then test their collision properties. Having the entire map available at once is very convenient, but may require a lot of ROM or RAM depending on how you do it. If that isn't possible, the common approach is to use the circular buffer I mentioned before, where the parts that are left behind are replaced with new data that is about to be scrolled in.
Re: Metatiles and Dynamic Nametable Management
Thanks for answers guys, i'm using bit 2 for solidity in the fifth byte, i have just the map compile itself in a bitmap where every bits represent if the tile is solid or not. But i still can't understand how deal with scroll, if you saw one of my previuous little video i'm drawing the the 16x16 metatile starting from opposite nametable from bottom to up. now everytime i'm filling the collision table too, now, if i understand right i can make a circular array, switching all position inside the map. I'm updating the metatile so the map information every 16 frame so every 16 pixel units scroll but, the map, scroll vertically one pixel each frame, so it could be that the player go inside the scrolled metatile inbetween the 16 frame. I have to put an offset on the player check for this?
I', linking another video just to make an evidence of what happening until now, i'm filling the first 30 byte of hex editor everytime a metatile pillar is done https://www.youtube.com/watch?v=XY399cxDZlc
I', linking another video just to make an evidence of what happening until now, i'm filling the first 30 byte of hex editor everytime a metatile pillar is done https://www.youtube.com/watch?v=XY399cxDZlc
Re: Metatiles and Dynamic Nametable Management
Guys let me explain what i'm triyng to do. I made my variable of 60 byte to fill the two nametables, and i'm assuming that the viewport starts from byte 31 (30 indexed) so, cause i'm writing after the world camera scroll 16 pixels ans start to draw from the first usable bottom address of the second nametable and continues up, i'm writing the first byte and then let the variabile roll afterwards so after one nametable cycle the first metatile written appears on the screen et the top position and continue to roll to the bottom and after that is kicked out. This way everything i always synchronized with the viewport on screen. I'm thinking to fill the gap from 16 pixels to 16 pixels using this pixel as offset, so after calculate the collision on map i add the offset to check if the collision exists or not. It could be a good way to do this stuff? always an example on how to works right now with a little video, the first 60 byte in the hex editor is my collision bitmap, as you can see when it reaches the 30 position the tile appears on screen.
https://www.youtube.com/watch?v=WQI2m16Jg0A
https://www.youtube.com/watch?v=WQI2m16Jg0A
Re: Metatiles and Dynamic Nametable Management
Guys i made a system that works but not works fine cause there’s the problem i mentioned earlier, please someone lead me to the right way. everything works, the array roll, the checks are made, the collision happen in the right spot but there’s a caviat. The screen scroll one pixel a time, the map scroll everytime one metatile is written, so every 16 pixels, i’m trying to apply this dynamic offset to the player but it doesn’t work properly, any help would be very appreciated.
Re: Metatiles and Dynamic Nametable Management
It looks like you're struggling with consistently triggering scroll updates based on the number of scrolled pixels... so here's some advice regarding that:
Generally speaking, if the map is built from 16x16-pixel blocks, you have to draw a new slice (and possibly buffer a new slice of collision data) every 16 scrolled pixels. The thing is, you don't want to restrict the scroll speed to only one specific amount the entre time, or manually count scrolled pixels and risk getting out of sync. Fortunately, 16 is a power of two, so we can use some bitwise trickes here. If you pay attention to the binary representations of numbers, you'll see that bit 4 (the 5th bit) changes whenever a 16-unit boundary is crossed:
15 -> 16: 00001111 -> 00010000
29 -> 33: 00011101 -> 00100001
64 -> 60: 01000000 -> 00111100
Based on this fact, you can reliably detect a boundary crossing by backing up the old camera position (or scroll value, in case you don't have a camera entity per se, but I highly recommend you do), moving to the new position and comparing the two values to see if bit 4 changed. Bit changes can be detected with a XOR operation, since A XOR B will only be 1 if A and B are different. Here's how the test could be written in assembly:
After that, if your game can scroll both ways (i.e. players can backtrack), you need to find out the direction of the movement. Again, comparing the old and the new camera position can give you the answer. As long as the largest possible change is < 128 (and it will certainly always be in this case), a simple 8-bit signed comparison is enough (even if the camera's position is 16 bits - the higher bits have absolutely no effect on the result):
After this you know if the row you have to update is at the top of the screen or at the bottom, and you can calculate its position accordingly.
Generally speaking, if the map is built from 16x16-pixel blocks, you have to draw a new slice (and possibly buffer a new slice of collision data) every 16 scrolled pixels. The thing is, you don't want to restrict the scroll speed to only one specific amount the entre time, or manually count scrolled pixels and risk getting out of sync. Fortunately, 16 is a power of two, so we can use some bitwise trickes here. If you pay attention to the binary representations of numbers, you'll see that bit 4 (the 5th bit) changes whenever a 16-unit boundary is crossed:
15 -> 16: 00001111 -> 00010000
29 -> 33: 00011101 -> 00100001
64 -> 60: 01000000 -> 00111100
Based on this fact, you can reliably detect a boundary crossing by backing up the old camera position (or scroll value, in case you don't have a camera entity per se, but I highly recommend you do), moving to the new position and comparing the two values to see if bit 4 changed. Bit changes can be detected with a XOR operation, since A XOR B will only be 1 if A and B are different. Here's how the test could be written in assembly:
Code: Select all
lda CameraY ;gets the current position of the camera
eor OldCameraY ;compares it to the previous position
and #%0001000 ;isolates the bit we're interested in
bne UpdateRow ;branches if the bit has changed
Code: Select all
lda CameraY ;gets the current position of the camera
cmp OldCameraY ;calculates the difference from the previous position
bmi MovedUp ;branches if the difference is negative
bpl MovedDown ;branches if the difference is positive
Re: Metatiles and Dynamic Nametable Management
Thanks Tokumaru, i applied this logic not in your convenient way but will do it thanks. What i'm struggling si the offset to precise collisions, i'm applyng the difference between cameray and old camera y as offset to take care of the scroll inbetween the 16 pixels, but i don't know why it doesn't seem to work properly
this is a snippet of my code right now (i don't test direction right now but i will, in this moment i'm trying to subtract the value cause i was triyng something but just to know if the logic could be correct)
and in the camera manager:
this is a snippet of my code right now (i don't test direction right now but i will, in this moment i'm trying to subtract the value cause i was triyng something but just to know if the logic could be correct)
Code: Select all
LDA player_x
CLC
ADC #$05
STA temp_x
STA debugMarkerUpleftX
LDA player_y
CLC
ADC #$05
ADC CameraYDifference
STA temp_y
STA debugMarkerUpleftY
JSR check_collision_point
; Angolo in alto a destra
LDA player_x
CLC
ADC #10
STA temp_x
STA debugMarkerUpRightX
LDA player_y
CLC
ADC CameraYDifference
CLC
ADC #$04
STA temp_y
STA debugMarkerUpRightY
JSR check_collision_point
; Angolo in basso a sinistra
LDA player_x
CLC
ADC #$05
STA temp_x
STA debugMarkerDownleftX
LDA player_y
CLC
ADC #10
SEC
SBC CameraYDifference
STA temp_y
STA debugMarkerDownleftY
JSR check_collision_point
; Angolo in basso a destra
LDA player_x
CLC
ADC #10
STA temp_x
STA debugMarkerDownRightX
LDA player_y
CLC
ADC #10
SEC
SBC CameraYDifference
STA temp_y
STA debugMarkerDownRightY
JSR check_collision_point
DEC CameraYDifference
notupdate:
Code: Select all
continua:
CMP #16
BCC NonDisegnare
LDA CameraY
STA OldCameraY
JSR ShiftCollisionMap
JSR UpdateCollisionMap
LDA #$10
STA CameraYDifference
JSR VRAMCopyPrep
Re: Metatiles and Dynamic Nametable Management
Guys thanks, i did it, now i'm trying to apply much solid tokumaru's approach but works and without glitch
https://youtu.be/p-DMHrhkEGQ?si=NhdfIqu9-aY-2plv


Re: Metatiles and Dynamic Nametable Management
Good morning guys (at least at my slice of the world), i'd like to make some questions about how to procede. It's better to gather some information here to newbie like me or is better to make a new topic? Now that i solved, in my humble opinion of course, one of the most difficult technical barrier for my game (scroll, update and background dynamic collisions) i need to move on some other best practice and technique to implement the real gameplay and i'm a little confused about a lot of stuff, always considering a finished game and not a functionality demo.
Re: Metatiles and Dynamic Nametable Management
If your next question isn't directly about the topic (Metatiles and Dynamic Nametable Management) I think it might be better to open a new thread. If it's a very broad topic that is hard to narrow down to multiple smaller topics (something like "how to make an action game?") just give it a broad topic title, and you can ask about all sorts of things in the same thread. You can also link this topic to give some context to new readers.
Re: Metatiles and Dynamic Nametable Management
Great so i make this solved and maybe link this topic to the other ones.