puppydrum64 wrote: ↑
Mon May 17, 2021 7:22 pm
I read elsewhere that most games either associate collision data with metatiles or have that on a separate table in ROM.
Your metatiles currently have 4 bytes each. You need at least one more byte in order to specify which palette they use (2 bits) and their solidity (at least 1 bit, but if you have 1-way platforms, slopes or other kinds of fancy stuff, you'll definitely need more). The problem with this is that multiplying by 5 is not as fast or as straightforward as multiplying by 4. For this reason, many programmers chose to store their metatiles in parallel arrays (the 6502 is better suited for accessing structures of arrays rather than arrays of structures, after all):
Code: Select all
.db $45, $53, $b4, $ab, $24
.db $45, $54, $b5, $ad, $24
.db $47, $55, $b6, $ac, $24
.db $47, $56, $b7, $ae, $24
.db $80, $80, $81, $82, $00
This way you can immediaely access any byte of a metatile using only its index, no need to waste time calculating pointers.
Some programmers like to store collision and/or color information in the level map itself, because in some instances that can be easier to handle. That often requires more storage space though, since this information will be repeated for every instance of each metatile, as opposed to only once per metatile like in the example above. I personally prefer to make color and collision properties of the metatiles themselves, because it keeps things compact and consistent.
Code: Select all
LDA $0200,X ;get sprite Y position on screen
SBC fallingSpeed ;an arbitrary value
JSR DestroyObject ;some routine that replaces the sprite with blank tiles.
Collision aside, this is not really how you go about applying gravity. NES sprites are just a means of representing the objects that exist in your game, so you don't go around indiscriminately simulating physics on OAM entries like that. You're supposed to have your game objects modeled somewhere in RAM, where they have properties like coordinates, velocities, health, animation timers, and so on, and it's on those objects that you need to apply physics calculations. Then, once all objects have reached their final position for a frame, you generate the OAM entries necessary to draw them on the screen.
Also, each object normally has its own update subroutine, so that they get to decide what happens to them on a case-by-case basis. If you have the game engine control the objects from the outside, it gets much harder to take the necessities of each object into consideration. For example, not all objects are subject to gravity (e.g. floating coins the player can pick up are not supposed to fall), and even objects that *seem* like they're subject to gravity, may not really have any gravity applied to them as a means of saving CPU time (e.g. enemies that just patrol back and forth without ever falling don't actually need gravity).
As for collisions against the level geometry, the typical procedure goes something like this:
-Add up all forces acting on a the same axis to calculate the final displacement in that axis;
-Apply the displacement to the object;
-Depending on the direction of the movement (positive or negative), pick one edge of the object and check if that overlaps anything solid;
-If there was a collision against something solid, calculate how deep the edge of the object is into the solid object and push the object back that many pixels;
-Do the same for the other axis.