Actions

SPG:Game Objects

From Sonic Retro

Revision as of 10:44, 25 April 2021 by LapperDev (talk | contribs) (Extra info regarding badnik sensors.)

Notes:

  • Research applies to all four of the Mega Drive games, and Sonic CD. If there are any varying differences between the games, this will be covered below.
  • Variables and constants for Sonic and other characters such as X Position and acc will be referenced frequently, they can be found in Basics.
  • An object's actual Width Radius and Height Radius are separate to an object's hitbox width radius and height radius.

Introduction

Objects move in various ways, some simple and some rather complex. It may be enough to simply observe an object to know how it acts, but this isn't the case most of the time where greater depth is required.

Hitboxes

Hitboxes are the game's simplified way of giving an object a size. Each object has it's own size defined with a Width Radius and a Height Radius, and they aren't always obvious. Visual examples will be given for most objects in this guide.

Note: More detailed information about how hitboxes and solid objects work, as well as Sonic's hitbox, can be found at Solid Objects.

Triggers

Sometimes, but rarely, an object will forgo the hitbox system entirely and instead perform it's own custom checks on the Player's position, checking if it is within some kind of rectangle. This serves the same purpose as hitboxes, but is fundamentally different. For one, it happens on the object side while hitboxes are checked at the end of the Player's code. Secondly, a trigger can be a rectangle of any size, without using radius values. So they will be described as having a top left position, and a complete width and complete height. Just a normal rectangle. What you see is what you get with these.

Because these are totally separate and do not involve the Player's hitbox at all, they will be differentiated as "Triggers" or trigger areas.

General Objects

General objects appear in many zones and games and the code should be the same between them.


Rings

SPGRingHitbox.png

Rings have a hitbox with a width radius of 6 and a height radius of 6, resulting in a 13 x 13 rectangle. (while their sprite is larger, at 16px), so Sonic can get quite close to a ring before a collision occurs and he collects it.

Scattered Rings

When a ring is bouncing around, it has a Width Radius of 8 and a Height Radius of 8 resulting in a 17 x 17 rectangle.

Ring Gravity

Rings do not have same gravity constant as Sonic does. Instead, their gravity is a force of 0.09375. So, this value is added to the rings' Y Speed every frame.

Ring Bounce

When the scattered rings hit the ground, their vertical speed is multiplied by a factor of -0.75. This has the effect of reversing their vertical motion, as well as slowing it somewhat. This calculation is performed after the addition of the gravity. Their horizontal speed is unaffected by bouncing.

Rings only check for the floor once every 4 frames, using a sensor at their X Position and Y Position + Height Radius.

Clearly, when the rings bounce off the floor, they do so so imprecisely as on 75% of frames they are not even checking for it. So they sometimes pass well into the ground before deciding to bounce away. This is really not noticed during normal play, and was necessary to avoid too much slowdown.

But there are further limitations on bouncing rings, probably also in place to avoid processor load. They are totally unaffected by walls (they do not cast any wall sensors), and are only concerned with vertical surfaces. These checks also only happen when the ring is moving downwards (Y Speed > 0) thus they can also fly up through ceilings. This can actually become a bother to Sonic if he is struck in a small corridor, as most of his rings are lost in the ceiling and don't fall back down to be regathered. To make things worse, to disperse the processor load, the floor check only happens every 4 frames, offset for each ring, meaning rings will tend to fall through floors entirely.

Ring Lifespan

All scattered rings are destroyed after 256 steps if they have not been regathered. Also, if they leave the horizontal view boundaries, they are destroyed. Again, on a more powerful system, you may choose not to include this feature.

Ring Animations

Fixed rings have 4 frames of animation, and spend 8 steps showing each frame before moving to the next. Scattered rings are more complicated, in that they have a much faster animation speed when they are created (1 frame per 2 steps), but this slows down over their lifespan.

The way you achieve this depends on how you animate your sprites. If you're using animation speed instead of frame duration, your formula is:

    animationSpeed = floor(lifespanTimer * 0.5 / ringLifespan)

If you are using Variable Speed Animation System, your formula is a bit different:

    frameDuration = floor(ringLifespan * 2 / lifespanTimer)

Springs

