Pokun wrote:
1. I need a hint on how to do collisions with non-moving solid objects like walls.
Here's an object and the level map it interacts with:
Code:
00 01 02 03 04 05 06 07
+------+------+------+------+------+------+------+------+
0 | | | | | | | | |
0 | | | | | | | | |
+------+------+------+------+------+------+------+------+
0 | | | | | | | | |
1 | | | 0----------1 | | | |
+------+------+----|$$$$$$$$$$|----+------+------+------+
0 | | | |$$$$$$$$$$| | | | |
2 | | | |$$$$$$$$$$| | | | |
+------+------+----|$$$$$$$$$$|----+------+------+------+
0 | | | |$$$$$$$$$$| | | | |
3 | | | |$$$$$$$$$$| | | | |
+------+------+----|$$$$$$$$$$|----+------+------+------+
0 | | | 2----------3 | | | |
4 | | | | | | | | |
+------+------+------+------+------+------+------+------+
0 | | | | | | | | |
5 | | | | | | | | |
+------+------+------+------+------+------+------+------+
You basically have to check all the blocks that touch one of the edges of the object whenever the object moves in that direction, and whenever solid blocks are found, push the object back enough so that it isn't overlapping the solid block anymore.
For example, if the object above moved right, you'd check all the blocks between points 1 and 3, which are (04, 01), (04, 02), (04, 03) and (04, 04). If any of those are solid, you push the object left enough so it stops overlapping the solid block. The process is the same for any of the 4 directions.
Quote:
I heard of having a map that keeps track of all solid terrain, but how would I go about doing that in practice?
Where you store the collision data is entirely up to you. Some people do use separate maps for solidity, but it makes much more sense to have the solidity as an attribute of the blocks used to draw the levels.
For the sake of simplicity, let's assume that the blocks we're dealing with are tiles, because tiles are always 8x8 pixels, while metatiles come in various sizes depending on the game.
Since the collision points are calculated from the sprite position, they are in pixel units. To find the coordinates of the corresponding tile, you have to divide the pixel coordinates by 8 (the width/height of a tile). For example, a point at pixel coordinates (173, 204) corresponds to the tile at (21, 25). Having the coordinates of the tile, you can calculate its address in a tile map using the following formula: Y * 32 + X, so in our example we're looking for the tile at offset (25 * 32) + 21 = 821. Using pointers you can read the index of the tile at that position, and use it to look up its solidity status. How you're gonna do that is up to you. You could have a table with 256 entries specifying the solidity of each tile, but for a simple game it makes sense to have that information built in the tile index itself... for example, tiles $00 to $3F are empty, tiles $40 to $7F are solid, tiles $80 to $BF are water, and so on.
Quote:
2. How do people store level data? Do you simply store full screens of nametable and attribute data or do you somehow use loops and stuff to draw it? Currently I store every screen/stage in their own uncompressed table.
Whatever fits the design of the game. Uncompressed NT/AT data is 1KB per screen, so that only makes sense for games that don't have many unique screens. Games with static screens should at least use RLE or LZ to reduce the size of these raw screens. Most games use metatiles though. 16x16 or 32x32 are very popular sizes, because they reduce the space occupied by each screen from 1024 to 254 and 64 bytes, respectively. And you can even compress the maps further.
Quote:
3. Currently the main character moves pixel by pixel but I'd like them to smoothly move one tile (or half tile) per button press like how Lolo or most RPG heroes does. Nothing I tried worked very well.
One way to do it is to create a state variable for your character. The variable starts in the "idle" state. When a direction is pressed in the controller, check if the player's coordinates are multiples of 8, and if that's the case, set the state to "walking up/down/left/right", depending on the direction that was pressed, otherwise, ignore the input. Then, check the state and move 1 pixel in the direction specified by it, if any. If after the movement the coordinates became multiples of 8, set the state to "idle" again.