Actions

Difference between revisions of "SPG:Slope Physics"

From Sonic Retro

m (The Three Speed Variables)
(Changing "Sonic" to "the Player")
Line 4: Line 4:
 
*This guide relies on information about tiles and sensors discussed in [[SPG:Solid_Tiles|Solid Tiles]]
 
*This guide relies on information about tiles and sensors discussed in [[SPG:Solid_Tiles|Solid Tiles]]
  
*Following only describes how [[Sonic the Hedgehog|Sonic]] collides and interacts with solid tiles. Solid objects, such as [[Monitor|Monitors]], Moving Platforms, and Blocks each have their own collision routines with Sonic and don't necessarily behave exactly the same as the tiles do. For this, refer to [[SPG:Solid_Objects|Solid Objects]].
+
*Following only describes how the Player collides and interacts with solid tiles. Solid objects, such as [[Monitor|Monitors]], Moving Platforms, and Blocks each have their own collision routines with the Player objects and don't necessarily behave exactly the same as the tiles do. For this, refer to [[SPG:Solid_Objects|Solid Objects]].
  
 
*Variables and constants for Sonic and other characters such as X Position and ''acc'' will be referenced frequently, they can be found in [[SPG:Basics|Basics]].
 
*Variables and constants for Sonic and other characters such as X Position and ''acc'' will be referenced frequently, they can be found in [[SPG:Basics|Basics]].
  
 
==Introduction==
 
==Introduction==
Once you have Sonic able to collide with solid tiles, he needs to move correctly over the terrian surface with momentum and physics. Knowing how sensors work will allow Sonic move smoothly over terrain with different heights, and knowing how Sonic's ground speed is affected by inputs to walk will allow him to move left and right, but that is not all there is to the engine.  
+
Once you have the Player object able to collide with solid tiles, they need to move correctly over the terrain surface with momentum and physics. Knowing how sensors work will allow the Player move smoothly over terrain with different heights, and knowing how the Player's ground speed is affected by inputs to walk will allow him to move left and right, but that is not all there is to the engine.  
This guide will explain how Sonic reacts to certain angles, and how 360 degree movement with momentum is acheived.
+
This guide will explain how the Player reacts to certain angles, and how 360 degree movement with momentum is achieved.
  
 
==Moving At Angles==
 
==Moving At Angles==
  
Sonic's speed has to be attenuated by angled ground in order to be realistic.
+
The Player's speed has to be attenuated by angled ground in order to be realistic.
  
There are two ways in which Sonic's ground speed is affected on angles. The first will make sure that he does not traverse a hill in the same amount of time as walking over flat ground of an equal width. The second will slow him down when going uphill and speed him up when going downhill. Let's look at each of these in turn.
+
There are two ways in which the Player's ground speed is affected on angles. The first will make sure that they do not traverse a hill in the same amount of time as walking over flat ground of an equal width. The second will slow them down when going uphill and speed them up when going downhill. Let's look at each of these in turn.
  
 
===The Three Speed Variables===
 
===The Three Speed Variables===
  
If Sonic were a simple platformer that required nothing but blocks, you would only need two speed variables: X speed (X Speed) and Y speed (Y Speed), the horizontal and vertical components of Sonic's velocity. Acceleration (''acc''), deceleration (''dec''), and friction (''frc'') are added to X Speed; jump/bounce velocity and gravity (''grv'') are added to Y Speed (when Sonic is in the air).
+
If Sonic were a simple platformer that required nothing but blocks, you would only need two speed variables: X speed (X Speed) and Y speed (Y Speed), the horizontal and vertical components of the Player's velocity. Acceleration (''acc''), deceleration (''dec''), and friction (''frc'') are added to X Speed; jump/bounce velocity and gravity (''grv'') are added to Y Speed (when the Player is in the air).
  
But when slopes are involved, while Sonic moves along a slope, he's moving both horizontally and vertically. This means that both X Speed and Y Speed have a non-zero value. Simply adding ''acc'', ''dec'', or ''frc'' to X Speed no longer works; imagine Sonic was trying to run up a wall - adding to his horizontal speed would be useless because he needs to move upward.
+
But when slopes are involved, while the Player moves along a slope, they're moving both horizontally and vertically. This means that both X Speed and Y Speed have a non-zero value. Simply adding ''acc'', ''dec'', or ''frc'' to X Speed no longer works; imagine the Player was trying to run up a wall - adding to their horizontal speed would be useless because they need to move upward.
  
The trick is to employ a third speed variable (as the original engine does), Ground Speed. This is the speed of Sonic along the ground, disregarding Ground Angle altogether. ''acc'', ''dec'', and ''frc'' are applied to Ground Speed, not X Speed or Y Speed.
+
The trick is to employ a third speed variable (as the original engine does), Ground Speed. This is the speed of the Player along the ground, disregarding Ground Angle altogether. ''acc'', ''dec'', and ''frc'' are applied to Ground Speed, not X Speed or Y Speed.
  
While on the ground, X Speed and Y Speed are derived from Ground Speed every step before Sonic is moved. Perhaps a pseudo-code example is in order:
+
While on the ground, X Speed and Y Speed are derived from Ground Speed every step before the Player is moved. Perhaps a pseudo-code example is in order:
  
   X Speed = Ground Speed*cos(Ground Angle);
+
   X Speed = Ground Speed * cos(Ground Angle)
   Y Speed = Ground Speed*-sin(Ground Angle);
+
   Y Speed = Ground Speed * -sin(Ground Angle)
 
    
 
    
   X Position += X Speed;
+
   X Position += X Speed
   Y Position += Y Speed;
+
   Y Position += Y Speed
  
