Actions

SPG:Slope Collision

From Sonic Retro

Revision as of 07:56, 11 November 2022 by LapperDev (talk | contribs) (Added animation for floor sensors)
Sonic Physics Guide
Collision
Physics
Gameplay
Presentation
Special

Notes:

  • The research applies to all four of the Sega Mega Drive games and Sonic CD.
  • This guide relies on information about tiles and sensors discussed in Solid Tiles.
  • This page is essentially part 1 of 2. This details specifics & basics of Player and Solid Tile collision. For part 2, detailing Player physics when on slopes and specific methods of collision with steep slopes such as walls and ceilings, go to Slope Physics.

Introduction

Now that you know how Solid Tiles and Sensors work, the Player object can use these to detect where nearby surfaces are, and react to collisions to essentially allow terrain around them to act "solid".

The Player's Sensors

Like any object which wants to collide with tiles, sensors are needed at the edges to detect the Solid Tiles. In the case of the Player object, many of these sensors surround them in all 4 directions.

SPGSensors.png SPGSensorAnchors.png The white points represent the anchor positions of the Player's sensors.

 A and B - Floor collision
 C and D - Ceiling collision (only used mid-air)
 E and F - Wall collision (shifting by 8px depending on certain factors, which will be explained)
 XY - the Player's X Position and Y Position


Since the Player's collision setup is symmetrical, it makes sense for the game to set up widths and heights using radius values. The Player has separate radius values for their E and F sensor pair (their Push Radius) which always remains the same, and for their A, B, C and D sensors there is a Width Radius and Height Radius both of which will change depending on the Player's state. For these sizes see Characters.

Note on sprite alignment:

  • The Player's sprite is 1 pixel offset to the left when they faces left, which can result in them appearing to be 1px inside a tile when pushing leftwards. Amusingly, this offset will appear corrected when pushing most objects thanks to their hitboxes sticking out 1px further on their right and bottom (due to their origins being off-centre by 1 in X and Y). So while tiles are collided with accuracy, it will appear the opposite in-game. More about object collision in Solid Objects.


Sensor Activation

Before jumping into exactly where these sensors are how these sensors make Sonic react to the floor, it's best to know when they are actually being used.

While Grounded

Floor Sensors A and B are always active while grounded, and will actively search for new floor below the Player's feet.

When grounded, Wall Sensors E and F only activate when the Player is walking in that direction. For example, while standing still the Player isn't checking with their wall sensors at all, but while Ground Speed is positive, the Player's E sensor is inactive, and while Ground Speed is negative, the Player's F sensor is inactive.

However this is not always the case, both wall sensors simply don't appear when the Player's Ground Angle is outside of a 0 to 90 and 270 to 360 (or simply -90 to 90) degree range, meaning when you running around a loop, the wall sensors will vanish for the top half of the loop. In S3K however these sensors will also appear when the Player's Ground Angle is a multiple of 90 in addition to the angle range.

While grounded Ceiling Sensors C and D are never active, and the Player won't check for collision with solid tiles above them while on the floor.

While Airborne

While in the air, all sensors play a part to find ground to reattach the Player to. But rather than have all active at once and risk lag, only 4-5 will be active at any given time.

As you move, the game will check the angle of your motion (X Speed and Y Speed) through the air. It will then pick a quadrant by rounding to the nearest 90 degrees. (this is different to the Mode, this is simply a measurement of if you are going mostly left, right up or down). The quadrant can be more easily found by simply comparing the X Speed and Y Speed and finding which is larger or smaller.

 if absolute X Speed is larger then or equal to absolute Y Speed then
   if X Speed is larger than 0 then
     the Player is going mostly right
   else
     the Player is going mostly left
 else
   if Y Speed is larger than 0 then
     the Player is going mostly down
   else
     the Player is going mostly up

Depending on the quadrant, different sensors will be active.

When going mostly right, the Player's F sensor will be active, along with both A and B floor sensors and the C and D ceiling sensors.

