Reputation: 3436
I have been reading about collision detection in games on stackoverflow and other sites. A lot of them talk about BSPs, bounding elipses, integration etc. However, on the NES, they managed to do floor and wall collision detection in games and I find it hard to believe that they did many calculations to detect wall collisions.
I guess my question is, given a level made up of just tiles, how did they detect collisions with walls and floors in games like Mario and Megaman which had little processing power?
I have written some collision code that is basically 'priori' as it searches for the first tile you will hit in a certain direction. I'm just wondering if there's a better way. (just using after-the-fact collision detection instead maybe)
eg, code to check for tile collisions for moving downward (I check vert then horizontal movement):
def tile_search_down(self, char, level):
y_off = char.vert_speed
assert y_off > 0
# t_ are tile coordintes
# must be int.. since we're adding to it.
t_upper_edge_y = int( math.ceil((char.y+char.h) / self.tile_height ) ) #lowest edge
while (t_upper_edge_y*self.tile_height) < (char.y+char.h+y_off): # lowest edge + offset
t_upper_edge_x = int( math.floor(char.x/self.tile_width) )
while (t_upper_edge_x*self.tile_width) < (char.x+char.w):
t_x = t_upper_edge_x
t_y = t_upper_edge_y
if self.is_tile_top_solid(t_x, t_y, plane):
char.y = t_y*self.tile_height - char.h
char.vert_speed = 0.0
char.on_ground = True
return
t_upper_edge_x += 1
t_upper_edge_y += 1
char.y += y_off
Upvotes: 24
Views: 23963
Reputation:
In older games collision detection was often less than perfect, trading accuracy for performance.
For example, in Super Mario Bros. collision with enemies is only checked every other frame. Collision with the end-of-level flag pole is done only once every 27 frames. There is also a limit on the maximum number of objects checked for collisions, which famously allows you to pass through some of Browser's attacks at the end of the game without dying.
Another example is the PC Engine port of Gradius. Rather than using more expensive bounding box hit detection, it uses a tile system. Each object is reduced to a tile number, consisting of the X and Y position rounded to a multiple of 8 and concatenated into a single number. If two objects occupy the same 8x8 tile they are deemed to have collided. It's less accurate but tends to favour the player, so presents an acceptable and fun compromise.
Upvotes: 2
Reputation: 143204
For the types of NES-era games you're talking about, everything was 2D. That alone simplifies many things.
Some machines of that era (particularly ones with hardware sprites, like the Commodore 64) had hardware collision detection. Most games that weren't relying on hardware collision detection would either use a bounding box or a hit mask (1-bit bitmap of the sprite).
Either way, collision detection was usually done "a posteriori", except for special cases like the edges of the world. Some games actually did have bugs where moving too fast when you hit something could cause you to pass through it. (In fact, reviews of early 80's games would often comment on how precise the collision detection was.)
For platformers, you'd typically check to see if the character is "grounded" before applying gravity.
The one-way platforms thing isn't too hard to deal with after the fact since you know the sprite's velocity vector, so you can use that to determine whether or not the collision should register.
Upvotes: 19
Reputation: 3436
There is article here that is an in-depth look at programming a Nintendo Entertainment System (NES) "platform game".
I may not have been googling right because I haven't stumbled upon this article before.
Upvotes: 16
Reputation: 1700
For games such as Super Mario World (SNES), the game stored the levels in a memory format that made it easy to take Mario's X/Y location, convert it to a tile address, and then check the tiles immediately around that address. Since the levels were always a fixed width (though the area you could view varied), it made addressing easier to manage since it was always a fixed offset from mario's position, e.g. Address + 1 for the tile beside mario, Address + 0x300 for the tile below him, etc.
Upvotes: 14