From Sonic Retro
|Sonic Physics Guide
The Sonic games have a screen size of 320x224 pixels during normal Zone play. The Player isn't always locked in the centre of the screen, but has some freedom of movement within the view borders before it begins to scroll.
In the Sega Mega Drive games, the horizontal border is defined as:
- Left border: 144
- Right border: 160
Interestingly, this centres the Player when they walk right but they aren't centred when they walk left. If you so choose, you can change the borders to 152 and 168 instead, to even things out a bit.
In Sonic CD, though, horizontal scrolling works a bit differently. The camera doesn't really have a horizontal border, but rather defines a horizontal singular point to focus the Player's sprite at. By default, it's placed dead centre at 160, but it does shift around with the extended camera, which is explained below. We will call this the horizontal focal point.
When the Player moves past the border/horizontal focal point, the camera will catch up towards the Player by how much they have moved. However, the camera's movement speed is capped at 16 in Sonic 1, 2, and CD, and at 24 in Sonic 3, & K, due to limitations with the level drawing engine. This results in the camera lagging behind the Player if they are going too fast.
In all of the games, a singular vertical point is used for defining where to focus the Player's sprite at. By default, it's set to 96 pixels. It does shift around when the Player is looking up or down, which is explained below. We will call this the vertical focal point.
In the Air
A border is defined when the Player is in the air, with its centre point located at the vertical focal point.
- Top border: Centre - 32
- Bottom border: Centre + 32
When the vertical focal point is at its default position, it sets the top border at 64 and the bottom border at 128.
When the Player moves past the border, the camera will catch up towards the Player by how much they have moved. However, the camera's movement speed is capped at 16 in Sonic 1, 2, and CD, and at 24 in Sonic 3 & K, due to limitations with the level drawing engine. This results in the camera lagging behind the Player if they are going too fast.
The only time that the camera will scroll towards the Player when they are inside the border is when the bottom level boundary is in the middle of being shifted. In the original games, it only applies boundary checks when the camera is moving, and so when the bottom boundary is shifting, they keep the camera position updated. In your engine, it might be more ideal to always apply the boundary check, regardless of camera movement.
Note: Knuckles uses the same vertical borders while gliding and climbing. He's considered back on the ground when he starts to clamber over the corner of a wall, or stands up after sliding from a glide (i.e. when sliding, even though he is in contact with the ground, it still considers him to be in the air).
Here's a demonstration to show how the Player's Y position roams freely between the Y borders.
Note: Sonic's position may appear a little lower than a border while jumping, this is due to a 5px offset while sonic is curled which applies to all characters. See Solid Tiles for more details.
On the Ground
On the ground, there's not really a border, but rather tries to keep the Player's sprite positioned on the vertical focal point. The camera will move towards the Player by how much they have moved past it, with a speed cap applied, like with when the Player is in the air. However, that speed cap varies depending on a few circumstances.
If the vertical focal point is at its default position (again, 96), then the speed cap is 16 in Sonic 1, 2, and CD, or 24 in Sonic 3 & K if the Player's ground speed is greater than or equal to 8. If the Player's ground speed is less than 8, however, the speed cap will be set to 6. This makes the camera catch up faster when going fast, but otherwise go at a moderate pace.
If the vertical focal point is NOT at its default position (a.k.a., when it has shifted from looking up or down), then the speed cap is set to 2, no matter what.
Here's a demonstration to show how the Player's Y position stays locked to the central Y.
Looking Up and Down
- Looking Up: Vertical focal point moves down by 104 pixels (effectively scrolling up), at a rate of 2 per step.
- Looking Down: Vertical focal point moves up by 88 pixels (effectively scrolling down), at a rate of 2 per step.
In Sonic 1, the camera begins to scroll immediately when you press up or down. Obviously, this is annoying if there is to be a spindash or super peel out in your engine. In Sonic 2, 3 & K, the solution is to simply wait 120 steps after you begin to hold the button before it starts scrolling. In Sonic CD, though, another method is employed. After you press the up or down button, you have 16 steps to press it again, upon which the screen begins to scroll. Unfortunately it will freeze the scrolling if you press the up or down button while the screen is already scrolling. For instance, look up by double-tapping, let go, and then press down. The screen will freeze, and stay there until you let go. Even initiating a spindash doesn't return things to normal.
In all the games, once you let go of up or down (also in Sonic 2, 3, & K, once you initiate a spindash), the vertical focal point scrolls back to the default position by 2 pixels per step.
As explained before, the camera moves when it detects that the Player is not positioned at the vertical focal point. The shift will cause it to move.
(Not in Sonic CD)
The Player object has a previous position table in memory. The game knows where they've been over the last several seconds with frame precision. This is called upon for the spindash lag.
When the spindash is launched, a timer (t) is set to 32 (minus the rev variable, which can be between 0 and 8 - see spindash for more details). t then decreases by 1 every step.
While t is non-zero, the camera stops behaving normally and begins to move, not based on the Player's current position, but their position t-1 steps ago. Once t runs out, the camera returns to business as usual.
If the camera travels 32 steps into the past, and moves based on those recorded positions for a duration of 32 steps, it would effectively just repeat them, and then switch back to the current position, hopping 32 steps back into the future. This isn't how it works. Since it goes back 32 steps, and waits 32 more to return to normal, that means a total of 64 recorded camera positions. In order to take all of these positions into account during the 32 steps before the camera returns to normal, they are added together in pairs.
As an example, let's imagine the Player has been charging up their spindash for at least 32 steps, so that they haven't moved during this time. Then, they launch at a speed of 8. Since in the last 32 steps he hasn't moved, the camera will move by 0 + 0 for 16 frames, remaining stationary. Then, it will have caught up to the point in time at which the Player launched. The Player will have been moving 8 pixels every step from this point on. The camera will then move 16 pixels for 16 more steps until t runs out. (Technically, the Player doesn't move in the exact frame in which the spindash launches, so the camera will move by 0 + 8 for one step, and then 8 + 8 for a while, and the 7 + 8 as friction kicks in, and then 7 + 7, and so on).
The trouble with this lag is that if you initiate and release a spindash quickly enough after moving, the camera will actually move backward to follow where you've been.
Flame Shield/Hyper Sonic Air Dash
The same lag routine happens when Sonic does the airdash as Hyper Sonic, or with the Flame Shield. However, the trick is when he launches, the entire previous position table is blanked out with his current position, so that the camera can't scroll backward. In your engine, if you do the same thing for the launch of a spindash, you won't have to worry about backward scrolling at all.
- You can achieve an almost identical effect without a previous position table by simply disallowing the camera to move for about 16 steps after launching. This is somewhat easier to do.
Extended Camera (Sonic CD)
In Sonic CD only, when the Player reaches a ground speed of 6 (or is 16 steps into charging up a spindash or super peel out), the horizontal focal point is shifted back 64 pixels in the opposite direction the Player is facing, 2 per step. When their ground speed drops back below 6, it moves back to the default position (again, 160). The issue is, the ground speed doesn't update in mid-air, often leading to an off-centre view when jumping or running off of a ledge.
If you use this shift effect in your engine, you could perhaps use the Player's actual horizontal speed instead, as it doesn't make sense to scroll horizontally when going down or up a wall, or worse, on a ceiling.