No matter what happens to the Ground Angle, Ground Speed is preserved, so the engine always knows what speed Sonic is "really" moving at.
+
No matter what happens to the Ground Angle, Ground Speed is preserved, so the engine always knows what speed the Player is "really" moving at.
  
 
===Slope Factor===
 
===Slope Factor===
  
By this point, Sonic should be able to handle any hills with an accurate velocity but he still needs to slow down when going uphill and speed up when going downhill.
+
By this point, the Player should be able to handle any hills with an accurate velocity but they still need to slow down when going uphill and speed up when going downhill.
  
 
Fortunately, this is simple to achieve - with something called the Slope Factor. Just subtract Slope Factor*sin(Ground Angle) from Ground Speed at the beginning of every step.  
 
Fortunately, this is simple to achieve - with something called the Slope Factor. Just subtract Slope Factor*sin(Ground Angle) from Ground Speed at the beginning of every step.  
Line 44: Line 44:
 
   Ground Speed -= Slope Factor*sin(Ground Angle);
 
   Ground Speed -= Slope Factor*sin(Ground Angle);
  
The value of Slope Factor is always ''slp'' when running, but not so when rolling. When Sonic is rolling uphill (the sign of Ground Speed is equal to the sign of sin(Ground Angle)), Slope Factor is ''slprollup'' ($001E). When Sonic is rolling downhill (the sign of Ground Speed is '''not''' equal to the sign of sin(Ground Angle)), Slope Factor is ''slprolldown'' ($0050).
+
The value of Slope Factor is always ''slp'' when running, but not so when rolling. When the Player is rolling uphill (the sign of Ground Speed is equal to the sign of sin(Ground Angle)), Slope Factor is ''slprollup'' ($001E). When the Player is rolling downhill (the sign of Ground Speed is '''not''' equal to the sign of sin(Ground Angle)), Slope Factor is ''slprolldown'' ($0050).
  
'''Note:''' In Sonic 1, it appears that Slope Factor doesn't get added if Sonic is stopped and in his standing/waiting cycle. But in Sonic 3 & Knuckles, Slope Factor seems to be added even then, so that Sonic can't stand on steep slopes - they will force him to walk them down.
+
'''Note:''' In Sonic 1, it appears that Slope Factor doesn't get added if the Player is stopped and in his standing/waiting cycle. But in Sonic 3 & Knuckles, Slope Factor seems to be added even then, so that the Player can't stand on steep slopes - it will force them to walk down.
  
 
==Jumping At Angles==
 
==Jumping At Angles==
  
Jumping is also affected by the angle Sonic is at when he does it. He can't simply set Y Speed to negative ''jmp'' - he needs to jump away from the Ground Angle he's standing on. Instead, both X Speed and Y Speed must have ''jmp'' subtracted from them, using cos() and sin() to get the right values.
+
Jumping is also affected by the angle the Player is at when they do it. It can't simply set Y Speed to negative ''jmp'' - he needs to jump away from the Ground Angle they're standing on. Instead, both X Speed and Y Speed must have ''jmp'' subtracted from them, using cos() and sin() to get the right values.
  
 
More pseudo-code:
 
More pseudo-code:
  
   X Speed -= jmp*sin(Ground Angle);
+
   X Speed -= jmp * sin(Ground Angle)
   Y Speed -= jmp*cos(Ground Angle);
+
   Y Speed -= jmp * cos(Ground Angle)
  
 
Notice how the jump values are subtracted from the X Speed and Y Speed. This means his speeds on the ground are preserved, meaning running up fast on a steep hill and jumping gives you the jump speeds and the speeds you had on the hill, resulting in a very high jump.
 
Notice how the jump values are subtracted from the X Speed and Y Speed. This means his speeds on the ground are preserved, meaning running up fast on a steep hill and jumping gives you the jump speeds and the speeds you had on the hill, resulting in a very high jump.
Line 61: Line 61:
 
==Switching Mode==
 
==Switching Mode==
  
So Sonic can run over hills and ramps and ledges, and all that is great. But it is ''still'' not enough. He cannot make his way from the ground to walls and ceilings without more work.
+
So the Player can run over hills and ramps and ledges, and all that is great. But it is ''still'' not enough. They cannot make their way from the ground to walls and ceilings without more work.
  
 
Why not? Well, because sensor <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> check straight downward, finding the height of the ground. There is just no way they can handle the transition to walls when everything is built for moving straight up and down on the Y-axis.
 
Why not? Well, because sensor <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> check straight downward, finding the height of the ground. There is just no way they can handle the transition to walls when everything is built for moving straight up and down on the Y-axis.
Line 69: Line 69:
 
===The Four Modes===
 
===The Four Modes===
  
It seems pretty reasonable to assume that, because Sonic can traverse ground in 360 degrees, the engine handles all 360 degrees in much the same way. But, in fact, the engine splits the angles into four quadrants, greatly simplifying things.
+
It seems pretty reasonable to assume that, because the Player can traverse ground in 360 degrees, the engine handles all 360 degrees in much the same way. But, in fact, the engine splits the angles into four quadrants, greatly simplifying things.
  
 
To better understand what I am talking about, imagine a simpler platformer without full loops, just a few low hills and ramps. All the character would need to do is, after moving horizontally, move up or down until they met the level of the floor. The angle of the floor would then be measured. The angle would be used to attenuate Ground Speed, but nothing more. The character would still always move horizontally and move straight up and down to adhere to floor level.
 
To better understand what I am talking about, imagine a simpler platformer without full loops, just a few low hills and ramps. All the character would need to do is, after moving horizontally, move up or down until they met the level of the floor. The angle of the floor would then be measured. The angle would be used to attenuate Ground Speed, but nothing more. The character would still always move horizontally and move straight up and down to adhere to floor level.
  
