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

Opinions on floor collision

Opinions on floor collision
by on (#40848)
Hey everyone. I'm having some trouble coming up with a simple set of rules to implement decent floor collision. The problem is mainly about slopes, and I'll present it with a series of sketches.

Code:
  \
    \
      \          +---+
        \        |   |
          \      |   |
            \    |   |
              \  |   |
                \o---+
                  \
                    \
                      \
                        \

This is how the regular hitbox of the player would collide with a slope. This is not the desired behavior, as the art for the character would appear to not be standing on the floor (not without special angled sprites, at least).

In order to fix the problem above, we can shift the collision data to the left by half the character's width when a slope is detected (slopes can be detected when one of the edges of the hitbox is on the ground but the other is not) in order to center it and make it look more stable:

Code:
  \
    \
      \       +---+
        \     |   |
          \   |   |
            \ |   |
       +-> \  |   |
       |     \+-o-+
       |       \  \
   displaced        \
 collision map        \
                        \

Now, although the hitbox is colliding with the displaced version of the ground at the exact same point as before, because it is displaced it looks more correctly placed than before. This is great because every object, regardless of it's width, will seem to have it's central point colliding with the ground, as opposed to the quick fix of using art that differs from the collision data in hopes to compensate the bad positioning (but this would only work well for objects of a certain width).

Now, the fix proposed above should work well for slopes, but there are a couple of problems caused by it. Look at this:

Code:
     \
       \                   +---+
         \                 |   |
           \               |   |
             \             |   |
               \           |   |
                 \---------o-+-+
                             |
                             |
                             |
                             |

In this case, we do not want the character to fall yet, because it'd have half of it' body stuck into the wall while doing this. So we must find a way to tell slopes and pits apart, so that the collision data is not displaced on pits. This can probably be detected by looking at the sudden height decrease, so it's not such a big deal. Also, pits must be detected anyway to make the character start falling.

Now here's one thing I have no idea how to deal with:

Code:
  \
    \       +---+
      \     |   |
        \   |   |
          \ |   |
            |   |
            +-o-+
              |
              |
              |
              |
              |
              |

If the slope ends directly in a pit, there seems to be no way to make sure the character has the whole hitbox out of the wall before falling. I've been looking at some games, and Mega Man X on the SNES seems to handle this last case pretty well. On the Armadillo stage, there are some quite good slopes to try this stuff on. When you reach the end of the slope, instead of falling down you keep moving in a straight horizontal line until the whole hitbox is completely free to fall.

This means that Mega Man X behaves exactly as I'd like the characters in my project to. To only problem is that I can't seem to find a decent rule to fix this last problem that will be compatible with the other rules. Does anyone have any ideas? Can anyone think of a different set of rules to make this whole thing work?

This is not for my NES project, but for an ActionScript 3 game I'm making for college. The game doesn't really need to behave like this, but I'll have to deal with this kind of thing anyway later for my personal projects, so I decided I'd use this game as a testing ground. If anyone has anything to contribute, I really appreciate it.

by on (#40851)
Try reading the map's opacity and slope at the bottom center, bottom left, and bottom right of the sprite cel.

by on (#40852)
tepples wrote:
Try reading the map's opacity and slope at the bottom center, bottom left, and bottom right of the sprite cel.

And then...?

by on (#40853)
Code:
bool IsPlayerOnFloor()
{
  if( IsOnFloor( center_point ) )
    return true;

  if( IsOnFloor( left_corner ) )
    return !IsOnSlopedFloor( left_corner ) )

  if( IsOnFloor( right_corner ) )
    return !IsOnSlopedFloor( right_corner ) )

  return false;
}


I believe that's what tepples was getting at.

EDIT -

Hrm.. I just realized that wouldn't work with your last case there.

by on (#40859)
I was actually considering making ledges a tile type. Look a this:

Code:
\
 \
  \
   \gggggL
        v
        v
        v


\ is a slant, g is a completely solid metatile the player walks on top of, v is a wall, and L is a ledge tile type. Here's how "L" is handled. It acts just as "g" acts, a solid tile the player can walk on top of until the player's left bounding box border crosses the left edge of the L tile type. So it will allow the player to walk all the way off the edge until the left bounding box border crosses a certain point, at which point the player will fall into the pit. Now this idea could be modified, but I'm just throwing it out there.

by on (#40860)
So is this the right time to link to Gregmann's blog post about programming MC kids?

by on (#40862)
Dwedit wrote:
So is this the right time to link to Gregmann's blog post about programming MC kids?

That game isn't such a good example... the collision system is pretty hacky, and the author himself said there are still some problems with terrain collision (go up a hill and watch the player fall one pixel down to the ground at the top).

Anyway, this game seems to heavily rely on block types to make floor collision work properly. This is similar to what Celius suggested and it just might be the answer. Of course I'd like to come up with a system where the shape of the terrain would be enough for decent collision detection, but I guess I may be just dreaming here.

by on (#40863)
It's possible to create collision detection that's shape specific, especially if you're working with 16 pixel wide metatiles (though I don't know if this is what you are working with). For example, take this tile:

Code:
1              1
1              1
11            11
11            11
11            11
111          111
111          111
1111        1111
1111        1111
11111      11111
111111    111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111


This is 16x16 pixels, where each 1 is a solid pixel. All you need to do is define the heights of each column of pixels. In this case, you'd define a 16 byte array somewhere in ROM that goes:

.db 0, 2, 5, 7, 9, 10, 11, 11, 11, 11, 10, 9, 7, 5, 2, 0

Those define the relative Y coordinates in the tile of the tops of the columns of pixels. For these types of tiles though, you'd have to check for collision for every pixel along the bounding box edge. This is a major disadvantage because it's really slow.

by on (#40864)
I already use that kind of height table, yes. At first I thought I'd just have the central point of the sprite stick to the top of whatever pixel column it was on. However, when standing at the edge of a cliff, one of the corners should prevent you from falling. The problem is that if the central point defined the vertical position of the sprite, once it's out of the floor you can't simply have the corner point take over that role or there would be a "jump" when the position is adjusted to it.

It's really hard coming up with a decent collision system for irregular floors with slopes...! It's no surprise there were so many platformers that used only blocks or at most simple slopes.

by on (#40865)
Oy. Sorry I'm not contributing, but seeing all this makes me cringe. Hehe.

It was hard enough for me to get 90 and 0 degree platforms to work correctly. Luckily those will be all the platform types I'll use. I wouldn't want to begin thinking about slants. Especially that parabola Celius showed.

by on (#40866)
Collision detection on this level is a bit ridiculous, especially if you're dealing with entities wider than the metatile. Though it's very important for some things. I'm probably going to need this kind of table in my game for a completely circular solid platform (like the gears in the clock tower levels in Castlevania 3). This won't be so hard to deal with especially since the platforms are about 3-4 metatiles wide, so the player won't have to deal with mutliple collisions inside a tile, like the one I demonstrated above.

I've actually decided to stick with only a few types of solid metatiles: block, 1/1 (slope) slants, 1/2 slants. Though there are slants in all 4 directions, and I believe Castlevania Symphony of the Night on PS uses about that many tile types. However, I think it has 2/1 slants also, and I may incorporate this sort of thing in my game though I don't think it's that necessary.

by on (#40867)
There is yet one more way to possibly handle slopes: Inset them by 8 pixels, and use box collision as normal. Then you don't need to concern yourself with the bottom-center of the sprite, just the whole box. Probably not such a hot idea though.

by on (#40870)
Generally I think you should check for collision in the exact same way every time: if a collision point on the bounding box is within a certain tile, it has "collided" with that tile, meaning it is inside the tile. For different tile types, you handle collision detection (when the player doesn't just enter a tile, but physically collides with the ground) differently. For example, the player may stop being effected by gravity on a 1/1 slope when the player's midpoint on the bounding box RelativeY >= RelativeX. So in the case of 1/1 slopes, collision detection only applies to the midpoint of the object (so if the midpoint hasn't entered the 2x2 tile, there is no collision detection), but that's all up to the code that determines how something collides for that particular tile type. If you handle tile types separately with different collision conditions, I think you should be fine.

I would really stick with ledge tile types which don't appear on the screen, but like I explained they stick off of the ledge so the player can walk to the very end without falling off beforehand. You can also create 1/1 slope ledge tile type that extends off the ledge like so:

Code:
\
 \
  \
   \
   |\
   |
   |
   |


The code for this tile type would still tell the midpoint to collide with a 1/-1 slant, but only under the condition that the left edge of the bounding box hasn't past the left edge of the ledge tile. That's how you might handle that type of scenario.

by on (#40872)
Oh doing slopes really sounds complicated, and while many games didn't do it quite a few did it. When it comes to the NES, Gimmick and SMB3 instantly comes in mind, but it's true not that many NES games have slopes.

You'd want collision to fit into 2 bits or so. '00' means solid, '01' means transparent, '10' for left slope and '01' for right slope or something like that.

And what you said in the very fist post seems like a good solution, but instead of shifting collision data to the left, you should just design metatiles so that their collision slope doesn't match the graphic slope but is 8 pixels ahead. For example a slope will look like that graphically :
Code:
_
 \
  \
   \
    \
     \
      \
       \
        \
         |
         |
         |
         |
         |

But inside the computer for collision it would look like that :
Code:
\
 \
  \
   \
    \
     \
      \
       \_
         |
         |
         |
         |
         |


Using special metatile for slope start and slope end seems ackward and to be a bad idea overall. It's very user unfriendly too.

Oh and all of this makes me feel like I should add slopes to my game engine, but the simple 1-bit collision map barely fitted my metatile definition sheme.

by on (#40874)
Bregalad wrote:
instead of shifting collision data to the left, you should just design metatiles so that their collision slope doesn't match the graphic slope

Did you catch the part where I said this will only work for a specific sprite width? This is indeed the simplest solution, and might work well for the player, but once I have a huge enemy, like, 3 times wider than the player, walk on the same slope, things will look weird. Also, consider tiny items that might end up completely below the floor line.

Dynamically shifting the collision data (this isn't hard, really, just look a few pixels back instead of where the sprite actually is) on a per sprite basis will result in all of them having their middle points appear to be colliding with the floor. Or simply using the middle point at all times, just considering ledges special cases where the other 2 points (left and right) are considered too.

Both options should work, and the only real problem I see is the last case I presented. Celius' suggestion of extending the slope past the wall might work, but that's still specific to a certain sprite width. Different sprites will need different slope extensions to fall at the correct time.

by on (#40876)
Try using a collision system which uses the bottom corner points, and a movable point in between the corner points.

The idea is that the movable point defaults to the center between the two corner points, and you'll mostly be using the movable point to determine if the entity is on the ground or not.

If the movable point is on the ground, then the entity is on the ground, regardless of the corner points.

If the movable point is off the ground, but both of the corner points are on the ground, then you're on the ground, just too wide to fall through whatever gap is there.

If the movable point is off the ground, but just one of the corner points is on, then you're either floating over a slope, or you're stepping off of a ledge. The way you tell is by checking up to x amount of pixels underneath the movable point. If there's something solid under the point, within that tolerance, then you can simply reposition the entity on the ground, relative to the movable point.

If there's nothing under the movable point within the tolerance, then you slide the movable point towards the corner that still registers a collision, until the point is over the ledge, and you basically just glue the point to that edge, until you move in a way that the corner point moves off the ledge too, because that's when you fall.

If you walk back towards the ledge, rather than away from it, then once the movable point is back in the center of the entity, you unglue it from the ledge and you go back to repositioning the entity on top of the slope.

Hope this makes sense, I kinda had to think back to my TGF and MMF days to come up with it. :P

by on (#40885)
Quote:
Did you catch the part where I said this will only work for a specific sprite width? This is indeed the simplest solution, and might work well for the player, but once I have a huge enemy, like, 3 times wider than the player, walk on the same slope, things will look weird. Also, consider tiny items that might end up completely below the floor line.

Oh you are right. But after all, even if a signle corner would touch the slope, that wouldn't happear so weird. I looked at Gimmick and it seems to be like that. The collision window is typically slightly smaller than the area the sprite takes, so anyway some part of the sprite will be inside the slope and this won't look that weird.

Also, if the middle of the player is out of the cliff and that it falls, it won't look werid either. That's how actual physics woks in fact ! But yeah if half of your players goes into a wall it will look weird, unless you use minor pseudo-3D with oblique projection like Double Dragon or some Battletoads levels to hide that.

by on (#40915)
Drag wrote:
Try using a collision system which uses the bottom corner points, and a movable point in between the corner points.

I believe your idea is the most interesting so far, because it looks like it could work without the need for special blocks and other "hacks".

I'm still thinking of as many aspects of it as I can, as there is another complicated case I haven't talked about before: landing on a ledge. When a character is falling and hits a ledge, it might be difficult to place it the same as if it walked up to that point. I believe that with your technique this is possible though, I just have to give it some more thought. Thanks for the idea!
Bkg slope/char interaction
by on (#40917)
I've got the same exact issue with sloped tiles in my project as well. I've also got a lookup table per character type for the y height per x value. I'm going for a slope tile system something like the arcade version of strider.

So far what I'm doing is having a single floor detection point (F) on the center base of the character, and then two wall detection points (W) 12 pixels over, and 16 pixels up on either side. The character can slide down walls and wall jump like Megaman X.

I have a single ceiling detect point on the head about 48 pixels above the base as well (C). My character is 56 pixels tall, and between 16-24 chars wide. The ceiling detect point is used to zero out Y velocity when a solid tile is hit when jumping up. Eventually I want to have ceiling hang/grapple.

Code:
   
   C


W      W
 
   F


I just accepting that the character can overlap the wall in the wall for a small amount of time and I think I'll add a push away amount for cases where the character is too far inside the wall.

To make sure the character doesn't get trapped inside a wall what I do is that if the floor detection point is inside a totally solid wall, I move the character up to the ground plane of the tile above it. (My scroll speed in limited to 8 pixels at a time in H or V).

Wall detect points only prevent horizontal motion with totally solid tiles, not sloped tiles. So far, I haven't been able to get my character stuck inside a wall section unless I design my level/metatiles in a certain nefarious way.

Also, I've got a "floor magnet" type effect so that my character sticks to the ground when going down an up to 45 degree slope.

Steep slopes (2 tiles over, 1 tile up) I'm still working out a way to handle them.

I think a lot of the decisions made for terrain detection points and code comes down to personal preference and speed vs accuracy tradeoffs. I'm erring more on the speed side. There isn't really a "right" way to do it.. only a "right for the given project" way.

by on (#40918)
I had an idea you might find interesting. It does involve block types and it has its limitations, but if the blocks are small enough (good old 16x16 pixels should be fine), this should not be a big deal. OK, say I want my floor to look like this:

Image

If I use 2 major block types (solid = dark, detailed = light), I could draw it like this:

Image

Solid blocks make the basic shape and the detailed ones "decorate" it, making it look closer to what we actually want. All I have to do then is collide with each type of block in a different way: solid blocks use the whole area between the 2 hitbox corners, while detailed blocks only care about the central point.

Image

Whenever the entity walks towards the ledge, once it's off the detailed block it will start colliding with the solid block below, behaving like Mega Man X (SNES) and Pugsley's Scavenger Hunt (NES).

Image

The main limitation is that slopes must end perfectly aligned to the grid. This should not be obvious to the player/user, who usually does not know about any grids. I'm leaning towards coding it like this because it seems really simple, and the limitations are not that bad.