When going mostly left, it is the exact same as going right, but the E wall sensor instead.

When going mostly up, both the C and D ceiling sensors and the E and F wall sensors are active.

When going mostly down, it is the same as going up, but the A and B floor sensors are active instead of the ceiling sensors.


Floor Sensors (A and B)

SPGStandingAnimated.gif

A and B sit at their feet at Y Position + Height Radius.

SPGSensorsOnTiles.gif

A and B Movement

These sensors are A on the Player's left side, at X Position - Width Radius, Y Position + Height Radius. While B should be on their right, at X Position + Width Radius, Y Position + Height Radius.

These radius values change depending on the character and action (see Characters).

A and B Process

Floor sensors are a special case, there are 2 sensors and they effectively compete to find the nearest floor to the Player. Both sensors behave the same and search for a Solid Tile and the smaller distance is the sensor that wins. For example, -10 is a smaller distance than 5. The sensor that wins is is then the distance and tile angle used (and it's found tile is the one referenced).

Once the winning distance is found, it can be tested and used to reposition the player.

As we know, sensors return a distance to the nearest surface, up to an extreme maximum of 32 pixels. If the Player's floor sensors are within 32ish pixels of the floor, the game may know the floor is there but we might not just want them to snap down right away. The game will test the winning distance found and react appropriately.

While grounded

In Sonic 1, if the winning distance value is less than -14 or greater than 14, the Player won't collide. In Sonic 2 onward however the positive limit depends on the Player's current speed - in this case, (for when the Player is on the floor) if the distance is greater than

 minimum(absolute(X Speed)+4, 14)

then they won't collide. So the faster the Player moves, the greater the distance the Player can be from the floor while still being pulled back down to it. The -14 limit remains the same.

If the Player was in a sideways mode, such as on a wall, it would use Y Speed instead.

If the player does collide with the floor, the distance will be added to (or subtracted from, on ceilings or left walls) the Players position, and the Ground Angle will be set to the tile angle found by the winning sensor.

Well, the angle changing isn't quite so simple. Above it was mentioned that certain tiles are flagged, which changes how the game reacts to the angle. If the tile is flagged, (like a normal full block or certain other special tiles) rather than using the tile's angle, Ground Angle is simply set to the current Ground Angle, but snapped to the nearest 90 degrees.

In Sonic 2 onwards, this angle snapping also occurs with normal tiles if the absolute difference between your current Ground Angle and the tile's angle is greater than 45° (32) ($20).

While airborne

While airborne, if the winning distance value is greater than or equal 0 (meaning the sensor isn't overlapping the floor yet) the Player won't collide.

If still colliding after that check, the game will then check the following:

When moving mostly down, it will check if both sensor's distances are larger than or equal to -(YSpeed + 8). If either of them are, the player will collide, if neither of them are, the Player will not collide.

However when moving mostly left or mostly right, the Player will collide if the Player's Y Speed is greater than or equal to 0.

Of course, upon successfully colliding with the floor, the the Player's grounded flag is set and Ground Speed is set according to the angle.

Jumping "Through" Floors

The above airborne behaviours are most noticeable with jump through (top solid) tiles when jumping from underneath. The solid tiles that make up these ledges are flagged by the engine as being a certain type that should only be detected by the Player's A and B sensors, so solid from the top only.

These are often in the hilly, green zones such as Green Hill Zone, Emerald Hill Zone, Palmtree Panic Zone, and so on. They are ignored entirely by C and D as well as the wall sensors E and F. Finally, sensor A and B (mostly) are only active in the air when the player is not moving mostly upwards. So with a slightly shorter jump, you will see the Player 'pop' upwards onto a jump through surface once they begin to fall.

As discussed above there are conditions to be met aside from just the sensors being active and finding the floor related to both the distances found and the current Y Speed of the Player. So you may also see the Player pop upwards onto a Jump through ledge if you start moving to the side at the peak of a straight jump thanks to those more relaxed rules for landing when moving mostly left or mostly right.

Ledges

The Player has to be able to run off of ledges. It would not do to just keep walking like Wile E. Coyote, not noticing that there is nothing beneath them.

If both sensor A and B detect no solid tiles, the Player will "fall" - a flag will be set telling the engine they are now in the air.

Balancing On Edges

One nice touch is that the Player goes into a balancing animation when near to the edge of a ledge. This only happens when they are stopped (their Ground Speed is 0).

How does the engine know? It is simple - any time only one of the ground sensors is activated, the Player must be near a ledge. If A is active and B is not the ledge is to their right and vice versa.

But if the Player began balancing the instant one of the sensors found nothing, they would do it too "early", and it would look silly. So it only happens when only one sensor is active, and X Position is greater than the edge of the solid tile. This is checked with an extra downward sensor at the Player's X Position and Y Position + Height Radius when Ground Speed is 0. All this extra sensor does is check if there is floor at their X Position, is it not related to collision or physics.

SPGBalancingAnimated.gif

Assuming the right edge of the ledge to be an X position of 2655 ($0A5F), the Player will only start to balance at an X Position of 2656 ($0A60) (edge pixel+1). they'll fall off at an X Position of 2665 ($0A69) (edge pixel+10) when both sensors find nothing.

In Sonic 2 and Sonic CD, if the ledge is the opposite direction than they are facing, they has a second balancing animation.

In Sonic 2, Sonic 3, and Sonic & Knuckles, the Player has yet a third balancing animation, for when they are even further out on the ledge. Assuming the same values as above, this would start when they are at an X Position of 2662 ($0A66).

Note: While balancing, certain abilities are not allowed (ducking, looking up, spindash, etc). In the Player 3 & Knuckles, the player is still allowed to duck and spindash (not to look up, though) when balancing on the ground but not when balancing on an object.


Ceiling Sensors (C and D)

SPGHitCeiling.gif

the Player's C and D sensors are always an exact mirror image of the Player's floor sensors, they have the same X positions but are flipped upside down and face upwards. They perform in the exact same way, competing against eachother, simply up instead of down.

However, they aren't active at the same times as the floor sensors, only while airborne.

C and D Process

When these sensors find a ceiling, much like the floor sensors the sensor which finds the smallest distance will win. The sensor that wins is the distance and angle used (and it's found tile is the one referenced). This winning distance can then be subtracted from the Player's position.

The distances are processed here in the same way as the floor sensors while airborne, mainly being that a winning distance of greater than 0 is not reacted to.


Wall Sensors (E and F)

SPGPushingAnimated.gif

E sits at the Player's left at X Position-Push Radius, while F sits at their right at X Position+Push Radius.

E and F Movement

Push Radius is always 10, placing E to the Player's left side, at X Position - 10. While F is to their right, at X Position + 10, giving the Player a total width of 21 pixels when pushing.

Sensors E and F Spend most of their time at the Player's Y Position however while the Player's Ground Angle is 0 (on totally flat ground) both wall sensors will move to their Y Position + 8 so that they can push against low steps and not just snap up ontop of them.

The horizontal sensors are always positioned at Y Position while airborne.

You may remember that sensors A and B are only 19 pixels apart but the Player is 21 pixels wide when pushing into walls. This means that the Player is skinnier by 2 pixels when running off of ledges than when bumping into walls.

So, these sensors remain rather steady, especially considering that Push Radius never changes. That's not to say these sensors don't move relative to this starting position though. They do, and a lot. As noted in Main Game Loop wall collision (while grounded) actually takes place before the Player's position physically moves anywhere, so they wont actually be in a wall when they try to collide with it. The game accounts for this by actually adding their X Speed and Y Speed to the sensor's default position each frame, this is where the sensor would be if the Player had moved yet.

E and F Process

Assuming the wall's left side to be at an X position of 704 ($02C0), the Player cannot get closer than an X Position of 693 ($02B5). Assuming the wall's right side to be at an X position of 831 ($033F), the Player cannot get closer than an X Position of 842 ($034A). Thus the distance between both sensors inclusive should be 21 pixels, stretching from the Player's X Position-10 to X Position+10.

When the Player collides with a wall, this will set their Ground Speed to 0 if they are moving in the direction of the wall, not away from it.

The distance value found by the sensor in it's given direction is used to stop the Player at a wall.

While Grounded

The distances found by the wall sensors are used slightly differently while grounded.

Naturally, the game will ignore a positive distance because they will not collide. If the sensor's distance is negative, this means that when the Player's position actually does change, they will be inside the wall.

In this case, because the sensor is actually out in front of the Player (where they will be after they moves) instead of using the distance to reposition the Player by directly changing their position, the game smartly uses the fact that the Player has still yet to move within the current frame. All it has to do is add the distance to the Player's X Speed (if moving right, or subtract the distance from the Player's X Speed if moving left. This would be done to Y Speed if in wall mode). This results in the Player moving when their position changes, right up to the wall, but no further. In the next frame, because Ground Speed has been set to 0 the Player will have stopped just like in any other situation.

Thanks to this process and the sensor's movement, this effectively results in no difference between this and if the sensor was simply checked after movevment had occured like all other sensors.

While Airborne

Like normal, if the distance is negative and the sensor is inside the wall, they will collide. The game will ignore a positive distance.


Extra Sensors

The Player cannot jump when there is a low ceiling above them. When the Player initally tries jumping, C and D sensors are activated for one frame to check if their is ceiling too close. If there is a collision detected with upwards C and D sensors at the Player's X Position - Width Radius and X Position + Width Radius, and if the closest distance found is less than 6 (meaning for a character the same size as Sonic the ceiling would be 25 pixels above the Player's Y Position or closer while standing), the Player won't bother jumping at all.


Summary

Here's a handmade visualisation of how sensors interact with solid tiles (here highlighted in bright blue, green, and cyan). You can notice how the sensors are pushing the Player from the ground tiles, and is overall rather simple. The E and F sensors lower when on flat ground. You can also notice the sensors snap in 90 degree rotations resulting in four modes, this is covered in Slope Physics.

SPGCollisionDemo.gif Keep in mind, while on the ground the upper C and D sensors would not exist, and while gsp is positive the left wall sensor would also not appear. These sensors are only included for illustration purposes.


Bugs Using This Method

Unfortunately, there are a couple of annoying bugs in the original engine because of this method.

If the Player stands on a slanted ledge, one sensor will find no tile and return a height of foot level. This causes the Player to be set to the wrong position.

SPGSlopeBug1Animated.gif

The Player raises up with sensor B sensor as they moves right. When B drops off the ledge, the Player defaults to the level of sensor A. Then they raises up with sensor A as they moves further right. So they will move up, drop down, and move up again as they runs off the ledge.

There are only a few areas where this is noticeable, but it applies to all Mega Drive titles and is pretty tacky.

The second form of it occurs when two opposing ramp tiles abut each other, as in some of the low hills in Green Hill Zone and Marble Zone.

SPGSlopeBug2Animated.gif

Sensor B starts climbing down the ramp on the right, but the Player still defaults to the level of the previous ramp found by sensor A. Because these ramps are usually shallow, this only causes them to dip down in the middle by about 1 pixel.

But that is not all. Because the highest sensor is the one the Player gets the angle from, even though it looks like they should be considered to be at the angle of the ramp on the right (because they are closer to it), they will still have the angle of the ramp on the left. When you jump, they will jump at that angle, moving backward, not forward like you would expect.

Notes

  • This page is essentially part 1 of 2. This details specifics & basics of Player and Solid Tile collision. For part 2, detailing Player physics when on slopes and specific methods of collision with steep slopes such as walls and ceilings, go to Slope Physics.