This is much like how Sonic does things. Only, when Ground Angle gets too steep, Sonic switches "quadrant", moving from Floor mode to Right Wall mode (to Ceiling mode, to Left Wall mode, and back around to Floor mode, etc). At any one time, in any one mode, Sonic behaves like a simpler platformer. The magic happens by combining all four modes, and cleverly switching between them smoothly.
+
This is much like how the Sonic games do things. Only, when Ground Angle gets too steep, the Player switches "quadrant", moving from Floor mode to Right Wall mode (to Ceiling mode, to Left Wall mode, and back around to Floor mode, etc). At any one time, in any one mode, the Player behaves like a simpler platformer. The magic happens by combining all four modes, and cleverly switching between them smoothly.
  
So how and when does Sonic switch mode?
+
So how and when does the Player switch mode?
  
When in Floor mode, and Ground Angle is steeper than 45° ($E0), the engine switches into Right Wall mode. Everything is basically the same, only the sensors check to the right instead of downward, and Sonic is moved to "floor" level horizontally instead of vertically.
+
When in Floor mode, and Ground Angle is steeper than 45° ($E0), the engine switches into Right Wall mode. Everything is basically the same, only the sensors check to the right instead of downward, and the Player is moved to "floor" level horizontally instead of vertically.
  
Now that he's in Right Wall mode, if Ground Angle is shallower than 45° ($E0), the engine switches back into Floor mode.
+
Now that they're in Right Wall mode, if Ground Angle is shallower than 45° ($E0), the engine switches back into Floor mode.
  
 
The other transitions work in exactly the same way, with the switch angles relative to the current mode.
 
The other transitions work in exactly the same way, with the switch angles relative to the current mode.
  
When the mode is being calculated, it simply checks which quadrant Sonic's Ground Angle is currently in, which will place Sonic in the correct mode (ranges are inclusive):
+
When the mode is being calculated, it simply checks which quadrant the Player's Ground Angle is currently in, which will place the Player in the correct mode (ranges are inclusive):
  
 
   Floor Mode (start of rotation)
 
   Floor Mode (start of rotation)
Line 104: Line 104:
 
These ranges are symmetrical for left and right, but does favour the floor and ceiling modes, with their ranges being a degree or two wider.
 
These ranges are symmetrical for left and right, but does favour the floor and ceiling modes, with their ranges being a degree or two wider.
  
You might rightly ask where the ground sensors are when in Right Wall mode. They're in exactly the same place, only rotated 90 degrees. Sensor <span style="color:#00f000; font-weight: bold;">A</span> is now at Sonic's ''ypos''+9 instead of X Position-9. Sensor <span style="color:#38ffa2; font-weight: bold;">B</span> is now at Sonic's ''ypos''-9, instead of X Position+9. Instead of vertical sensor lines, they are now horizontal, stretching 16 pixels beyond his foot level (which is now 20 pixels "below" him, at X Position+20).
+
You might rightly ask where the ground sensors are when in Right Wall mode. They're in exactly the same place, only rotated 90 degrees. Sensor <span style="color:#00f000; font-weight: bold;">A</span> is now at the Player's Y Position + Width Radius instead of X Position - width Radius. Sensor <span style="color:#38ffa2; font-weight: bold;">B</span> is now at the Player's Y Position - Width Radius, instead of X Position + Width Radius. Instead of downward vertical sensor, they are now horizontal facing left, at his foot level (which is now "below" them, at X Position + Width Radius). You they move and rotate in the same way for the other modes.
  
Yes, because the sensors move so far, it is possible for Sonic to be "popped" out to a new position in the step in which he switches mode. However, this is hardly ever more than a few pixels and really isn't noticeable at all during normal play. To adjust for this in a new engine, an alternative method to switch mode would be to check for solid ground using a 90 degree rotated mask. For example, standing upright on flat ground, the left side would check rotated 90 degrees for steep slopes to switch to Left Wall Mode, and the right would check rotated -90 degrees for steep slopes to switch to Right Wall Mode. Only the lower ground sensor of the rotated mask would need to check for ground. This would have to exclude walls so Sonic doesn't begin walking on a wall when he gets near one, but would mean Sonic switched mode sooner on a slope which means less "popping".
+
Yes, because the sensors move so far, it is possible for the Player to be "popped" out to a new position in the step in which he switches mode. However, this is hardly ever more than a few pixels and really isn't noticeable at all during normal play.  
 +
 
 +
*To adjust for this in a new engine, an alternative method to switch mode would be to check for solid ground using a 90 degree rotated rectangle. For example, standing upright on flat ground, the left side would check rotated 90 degrees for steep slopes to switch to Left Wall Mode, and the right would check rotated -90 degrees for steep slopes to switch to Right Wall Mode. Only the lower ground sensor of the rotated mask would need to check for ground. This would have to exclude walls so the Player doesn't begin walking on a wall when they get near one, but would mean the Player switched mode sooner on a slope which means less "popping".
  
 
One more thing: I said that solid tiles were made of height arrays. Operative word: ''height''. How do they work when in Right Wall mode? Well, rather gobsmackingly, it turns out that in the original engine, each solid tile has ''two'' complementary height arrays, one used for when moving horizontally, the other for when moving vertically.
 
One more thing: I said that solid tiles were made of height arrays. Operative word: ''height''. How do they work when in Right Wall mode? Well, rather gobsmackingly, it turns out that in the original engine, each solid tile has ''two'' complementary height arrays, one used for when moving horizontally, the other for when moving vertically.
  