Red springs propel Sonic at a speed of 16, and yellow springboards at a speed of 10. If the spring faces up or down, the value is either negative or positive, respectively, and Y Speed is set to it. If the spring faces left or right, the value is either negative or positive, respectively, and X Speed is set to it. Vertical springboards don't affect X Speed and likewise horizontal springs don't affect Y Speed.

For the most part Springs are simple solid objects which activate if Sonic touches the correct side.

Horizontal Springs

Much like vertical springs, horizontal springs will activate when you push into them.

However in Sonic 2 (16-bit) onwards, if Sonic is standing on a spring facing right and you slowly step off it and land on the floor nearby (moving right without turning) the spring will activate, even though it is impossible to have pushed into the spring. So something extra is occurring. This happens because if Sonic is not moving towards the spring (so either standing still or moving away), the game checks if his X and Y positions are within a box which surrounds the spring. This box is much larger than the spring itself, spanning vertically from the spring's Y - 24 to the spring's Y + 24 and horizontally from the spring's X to the spring's X + (40 in the spring's direction).

The result of this is you can walk up to a spring, stop, and if you are within 40 pixels of it you will be propelled away. Keeping in mind the normal Width Radius for the solid area of these Springs is 8, this can happen incredibly and noticeably early. This is all in addition to the normal spring activation by touching the actual side of it.

Horizontal springs also only propel sonic while he is grounded.

Control Lock

When Sonic bounces away from a horizontal spring (red or yellow), he cannot brake or otherwise affect his X Speed for 16 steps. The engine achieves this by setting the same horizontal control lock as when sliding back down steep inclines (in S3&K, bytes $32-33 in the player object's status table). Why lock the horizontal controls? The player is likely to be pressing in the direction of the spring as they run into it, and this would cause Sonic to bounce away in his braking animation. Temporarily ignoring input is a quick and elegant solution.

Diagonal Springs

There are no diagonal springs in Sonic the Hedgehog (16-bit). But there are in Sonic 2 (16-bit), 3, K, and CD.

Sonic 2, 3, and K work the same way, but Sonic CD is different.

In Sonic 2, 3, and K, a diagonal spring sets both X Speed and Y Speed to the spring's value, with the appropriate sign. So a red spring facing up and to the right sets Y Speed to -16 and X Speed to 16. The trouble with this method is that Sonic is technically bounced faster diagonally than horizontally or vertically. This is because they didn't bother to calculate the sine functions.

In Sonic CD, they do however. Conveniently, the absolute sine and cosine of a 45 degree angle are the same, so you only need one value. It comes out to 11.3125 for Red springs and 7.0703125 for Yellow ones.

Item Monitors

SPGItemMonitorHitbox.png

Item Monitors have a Width Radius of 15 and a Height Radius of 15, resulting in a 31 x 31 rectangle, this is their solid size you can push against.

The hitbox is 1 pixel larger on every side, with a width radius of 16 and a height radius of 16, resulting in a 33 x 33 rectangle.

The mechanics of breaking an item box can be found in Solid Objects.

When bumped from the bottom, Item monitors are given a Y speed of -1.5. They have a gravity of 0.21875 while falling.

Bumpers

Bumpers such as those in Spring Yard Zone set Sonic's X Speed to 7*cosine(p), and Y Speed to 7*-sine(p), where p is the angle measured from the bumper's centre to Sonic's. This is regardless of Sonic's velocity when he hits the bumper.

SPGBumperHitbox.png

Bumpers have a hitbox with a width radius of 8 and a height radius of 8, resulting in a 17 x 17 rectangle. Other than the hitbox speed repulsion, there is no solidity to bumpers.

Breakable Blocks and Rocks

When Sonic jumps on top of breakable objects, such as the rocks in Hill Top Zone, blocks in Marble Zone, or the tube caps in Chemical Plant Zone, he bounces away with a Y Speed of -3. X Speed is unaffected.

The block produces 4 segments. These segments have a gravity of 0.21875. Their initial x and y speeds are (-2, -2) & (2, -2) for the top two, and (-1, -1) & (1, -1) for the bottom two.

Breaking Walls

In Sonic 1, 2, 3, & K, the character's absolute X Speed must exceed 4.5 in order to break through destructible walls when rolling (except for Knuckles, who busts walls on contact, and doesn't need to be rolled up). X Speed is unaffected by the collision, as well.

However, when Knuckles breaks walls in Sonic 3 & Knuckles, though his X Speed is unaffected, he doesn't move during the frame in which he hits the wall. The same thing is true when Sonic spindashes through a wall in Sonic 3 & Knuckles.

In Sonic CD, the X Speed threshold is removed. Sonic can break through destructible walls by simply jumping near them, or rolling into them at any speed.

Buttons

SPGButtonHitbox.png

Buttons simply act solid but have a Width Radius and Height Radius which is smaller than the button when not depressed. When Sonic is standing on it, the subimage changes to depressed and the switch is activated.

Checkpoints

SPGCheckpointTrigger.png

Checkpoints appear to have a hitbox which will trigger when Sonic's touches is... but it doesn't. The checkpoint does it's own evaluation on Sonic's position to trigger a reaction. This is one of the "triggers" I mentioned at the top of this guide.

The trigger top left is Checkpoint X Position - 18 and Checkpoint Y Position - 64, the trigger size is 16 x 104.

Of course, the Y Position of a checkpoint is not centred on the entire thing, it's more closely centred on the pole, excluding the part at the top. This is why the trigger is larger above the Y Position than below it.



Bridges

The bridges in Sonic 1, 2 and 3 are known for their dynamic movement as Sonic moves over them. Bridges are set up with a controller object and an array of log objects which the controller object creates, though this can just be an array of values to represent the segments in most engines now. The controller object contains a few variables: There's the length (in segments) of the bridge, which is usually 12, but it can be longer; there's the index of the segment Sonic is standing on, which starts at 0 for the leftmost segment and ends at length-1.

Depression Amount

The depression amount is the lowest the bridge can go at any given time. This changes depending on the log Sonic is standing on. To get the current maximum depression amount in pixels the bridge controller uses predetermined values for each log.

The values go up in 2's, starting at 2 and continuing to the middle, with the other side being a mirror of the first half. For example, a bridge with length 5 will have the values 2,4,6,4,2 and a bridge with length 6, the values would be 2,4,6,6,4,2. The bridges commonly found in Sonic (12 segments in length) would have the values 2,4,6,8,10,12,12,10,8,6,4,2.

To get the current maximum depression for the bridge, the game uses the value from the log currently being stood on. We'll call the current value MaxDepression.

Calculating Each Log Depression

The Y Position of the segments in the bridge depend on the log that Sonic is currently standing on, as so:

SPGBridge.png Sonic is on the 5th segment, we'll call this the CurrentSegment and it's value is 5.

In this example, the depressions would look as follows: 2,4,6,8,10,12,12,10,8,6,4,2 So the current MaxDepression for the bridge will be the 5th log's value, which is 10.

To calculate the position of each log, we calculate how far it is from CurrentSegment relative to the edge it's near. We will call this value LogDistance.

 Segment 0 is 1/5 of the way to CurrentSegment, so it's LogDistance is 1/5 or 0.2.
 Segment 1 is 2/5 of the way to CurrentSegment, so it's LogDistance is 2/5 or 0.4. 
 Segment 4 is 5/5 of the way to CurrentSegment, so it's LogDistance is 5/5 or 1. 


Working from the other side, we use the distance from the end to CurrentSegment, rather than from the start.

 Segment 11 is 1/8 of the way to CurrentSegment, so it's LogDistance is 1/8 or 0.125.
 Segment 6 is 6/8 of the way to CurrentSegment, so it's LogDistance is 6/8 or 0.75.


(Since we've already calculated segment 4 from one direction, there's no need to do it from the other).

We then use LogDistance to calculate it's position:

 LogY = BridgeY + MaxDepression * sine(90 * LogDistance).


Some custom code to calculate these automatically may go as follows:

Notes:

  • This assumes first segment index starts at 0 in the loop, but CurrentSegment (the log currently stood on) would start at 1.
  • If Sonic is not on any of the logs (from walking off), the max depression is just 0 so the bridge won't need to run this code. In addition, the logs don't need to update when Sonic jumps off apart from slowly relaxing the bridge.
  • It does not account for any smoothing of the bridge movement, like in Sonic Mania
  • Sine here uses degrees not radians. Because the original game uses 256 angles rather than 360, there may be slight differences with the sine function causing some logs to be a pixel off (never the logs being stood on, mainly the logs towards the sides). It's tiny and unnoticeable, but can be corrected with extra work.
 // get the current segment stood on
 CurrentSegment = floor((Sonic's X position - Bridge's start X) / 16) + 1
 
 // get the current maximum depression for the bridge
 if CurrentSegment <= SegmentAmount / 2
   MaxDepression = CurrentSegment * 2   //working from the left side in
 else 
   MaxDepression = ((SegmentAmount - CurrentSegment) + 1) * 2   // working from the right side in
 // the above can be done upon bridge creation, getting the max depression for all segments and placing them in an array for later use
 
 // loop through all segments and find their y positions
 for (i = 0; i < SegmentAmount; i ++)
 {
   // get difference in position of this log to current log stood on
   difference = abs((i + 1) - CurrentSegment);
   
   // get distance from current log to the closest side, depending if before or after CurrentSegment
   if (i < CurrentSegment) 
     log_distance = 1 - (difference / CurrentSegment) //working from the left side in
   else 
     log_distance = 1 - (difference / ((SegmentAmount - CurrentSegment) + 1))   // working from the right side in
   
   // get y of log using max depression and log distance
   LogY[i] = BridgeY + floor(MaxDepression * sine(90 * log_distance))   //the final y position for the log
 }


Meanwhile, all these depression values are multiplied by the sine of the angle in the controller object that counts to 90 when Sonic is standing on top, and down to 0 when Sonic gets off, so the depression will smoothly increase with time when Sonic jumps on to the bridge, and then smoothly decrease when he leaves it. It takes 16 frames for bridge to return itself to its original position from full tension, resulting in a step of 5.625. As noted above, original uses 256 angles, so the actual angle range in the controller object is 0~64, with step of 4.

End of Level Capsules


Sonic 1 Method

Explosion

For 60 steps, every 8 steps, spawn explosion at capsule position plus random x,y offset (Max horizontal offset of 31 pixels, and according to calculations, vertical is the same). At end of those 60 steps, start with the animals

Animals

Switch to exploded frame. Spawn 8 animals at capsule position -28x, +32y, horizontally separated by 7, with alarms starting from 154 and decreasing by 8 per animal (animals don't jump out until their alarm reaches zero).

For 150 steps, every 8 steps, spawn animal at random X Position amongst the existing animal group (but tighter in, not near edges), with their alarm set to 12.

When all animal objects have disappeared, run "Got Through" message.

Sonic 2 Method

Explosion

An explosion spawns at lock's position, move lock at +8x, -4y. Wait 29 steps.

Animals

8 animals spawn at capsule position -28x, +32y, horizontally separated by 7, with alarms starting from 154 and decreasing by 8 per animal (the animals don't jump out until their alarm reaches zero).

For 180 steps, every 8 steps, an animal will spawn at random X Position amongst the existing animal group (but tighter in, not near edges), with their alarm set to 12.

When all animal objects have disappeared, the game will run the 'Got Through' message.



Sonic 1 Objects


Badniks

Here the hitboxes and movements of enemies will be detailed.

Motobugs

Motobugs move at a speed of 1. Once they touch a wall, they wait for 1 second before starting off in the other direction.

SPGMotobugHitbox.png

Motobugs have a Width Radius of 8 and a Height Radius of 14, resulting in a 17 x 29 rectangle.

They have a hitbox with a width radius of 20 and a height radius of 16, resulting in a 41 x 33 rectangle.

They check for the floor with 1 downwards facing sensor in at it's X Position and Y Position + Height Radius. If this sensor doesn't find floor (and if it is already moving), it will trigger a turn. Motobugs don't check for floor while turning.

Motobugs don't check for walls and will only turn when the floor below them runs out.

Choppers

Choppers have a gravity of 0.09375 and bounce with a speed of -7 at the Y Position where they spawned.

SPGChopperHitbox.png

Choppers have a hitbox with a width radius of 12 and a height radius of 16, resulting in a 25 x 33 rectangle.

Buzz Bombers

Buzz Bombers move at a speed of 4 (or -4).

SPGBuzzBomberHitbox.png

Buzz Bombers have a hitbox with a width radius of 24 and a height radius of 12, resulting in a 49 x 25 rectangle.

Crabmeats

Crabmeats move at a speed of 0.5 (or -0.5) while walking. They will walk for up to 127 frames. When they do turn they simply multiply their speed by -1. When shooting, they will wait 59 frames.

SPGCrabmeatHitbox.png

Crabmeats have a Width Radius of 8 and a Height Radius of 16, resulting in a 17 x 33 rectangle.

They have a hitbox with a width radius of 16 and a height radius of 16, resulting in a 33 x 33 rectangle.

They check for the floor with 1 downwards facing sensor which moves depending on the direction it is walking. It also fluctuates position every frame. Every other frame the sensor is positioned at X Position and Y Position + Height Radius, and on the other frames when walking right the sensor is at it's X Position + 16 and Y Position + Height Radius, and when moving left the sensor is at it's X Position - 16 and Y Position + Height Radius. This means it will never step too far off a cliff before turning, but is also checking under it. You could simply use 2 sensors, but this saves processing each frame.

Projectiles

When shot, Crabmeat's projectiles are given a Y Speed of -4, and an X Speed of either positive or negative 1. They have a gravity of 0.21875.



Caterkillers

Caterkillers are comprised of 4 segments, the head, and 3 body segments. The Head Segment is the only vulnerable part, while the body segments have hitboxes which damage the player (these also trigger the scattering upon being touched, but their main job is to hurt Sonic and they cannot be destroyed like a Badnik normally can). They head will also trigger scattering if not destroyed when touched.

SPGCaterkillerHitBox.png

The head segment has a Width Radius of 8 and a Height Radius of 7, resulting in a 17 x 15 rectangle. The hitboxes of all segments are just a little bit bigger, with a width radius of 8 and a height radius of 8, resulting in a 17 x 17 rectangle.

Only the head segment has a sensor for detecting the floor at it's X Position and Y Position + Height Radius. It is only active when the head moves a pixel.


The way they move is rather complex compared to other enemies. Firstly, let's go over timings.

Caterkillers scrunch up then flatten/stretch out, on a loop. They spend 16 frames moving, then 8 frames staying still. So this would be scrunching up for 16 frames, then not moving for 8, then stretching out for 16, then not moving for 8, and repeat.

Firstly this will go over how they work while on open ground, then what they do to track properly on slopes, then cover what they do when meeting a wall or a ledge.

For easier reference, we will number the segments like so:

SPGCaterkillerSegments.png

Scrunching Up

When starting to scrunch (and if the Cater killer isn't turning at all), each body part should already be spaced 12px apart. So if the Head Segment's X position was 50, the next body segment would have an X position of 62, or 38 if it is facing right, and so on. It's mouth is also set to open.

The Head Segment won't proceed (its X speed is 0), instead this is where the back end catches up with the front end.

Segment 1 will proceed with the head's X speed plus -0.25 (0.25 when the segment is moving right). This results in a movement of 4 pixels within the 16 frames.

Segment 2 will move with Segment 1's X speed plus -0.25 (0.25 when the segment is moving right). This results in a movement of 8 pixels within the 16 frames.

Segment 3 will move with Segment 2's X speed plus -0.25 (0.25 when the segment is moving right). This results in a movement of 12 pixels within the 16 frames.

Both the Head Segment and Segment 2 will animate upwards 7 pixels within the 16 frames. The other segments remain flat to the floor. Animate being the keyword here, the actual position and hitbox do not rise at all.

Stretching Out

When starting to stretch out (and if the Caterkiller isn't turning at all), each body part should already be spaced 8px apart. So if the Head Segment's X position was 50, the next body segment would have an X position of 58, or 42 if it is facing right, and so on. It's mouth is also set to closed.

Stretching out is basically the opposite, where the head moves forward and the back end stays still.

The Head Segment will proceed with an X speed of -0.75 (0.75 when moving right). This results in a movement of 12 pixels within the 16 frames.

Segment 1 will proceed with the head's speed plus 0.25 (-0.25 when the segment is moving right). This results in a movement of 8 pixels within the 16 frames.

Segment 2 will proceed with Segment 1's X speed plus 0.25 (-0.25 when the segment is moving right). This results in a movement of 4 pixels within the 16 frames.

Segment 3 doesn't proceed, it has Segment 2's X speed plus 0.25 (-0.25 when the segment is moving right). This results in 0 X speed.

This time, both the Head Segment and Segment 2 will animate downwards 7 pixels within the 16 frames, back to being flat to the floor.

Animation

As a segment rises, it does so in a particular way.

Across the 16 frames, this is how many pixels the raised segments will be from the ground while scrunching up.

 0, 0, 0, 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 7, 7

This will be reversed as they move back down while stretching out.

In your framework this could be baked into frames of animation or as an extra y offset subtracted from the draw position.

Slopes

The Head Segment sticks to the floor using a downwards sensor much like Sonic does as it moves.

Well, each body part needs to also stick to slopes as they move. This is done by having the Head Segment record and remember all of it's Y offsets in a small array (only on the movement frames) and having the next body part read from this as they move. This saves the game having to read data from tiles for each body segment. This array should be around 16 entries long.

Y Offset Arrays

Note: We will assume that position 0 of an array is the oldest value, while new values are added to the end.

After colliding with the floor, X Speed is added to it's X Position, the Head Segment will check each frame whether it has moved a pixel - this being if it's floored X position after moving does not equal it's floored X position before moving.

If movement has occurred, the current Y offset will be added to it's Y offset array.

The other segments will use this array to reposition themselves. Using Segment 1 as an example, it has an index which it will read from the array, this should be at around 12 back from the most recent value. This is because the segments are 12 pixels away from each other when fully stretched.

When Segment 1 moves a pixel (which occurs at different frames to the Head Segment), it will trim the oldest value from the Head Segment's array (effectively moving 1 Y offset array entry into the future). Then, it will read a value from the Head Segment's array at the index position. If this value is valid, the Y position of the segment will be adjusted according to the read value. After this happens, whatever the value is, Segment 1 adds this value to it's own array for Segment 2 to use in the exact same way.

Segment 2 and Segment 3 work in the exact same way, except Segment 2 will use Segment 1's array, and Segment 3 will use Segment 2's array (also, Segment 3 doesn't need to record any values to it's own array, being the last segment).

The result of this is while the arrays are all added to at the rate of that segment's motion, it's read from at the rate of the next segment's motion. This ensures that each segment will meet the same Y offset value when arriving at a particular X position.

Note: There's a possibility of this de-syncing if the timing of the states aren't perfectly in sync or speeds of the segments aren't perfectly balanced.

Ledges And Walls

When the Caterkiller has to turn, it doesn't suddenly stop or even turn all at once. Each body segment independently changes direction.

On the frames that the Head Segment meets a ledge or touches a wall, instead of recording a Y offset from the ground, a value of 128 is stored in the array. This will signal the next segment to turn around also, when they read it. Segments will not align themselves to the ground if nothing is found below or they have encountered a turning signal. The segment may spend 2 or more frames off the side of a ledge by 1 pixel however since the array only updates upon a pixel of movement, a turn signal isn't recorded multiple times.

So, one by one, the segments will change direction as they encounter this signal in the arrays, and each reach the point of turn.

On the movement frame a segment (including the head) turns, the fractional part of it's X position needs to be flipped. This is to ensure the segments are always perfectly pixel aligned after the 16 frame movement has passed. So, if the Head Segment has been moving left, and is at an X position of 50.75 when it turns, the 0.75 portion of the position is flipped (1-0.75 = 0.25) resulting in an X position of 50.25 afterwards. This happens for any segment and will help keep the segment at the same position within a pixel relative to it's direction, so nothing de-syncs.

Notes:

  • 1 pixel seems to be subtracted from a segment's X position when it turns to face left.
  • The segment will not stop at any point during a turn, and will continue to move in whichever direction it's now facing as if nothing happened.
Scattering

When you touch any part of the Caterkiller (unless in doing so you destroy it's head), it will break apart and each segment will bounce away.

Segment Scatter Speed

Upon scattering, each segment first is given its own X speed. Here, starting at the Head Segment and ending with Segment 3.

2, 1.5, -1.5, -2

This speed is negated if the segment is facing to the right. On this frame, their Y speed is set to -4

These will fall with a gravity of (0.21875), and upon contact with the floor their Y speed is set to -4 each time as a bounce.


Green Hill

S Tunnels

The S Tunnels in Green Hill Zone simply keep Sonic rolling at all times. If his speed reaches 0 and he stands up, the game acts as if you have pressed down and he rolls again instantly. Since the S tunnels have no flat ground, Sonic will always roll down it and should never just crouch. However, as part of the function making Sonic roll, if his gsp does happen to be 0, it will set his gsp to 2.

Marble

Pushable Blocks

Pushable blocks move 1 pixel at a time while being pushed (the mechanics of which can be found in Solid Objects). They are also constantly checking below themselves to ensure there is floor nearby. If there is no floor directly below their centre when they get pushed, they will change their behaviour. To avoid falling too soon and clipping the corner, they will begin to move at a speed of 4 in the direction of the push until they have moved 16 pixels. At this point they are completely over the ledge that they originally detected. They will then proceed to fall and land as normal.

Spike Traps

When Marble Zone Spike traps fall, their Y Speed increases by 0.4375 each frame. When they reach full length, they spend about 60 frames there. After this they begin to rise by 0.5px per frame, or 1 pixel every 2 frames. The length they can fall varies.

SPGSpikeTrapHitbox.png

They have a solid box at the top (which Sonic can walk on & push against) however the spike area is a damage hit box which will simply hurt Sonic upon contact but doesn't have solidity.

Scrap Brain

Conveyor Belts

A Scrap Brain Zone conveyor belt will simply add the belt speed to Sonic's X Position, Sonic's speeds are unaffected.

Sonic 2 Objects

Chemical Plant

Spring Ramps

Spring ramps aren't quite as simple as normal springs. Firstly, they have a specific region where they actuate.

SPGSpringRampActuationRegion.png

The ramp will activate if his X Position is within the green region as he stands on it.

When a Spring ramp activates they don't bounce Sonic instantly, instead, Sonic moves down a bit as the animation plays. There are 2 subimages, normal and down, and these both have different collision height arrays as shown below.

SPGSpringRampSolidty.png

On the left is how the solidity appears in-game, on the right is the height array as it is stored, it simply gets scaled by 2 horizontally. How slope data is used for solid objects is detailed in Sloped Objects.

Once activated it plays the down subimage for 4 frames, and Sonic will lower with it but is otherwise unaffected and will keep walking. On the next frame it's back up and Sonic is raised again but still unaffected, on the frame after this Sonic will actually be in the air.

So how fast do they bounce Sonic? Well, that's not perfectly simple either. It will bounce Sonic up with a Y Speed of -4, and depending on Sonic's X Position position along the ramp it will subtract a second modifier from his Y Speed. This is all dependant on the positions where Sonic's X Position is right now as he is bounced, not where he was when activated it.

SPGSpringRampPowerSteps.png

From left to right this modifier can be 0, 1, 2, 3 or 4.

So if Sonic happened to be in section 3, his Y Speed would become -4, minus the modifier of 2, resulting in -6.

His X Speed is also affected, if it's absolute value happens to be larger than or equal to 4, the modifier will be added to (or subtracted from) X Speed. If Sonic is in section 3, and he has a speed of 5, his speed would become 5+2. This gets capped at 6 in Sonic 2 due to the speed cap still being present in the air.

Spring Caps

The red spring caps that cover the tubes in Chemical Plant Zone work like springboards, but are slightly stronger than a Yellow springboard. They set Sonic's Y Speed to -10.5 upon collision.

Spinners

The black spinners that impel you forward in Chemical Plant Zone set X Speed to 16. They don't seem to slow you down if you're already moving faster than that, though.

Hill Top

Ski Lifts

The ski lifts in Hill Top Zone move with an X Speed of 2, and a Y Speed of 1.

Sonic 3 Objects

Carnival Night

Balloons

The balloons in Carnival Night Zone set Y Speed to -7 when Sonic collides with them, no matter what his angle of collision. X Speed is not affected.

SPGBalloonHitbox.png

Balloons have a hitbox with a Width Radius of 8 and a Height Radius of 8, resulting in a 17 x 17 rectangle.

Cannons

The cannons in Carnival Night Zone set Sonic's X Speed to 16*cosine(p), and Y Speed to 16*-sine(p), where p is the angle of the cannon.

Sonic and Knuckles Objects

Mushroom Hill

Mushrooms

The mushrooms in Mushroom Hill Zone work just like springboards, only each successive bounce is higher than the last, up to three bounces. The first bounce sets Y Speed to -6.5, the second, -7.5, and the third, -8.5.

Points

When you hit a Badnik or other point-bearing item (such as Bumpers), a small score notification will fly up out of it. After it spawns at the object's X and Y Position, it begins with a Y Speed of -3, and will slow down by 0.09375 each frame. Once it is no longer moving, it will vanish. This will take around 32 frames.