What about Left Wall and Ceiling mode? Wouldn't there need to be ''four'' height arrays? No, because tiles of those shapes simply use normal height arrays, just inverted. When in Ceiling mode, Sonic knows that the height value found should be used to move him down and not up.
+
What about Left Wall and Ceiling mode? Wouldn't there need to be ''four'' height arrays? No, because tiles of those shapes simply use normal height arrays, just inverted. When in Ceiling mode, the Player knows that the height value found should be used to move them down and not up.
  
 
<div class="large-12 columns" style="padding:0px">
 
<div class="large-12 columns" style="padding:0px">
 
<div class="large-6 columns" style="padding:0px">
 
<div class="large-6 columns" style="padding:0px">
With these four modes, Sonic can go over all sorts of shapes. Inner curves, outer curves, you name them. Here are some approximate example images with their angle values to help give you some idea of what this results in:
+
With these four modes, the Player can go over all sorts of shapes. Inner curves, outer curves, you name them. Here are some approximate example images with their angle values to help give you some idea of what this results in:
  
 
[[Image:SPGInnerCurve.PNG|link=Special:FilePath/SPGInnerCurve.PNG]] [[Image:SPGInnerCurveChart.PNG|link=Special:FilePath/SPGInnerCurveChart.PNG]]
 
[[Image:SPGInnerCurve.PNG|link=Special:FilePath/SPGInnerCurve.PNG]] [[Image:SPGInnerCurveChart.PNG|link=Special:FilePath/SPGInnerCurveChart.PNG]]
Line 124: Line 126:
 
[[Image:SPGOuterCurve.PNG|link=Special:FilePath/SPGOuterCurve.PNG]] [[Image:SPGOuterCurveChart.PNG|link=Special:FilePath/SPGOuterCurveChart.PNG]]
 
[[Image:SPGOuterCurve.PNG|link=Special:FilePath/SPGOuterCurve.PNG]] [[Image:SPGOuterCurveChart.PNG|link=Special:FilePath/SPGOuterCurveChart.PNG]]
  
You may notice Sonic's mode switches erratically on the convex curve, this is because his floor angle (Ground Angle) will suddenly decrease when switching to wall mode, causing it to switch back and forth until he is far enough down the curve to stabilise. This isn't usually noticeable, and happens less the faster you are moving.
+
You may notice the Player's mode switches erratically on the convex curve, this is because his floor angle (Ground Angle) will suddenly decrease when switching to wall mode, causing it to switch back and forth until he is far enough down the curve to stabilise. This isn't usually noticeable, and happens less the faster you are moving.
 
</div>
 
</div>
 
</div>
 
</div>
  
Note: The reason the gifs show the mode switch being the frame ''after'' the angle threshold is reached is simply because the collision being shown is the one used for ''that'' frame, ''before'' Sonic's Ground Angle updates.  
+
Note: The reason the gifs show the mode switch being the frame ''after'' the angle threshold is reached is simply because the collision being shown is the one used for ''that'' frame, ''before'' the Player's Ground Angle updates, but after they have moved.  
  
 
===When to Change Mode===
 
===When to Change Mode===
  
If you've checked the guide regarding the [[SPG:Main_Game_Loop|Main Game Loop]] you may notice the mode switching isn't mentioned at all, that's because the game doesn't actually ever "switch" his mode. Sonic's current "mode" is decided right before collision occurs. It will measure his angle, and decide which mode of collision to use right there and then. There is no "Mode" state stored in memory. So effectively, Sonic's mode changes whenever his angle (Ground Angle) does.  
+
If you've checked the guide regarding the [[SPG:Main_Game_Loop|Main Game Loop]] you may notice the mode switching isn't mentioned at all, that's because the game doesn't actually ever "switch" the Player's mode. The Player's current "mode" is decided right before collision occurs. It will measure his angle, and decide which mode of collision to use right there and then. There is no "Mode" state stored in memory. So effectively, the Player's mode updates whenever his angle (Ground Angle) does.  
  
Since the floor angle (Ground Angle) is decided ''after'' floor collision (as a result of floor collision) the floor collision that frame has to use the previous frames angle, even though Sonic has moved to a new part of the slope since then. This results in Sonic's mode effectively changing 1 frame ''after'' Sonic reaches one of the 45 degree angle thresholds.
+
Since the floor angle (Ground Angle) is decided ''after'' floor collision (as a result of floor collision) the floor collision that frame has to use the previous frames angle, even though the Player has moved to a new part of the slope since then. This results in the Player's mode effectively changing 1 frame ''after'' the Player reaches one of the 45 degree angle thresholds, as seen above.
  
 
===Falling and Sliding Off Of Walls And Ceilings===
 
===Falling and Sliding Off Of Walls And Ceilings===
  
When in Right Wall, Left Wall, or Ceiling mode and Sonic's Ground Angle is between 90 and 270, Sonic will fall any time absolute Ground Speed falls below ''fall'' ($0280) (Ground Speed is set to 0 at this time, but X Speed and Y Speed are unaffected, so Sonic will continue his trajectory through the air). This happens even if there is ground beneath him. If Sonic is in Right Wall, Left Wall, or Ceiling Mode but Sonic's Ground Angle is not between 90 and 270 then the horizontal control lock timer described below will still be set to 30 but Sonic will not enter a falling state remaining in his current state.
+
When in Right Wall, Left Wall, or Ceiling mode and the Player's Ground Angle is between 90 and 270, they will fall any time absolute Ground Speed falls below ''fall'' ($0280) (Ground Speed is set to 0 at this time, but X Speed and Y Speed are unaffected, so the Player will continue their trajectory through the air). This happens even if there is ground beneath them. If the Player is in Right Wall, Left Wall, or Ceiling Mode but their Ground Angle is not between 90 and 270 then the horizontal control lock timer described below will still be set to 30 but the Player will not enter a falling state remaining in their current state.
  
 
====Horizontal Control Lock====
 
====Horizontal Control Lock====
  
When Sonic falls or slides off in the manner described above, the [[SPG:Springs and Things#Horizontal Control Lock|horizontal control lock]] timer is set to 30 ($1E) (it won't begin to count down until Sonic lands back on the ground). While this timer is non-zero and Sonic is on the ground, it prevents the player from adjusting Sonic's speed with the left or right buttons. The timer counts down by one every step, so the lock lasts about half a second. During this time only ''slp'' and the speed Sonic fell back on the ground with is in effect, so Sonic will slip back down the slope.
+
When the Player falls or slides off in the manner described above, the [[SPG:Springs and Things#Horizontal Control Lock|horizontal control lock]] timer is set to 30 ($1E) (it won't begin to count down until the Player lands back on the ground). While this timer is non-zero and the Player is on the ground, it prevents directional input from adjusting the Player's speed with the left or right buttons. The timer counts down by one every step, so the lock lasts about half a second. During this time only ''slp'' and the speed the Player fell back on the ground with is in effect, so the Player will slip back down the slope.
  
   if (abs(Ground Speed) < 2.5 && (angle >= 45 && angle <= 315))  
+
   if abs(Ground Speed) < 2.5 and (angle >= 45 and angle <= 315)
 
   {
 
   {
     if (angle >= 90 && angle <= 270)
+
     if angle >= 90 and angle <= 270
 
     {
 
     {
       floor_mode = 0;
+
       floor_mode = 0
       Ground Speed = 0;
+
       Ground Speed = 0
 
     }
 
     }
     horizontal_lock_timer = 30;
+
     horizontal_lock_timer = 30
 
   }
 
   }
  
 
==The Air State==
 
==The Air State==
  
Any time Sonic is in the air, he doesn't have to worry about angles, Ground Speed, ''slp'', or any of that jazz. All he has to do is move using X Speed and Y Speed until he detects the ground, at which point he re-enters the ground state.
+
Any time the Player is in the air, they don't have to worry about angles, Ground Speed, ''slp'', or any of that jazz. All they have to do is move using X Speed and Y Speed until they detect the ground, at which point they re-enter the ground state.
  
 
===Jumping "Through" Floors===
 
===Jumping "Through" Floors===
  
There are some ledges that Sonic can jump up "through". These are often in the hilly, green zones such as [[Green Hill Zone (Sonic the Hedgehog 16-bit)|Green Hill Zone]], [[Emerald Hill Zone]], [[Palmtree Panic Zone]], and so on. The solid tiles that make up these ledges are flagged by the engine as being a certain type that should only be detected by Sonic's <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> sensors. They are ignored entirely by C and D as well as the horizontal sensor line. Finally, sensor <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> (mostly) only detect the floor when Sonic is moving downwards (but always while on the ground). So with a slightly shorter jump, you will see Sonic 'pop' upwards onto a jump through surface once he begins to fall.
+
There are some ledges that the Player can jump up "through". These are often in the hilly, green zones such as [[Green Hill Zone (Sonic the Hedgehog 16-bit)|Green Hill Zone]], [[Emerald Hill Zone]], [[Palmtree Panic Zone]], and so on. 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 <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> sensors. They are ignored entirely by C and D as well as the wall sensors E and F. Finally, sensor <span style="color:#00f000; font-weight: bold;">A</span> and <span style="color:#38ffa2; font-weight: bold;">B</span> (mostly) only detect the floor when the Player is moving downwards (but always while on the ground). So with a slightly shorter jump, you will see the Player 'pop' upwards onto a jump through surface once they begin to fall.
  
 
===Reacquisition Of The Ground===
 
===Reacquisition Of The Ground===
Both X Speed and Y Speed are derived from Ground Speed while Sonic is on the ground. When he falls or otherwise leaves the ground, X Speed and Y Speed are already the proper values for him to continue his trajectory through the air. But when Sonic lands back on the ground, Ground Speed must be calculated from the X Speed and Y Speed that he has when it happens.
+
Both X Speed and Y Speed are derived from Ground Speed while the Player is on the ground. When they fall or otherwise leave the ground, X Speed and Y Speed are already the proper values for him to continue his trajectory through the air. But when they land back on the ground, Ground Speed must be calculated from the X Speed and Y Speed that they have when it happens.
You might think that they would use cos() and sin() to get an accurate value, but that is not the case. In fact, something much more basic happens, and it is different when hitting into a curved ceiling as opposed to landing on a curved floor, so I will cover them separately.
+
You might think that the game would use cos() and sin() to get an accurate value, but that is not the case. In fact, something much more basic happens, and it is different when hitting into a curved ceiling as opposed to landing on a curved floor, so I will cover them separately.
  
 
As you land the angle of the ground you touch is read (Ground Angle).
 
As you land the angle of the ground you touch is read (Ground Angle).
The following covers the angle (Ground Angle) of the ground (floor or ceiling) that Sonic touches as he lands, and only happens the frame when he lands when changing from in air to on ground.
+
The following covers the angle (Ground Angle) of the ground (floor or ceiling) that the Player touches as they land, and only happens the frame when they land when changing from in air to on ground.
  
 
''Note: Since the classic games don't use degrees, and rather have angles ranging from 0 to 256, both approximate degree values and a more accurate (and inverted) decimal representation of the Hex values are included.''
 
''Note: Since the classic games don't use degrees, and rather have angles ranging from 0 to 256, both approximate degree values and a more accurate (and inverted) decimal representation of the Hex values are included.''
Line 221: Line 223:
 
   226° to 270° (161~192) ($5F~$40)
 
   226° to 270° (161~192) ($5F~$40)
  
Sonic reattaches to the ceiling and Ground Speed is set to Y Speed*-sign(sin(Ground Angle)).
+
The Player reattaches to the ceiling and Ground Speed is set to Y Speed*-sign(sin(Ground Angle)).
 
</div>
 
</div>
 
<div class="large-6 columns">
 
<div class="large-6 columns">
Line 229: Line 231:
 
   136° to 225° (97~160) ($9F~$60)
 
   136° to 225° (97~160) ($9F~$60)
  
Sonic hits his head like with any ceiling, and doesn't reattach to it. Y Speed is set to 0, and X Speed is unaffected.
+
The Player hits his head like with any ceiling, and doesn't reattach to it. Y Speed is set to 0, and X Speed is unaffected.
 
</div>
 
</div>
 
</div>
 
</div>
  
 
===Air Rotation===
 
===Air Rotation===
When Sonic leaves a slope, such as running up and off a quarter pipe, Sonic's angle smoothly returns to 0.  
+
When the Player leaves a slope, such as running up and off a quarter pipe, the Players's Ground Angle smoothly returns to 0.  
  
Sonic's angle (Ground Angle) changes by  
+
The Player's Ground Angle changes by  
 
   2.8125° (2) ($2)
 
   2.8125° (2) ($2)
 
each frame, in the direction towards 0.
 
each frame, in the direction towards 0.
 +
 +
 
*''Note: Degree angle is approximate, as the original game has angles ranging up to 256. Degree, decimal, and hex have been provided.''
 
*''Note: Degree angle is approximate, as the original game has angles ranging up to 256. Degree, decimal, and hex have been provided.''
*''Note: Regardless of Sonic's angle, Sonic's air sensors do not rotate. Air collision essentially ignores Sonic's mode.''
+
*''Note: Regardless of the Player's Ground Angle, their airborne sensors do not rotate. Air collision essentially ignores the Player's mode.''
  
 
[[Category:Sonic Physics Guide]]
 
[[Category:Sonic Physics Guide]]

Revision as of 15:56, 31 March 2021

Notes:

  • This guide relies on information about tiles and sensors discussed in Solid Tiles
  • Following only describes how the Player collides and interacts with solid tiles. Solid objects, such as Monitors, Moving Platforms, and Blocks each have their own collision routines with the Player objects and don't necessarily behave exactly the same as the tiles do. For this, refer to Solid Objects.
  • Variables and constants for Sonic and other characters such as X Position and acc will be referenced frequently, they can be found in Basics.

Introduction

Once you have the Player object able to collide with solid tiles, they need to move correctly over the terrain surface with momentum and physics. Knowing how sensors work will allow the Player move smoothly over terrain with different heights, and knowing how the Player's ground speed is affected by inputs to walk will allow him to move left and right, but that is not all there is to the engine. This guide will explain how the Player reacts to certain angles, and how 360 degree movement with momentum is achieved.

Moving At Angles

The Player's speed has to be attenuated by angled ground in order to be realistic.

There are two ways in which the Player's ground speed is affected on angles. The first will make sure that they do not traverse a hill in the same amount of time as walking over flat ground of an equal width. The second will slow them down when going uphill and speed them up when going downhill. Let's look at each of these in turn.

The Three Speed Variables

If Sonic were a simple platformer that required nothing but blocks, you would only need two speed variables: X speed (X Speed) and Y speed (Y Speed), the horizontal and vertical components of the Player's velocity. Acceleration (acc), deceleration (dec), and friction (frc) are added to X Speed; jump/bounce velocity and gravity (grv) are added to Y Speed (when the Player is in the air).

But when slopes are involved, while the Player moves along a slope, they're moving both horizontally and vertically. This means that both X Speed and Y Speed have a non-zero value. Simply adding acc, dec, or frc to X Speed no longer works; imagine the Player was trying to run up a wall - adding to their horizontal speed would be useless because they need to move upward.

The trick is to employ a third speed variable (as the original engine does), Ground Speed. This is the speed of the Player along the ground, disregarding Ground Angle altogether. acc, dec, and frc are applied to Ground Speed, not X Speed or Y Speed.

While on the ground, X Speed and Y Speed are derived from Ground Speed every step before the Player is moved. Perhaps a pseudo-code example is in order:

 X Speed = Ground Speed * cos(Ground Angle)
 Y Speed = Ground Speed * -sin(Ground Angle)
 
 X Position += X Speed
 Y Position += Y Speed

No matter what happens to the Ground Angle, Ground Speed is preserved, so the engine always knows what speed the Player is "really" moving at.

Slope Factor

By this point, the Player should be able to handle any hills with an accurate velocity but they still need to slow down when going uphill and speed up when going downhill.

Fortunately, this is simple to achieve - with something called the Slope Factor. Just subtract Slope Factor*sin(Ground Angle) from Ground Speed at the beginning of every step.

 Ground Speed -= Slope Factor*sin(Ground Angle);

The value of Slope Factor is always slp when running, but not so when rolling. When the Player is rolling uphill (the sign of Ground Speed is equal to the sign of sin(Ground Angle)), Slope Factor is slprollup ($001E). When the Player is rolling downhill (the sign of Ground Speed is not equal to the sign of sin(Ground Angle)), Slope Factor is slprolldown ($0050).

Note: In Sonic 1, it appears that Slope Factor doesn't get added if the Player is stopped and in his standing/waiting cycle. But in Sonic 3 & Knuckles, Slope Factor seems to be added even then, so that the Player can't stand on steep slopes - it will force them to walk down.

Jumping At Angles

Jumping is also affected by the angle the Player is at when they do it. It can't simply set Y Speed to negative jmp - he needs to jump away from the Ground Angle they're standing on. Instead, both X Speed and Y Speed must have jmp subtracted from them, using cos() and sin() to get the right values.

More pseudo-code:

 X Speed -= jmp * sin(Ground Angle)
 Y Speed -= jmp * cos(Ground Angle)

Notice how the jump values are subtracted from the X Speed and Y Speed. This means his speeds on the ground are preserved, meaning running up fast on a steep hill and jumping gives you the jump speeds and the speeds you had on the hill, resulting in a very high jump.

Switching Mode

So the Player can run over hills and ramps and ledges, and all that is great. But it is still not enough. They cannot make their way from the ground to walls and ceilings without more work.

Why not? Well, because sensor A and B check straight downward, finding the height of the ground. There is just no way they can handle the transition to walls when everything is built for moving straight up and down on the Y-axis.

How can we solve this? By using four different modes of movement. This will take a little explaining.

The Four Modes

It seems pretty reasonable to assume that, because the Player can traverse ground in 360 degrees, the engine handles all 360 degrees in much the same way. But, in fact, the engine splits the angles into four quadrants, greatly simplifying things.

To better understand what I am talking about, imagine a simpler platformer without full loops, just a few low hills and ramps. All the character would need to do is, after moving horizontally, move up or down until they met the level of the floor. The angle of the floor would then be measured. The angle would be used to attenuate Ground Speed, but nothing more. The character would still always move horizontally and move straight up and down to adhere to floor level.

This is much like how the Sonic games do things. Only, when Ground Angle gets too steep, the Player switches "quadrant", moving from Floor mode to Right Wall mode (to Ceiling mode, to Left Wall mode, and back around to Floor mode, etc). At any one time, in any one mode, the Player behaves like a simpler platformer. The magic happens by combining all four modes, and cleverly switching between them smoothly.

So how and when does the Player switch mode?

When in Floor mode, and Ground Angle is steeper than 45° ($E0), the engine switches into Right Wall mode. Everything is basically the same, only the sensors check to the right instead of downward, and the Player is moved to "floor" level horizontally instead of vertically.

Now that they're in Right Wall mode, if Ground Angle is shallower than 45° ($E0), the engine switches back into Floor mode.

The other transitions work in exactly the same way, with the switch angles relative to the current mode.

When the mode is being calculated, it simply checks which quadrant the Player's Ground Angle is currently in, which will place the Player in the correct mode (ranges are inclusive):

 Floor Mode (start of rotation)
 0° to 45° (1~32) ($FF~$E0)
 Right Wall Mode
 46° to 134° (33~95) ($DF~$A1)
 Ceiling Mode
 135° to 225° (96~160) ($A0~$60) 
 Left Wall Mode
 226° to 314° (161~223) ($5F~$21)
 Floor Mode (end of rotation)
 315° to 360° (224~256) ($20~$00)

Note: Since the classic games don't use degrees, and rather have angles ranging from 0 to 256, both approximate degree values and a more accurate decimal representation of the Hex values are included.

These ranges are symmetrical for left and right, but does favour the floor and ceiling modes, with their ranges being a degree or two wider.

You might rightly ask where the ground sensors are when in Right Wall mode. They're in exactly the same place, only rotated 90 degrees. Sensor A is now at the Player's Y Position + Width Radius instead of X Position - width Radius. Sensor B is now at the Player's Y Position - Width Radius, instead of X Position + Width Radius. Instead of downward vertical sensor, they are now horizontal facing left, at his foot level (which is now "below" them, at X Position + Width Radius). You they move and rotate in the same way for the other modes.

Yes, because the sensors move so far, it is possible for the Player to be "popped" out to a new position in the step in which he switches mode. However, this is hardly ever more than a few pixels and really isn't noticeable at all during normal play.

  • To adjust for this in a new engine, an alternative method to switch mode would be to check for solid ground using a 90 degree rotated rectangle. For example, standing upright on flat ground, the left side would check rotated 90 degrees for steep slopes to switch to Left Wall Mode, and the right would check rotated -90 degrees for steep slopes to switch to Right Wall Mode. Only the lower ground sensor of the rotated mask would need to check for ground. This would have to exclude walls so the Player doesn't begin walking on a wall when they get near one, but would mean the Player switched mode sooner on a slope which means less "popping".

One more thing: I said that solid tiles were made of height arrays. Operative word: height. How do they work when in Right Wall mode? Well, rather gobsmackingly, it turns out that in the original engine, each solid tile has two complementary height arrays, one used for when moving horizontally, the other for when moving vertically.

What about Left Wall and Ceiling mode? Wouldn't there need to be four height arrays? No, because tiles of those shapes simply use normal height arrays, just inverted. When in Ceiling mode, the Player knows that the height value found should be used to move them down and not up.

With these four modes, the Player can go over all sorts of shapes. Inner curves, outer curves, you name them. Here are some approximate example images with their angle values to help give you some idea of what this results in:

SPGInnerCurve.PNG SPGInnerCurveChart.PNG

You can observe Sonic's mode changing on the frame after his floor angle (Ground Angle) exceeds 45°. Sonic's position shifts a bit when the change occurs, due to the totally new collision angle and position.

SPGOuterCurve.PNG SPGOuterCurveChart.PNG

You may notice the Player's mode switches erratically on the convex curve, this is because his floor angle (Ground Angle) will suddenly decrease when switching to wall mode, causing it to switch back and forth until he is far enough down the curve to stabilise. This isn't usually noticeable, and happens less the faster you are moving.

Note: The reason the gifs show the mode switch being the frame after the angle threshold is reached is simply because the collision being shown is the one used for that frame, before the Player's Ground Angle updates, but after they have moved.

When to Change Mode

If you've checked the guide regarding the Main Game Loop you may notice the mode switching isn't mentioned at all, that's because the game doesn't actually ever "switch" the Player's mode. The Player's current "mode" is decided right before collision occurs. It will measure his angle, and decide which mode of collision to use right there and then. There is no "Mode" state stored in memory. So effectively, the Player's mode updates whenever his angle (Ground Angle) does.

Since the floor angle (Ground Angle) is decided after floor collision (as a result of floor collision) the floor collision that frame has to use the previous frames angle, even though the Player has moved to a new part of the slope since then. This results in the Player's mode effectively changing 1 frame after the Player reaches one of the 45 degree angle thresholds, as seen above.

Falling and Sliding Off Of Walls And Ceilings

When in Right Wall, Left Wall, or Ceiling mode and the Player's Ground Angle is between 90 and 270, they will fall any time absolute Ground Speed falls below fall ($0280) (Ground Speed is set to 0 at this time, but X Speed and Y Speed are unaffected, so the Player will continue their trajectory through the air). This happens even if there is ground beneath them. If the Player is in Right Wall, Left Wall, or Ceiling Mode but their Ground Angle is not between 90 and 270 then the horizontal control lock timer described below will still be set to 30 but the Player will not enter a falling state remaining in their current state.

Horizontal Control Lock

When the Player falls or slides off in the manner described above, the horizontal control lock timer is set to 30 ($1E) (it won't begin to count down until the Player lands back on the ground). While this timer is non-zero and the Player is on the ground, it prevents directional input from adjusting the Player's speed with the left or right buttons. The timer counts down by one every step, so the lock lasts about half a second. During this time only slp and the speed the Player fell back on the ground with is in effect, so the Player will slip back down the slope.

 if abs(Ground Speed) < 2.5 and (angle >= 45 and angle <= 315)
 {
   if angle >= 90 and angle <= 270
   {
     floor_mode = 0
     Ground Speed = 0
   }
   horizontal_lock_timer = 30
 }

The Air State

Any time the Player is in the air, they don't have to worry about angles, Ground Speed, slp, or any of that jazz. All they have to do is move using X Speed and Y Speed until they detect the ground, at which point they re-enter the ground state.

Jumping "Through" Floors

There are some ledges that the Player can jump up "through". These are often in the hilly, green zones such as Green Hill Zone, Emerald Hill Zone, Palmtree Panic Zone, and so on. 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. They are ignored entirely by C and D as well as the wall sensors E and F. Finally, sensor A and B (mostly) only detect the floor when the Player is moving downwards (but always while on the ground). So with a slightly shorter jump, you will see the Player 'pop' upwards onto a jump through surface once they begin to fall.

Reacquisition Of The Ground

Both X Speed and Y Speed are derived from Ground Speed while the Player is on the ground. When they fall or otherwise leave the ground, X Speed and Y Speed are already the proper values for him to continue his trajectory through the air. But when they land back on the ground, Ground Speed must be calculated from the X Speed and Y Speed that they have when it happens. You might think that the game would use cos() and sin() to get an accurate value, but that is not the case. In fact, something much more basic happens, and it is different when hitting into a curved ceiling as opposed to landing on a curved floor, so I will cover them separately.

As you land the angle of the ground you touch is read (Ground Angle). The following covers the angle (Ground Angle) of the ground (floor or ceiling) that the Player touches as they land, and only happens the frame when they land when changing from in air to on ground.

Note: Since the classic games don't use degrees, and rather have angles ranging from 0 to 256, both approximate degree values and a more accurate (and inverted) decimal representation of the Hex values are included.

When Falling Downward

SPGLandFloor.png

The following ranges are inclusive.

Shallow: When Ground Angle is in the range of

 0° to 23° (1~16) ($FF~$F0) 
 and mirrored:
 339° to 360° (241~256) ($0F~$00)

Ground Speed is set to the value of X Speed.

Half Steep: When Ground Angle is in the range of

 24° to 45° (17~32) ($EF~$E0) 
 and mirrored:
 316° to 338° (225~240) ($1F~$10)

Ground Speed is set to X Speed but only if the absolute of X Speed is greater than Y Speed. Otherwise, Ground Speed is set to Y Speed*0.5*-sign(sin(Ground Angle)).

Full Steep: When Ground Angle is in the range of

 46° to 90° (33~64) ($DF~$C0) 
 and mirrored:
 271° to 315° (193~224) ($3F~$20)

Ground Speed is set to X Speed but only if the absolute of X Speed is greater than Y Speed. Otherwise, Ground Speed is set to Y Speed*-sign(sin(Ground Angle)).

When Going Upward

SPGLandCeiling.png

The following ranges are inclusive.

Slope: When the ceiling Ground Angle detected is in the range of

 91° to 135° (65~96) ($BF~$A0) 
 and mirrored 
 226° to 270° (161~192) ($5F~$40)

The Player reattaches to the ceiling and Ground Speed is set to Y Speed*-sign(sin(Ground Angle)).

Ceiling: When the ceiling Ground Angle is in the range of

 136° to 225° (97~160) ($9F~$60)

The Player hits his head like with any ceiling, and doesn't reattach to it. Y Speed is set to 0, and X Speed is unaffected.

Air Rotation

When the Player leaves a slope, such as running up and off a quarter pipe, the Players's Ground Angle smoothly returns to 0.

The Player's Ground Angle changes by

 2.8125° (2) ($2)

each frame, in the direction towards 0.


  • Note: Degree angle is approximate, as the original game has angles ranging up to 256. Degree, decimal, and hex have been provided.
  • Note: Regardless of the Player's Ground Angle, their airborne sensors do not rotate. Air collision essentially ignores the Player's mode.