Fulbo
Member
Hi everyone!
So I'm working on a project to create a small Sonic engine, based on the guide written here: https://info.sonicretro.org/Sonic_Physics_Guide
I've run into a bug (one they said I would) within the Solid Tiles section, particular the 'Slopes & Curves' part. I'm using tiles for my terrain, height masks to calculate collision, and bbox_bottom to actually collide.
Similar in the tutorial, I check the left, right & middle corners of bbox_bottom to determine if I'd collide with a tile, and if so, snap them to the top of it. However, there are instances where none of them connect with the tile I'm currently on, so they just fall into the one below, as shown here:
- Middle connects, ergo collision. - None connects.
I'm wondering if I need to instead check every pixel of bbox_bottom, and see if any of them connect to a tile. Or, is there another method I could use to handle this issue?
My code is based off on Shaun Spaulding's (top lad) tutorial on Tilemap Slope Collisions, found here:
Anyways, here's what my project contains:
Player
I apologize if this is a bit hard/much to read for others. If it is, I'll fix it up later.
Anyways, if you have any suggestions, I'd be very grateful to hear them out.
So I'm working on a project to create a small Sonic engine, based on the guide written here: https://info.sonicretro.org/Sonic_Physics_Guide
I've run into a bug (one they said I would) within the Solid Tiles section, particular the 'Slopes & Curves' part. I'm using tiles for my terrain, height masks to calculate collision, and bbox_bottom to actually collide.
Similar in the tutorial, I check the left, right & middle corners of bbox_bottom to determine if I'd collide with a tile, and if so, snap them to the top of it. However, there are instances where none of them connect with the tile I'm currently on, so they just fall into the one below, as shown here:
- Middle connects, ergo collision. - None connects.
I'm wondering if I need to instead check every pixel of bbox_bottom, and see if any of them connect to a tile. Or, is there another method I could use to handle this issue?
My code is based off on Shaun Spaulding's (top lad) tutorial on Tilemap Slope Collisions, found here:
Anyways, here's what my project contains:
Player
Code:
Create Event:
// Collisions
tilemap = layer_tilemap_get_id("Collisions");
// Movement
xMove = 0;
yMove = 0;
yMove_Frac = 0;
//Constants
grv = 1;
horSpeed = 4;
jmp = 6;
Code:
Step Event:
// Current Positions Before Movement
var oldBBotLeft = (scr_inFloor(tilemap, bbox_left, bbox_bottom + 1) >= 0);
var oldBBot = (scr_inFloor(tilemap, x, bbox_bottom + 1) >= 0);
var oldBBotRight = (scr_inFloor(tilemap, bbox_right, bbox_bottom + 1) >= 0);
// Movement
xMove = (keyboard_check(vk_right) - keyboard_check(vk_left)) * horSpeed;
// Collision Hor
var bbox_side;
if (xMove > 0) bbox_side = bbox_right; else bbox_side = bbox_left;
var p1 = tilemap_get_at_pixel(tilemap, bbox_side + xMove, bbox_top);
var p2 = tilemap_get_at_pixel(tilemap, bbox_side + xMove, bbox_bottom);
// If middle centre is in a solid tile...
if (tilemap_get_at_pixel(tilemap, x, bbox_bottom) > 1) p2 = 0; // Ignore bottom side tiles if on a slope
// Actually Collide
if (p1 == 1 || p2 == 1) { // Don't set check to 'p != 0', otherwise you won't be able to climb up slopes
if (xMove > 0) { x = x - (x mod TILE_SIZE) + (TILE_SIZE - 1) - (bbox_right - x) }
else { x = x - (x mod TILE_SIZE) - (bbox_left - x); }
xMove = 0;
}
// Move X
x += xMove;
// BBox_Bottom Position Recordings
var curBBotLeft = (scr_inFloor(tilemap, bbox_left, bbox_bottom + 1) >= 0);
var curBBot = (scr_inFloor(tilemap, x, bbox_bottom + 1) >= 0);
var curBBotRight = (scr_inFloor(tilemap, bbox_right, bbox_bottom + 1) >= 0);
// Jump
if (curBBotLeft || curBBot || curBBotRight) {
// Jump
if (keyboard_check_pressed(ord("Z"))) { yMove = -jmp; }
} else { // If in air...
// Gravity
if (yMove < 6) { yMove += grv;} // Increase Gravity
else if (yMove > 6) { yMove = 6; } // Terminal Velocity
}
// Store Fractions
var nYMove = yMove;
nYMove += yMove_Frac;
// Convert Decimal to Integer With Fractions
yMove_Frac = nYMove - (floor(abs(nYMove)) * sign(nYMove));
nYMove -= yMove_Frac;
// Collision Vert
var nextBBotLeft = tilemap_get_at_pixel(tilemap, bbox_left, bbox_bottom + nYMove);
var nextBBot = tilemap_get_at_pixel(tilemap, x, bbox_bottom + nYMove);
var nextBBotRight = tilemap_get_at_pixel(tilemap, bbox_right, bbox_bottom + nYMove);
// Prepare for Slope Collision
var floorOffset; floorOffset[0] = scr_inFloor(tilemap, bbox_left, bbox_bottom + nYMove); // Bottom Left
floorOffset[1] = scr_inFloor(tilemap, x, bbox_bottom + nYMove); // Bottom
floorOffset[2] = scr_inFloor(tilemap, bbox_right, bbox_bottom + nYMove); // Bottom Right
// Determine What BBox_Bottom Corner is Closest to a Floor
var leftCloser = (floorOffset[0] >= floorOffset[2] && floorOffset[0] >= floorOffset[1]);
var middleCloser = (floorOffset[1] >= floorOffset[0] && floorOffset[1] >= floorOffset[2]);
var rightCloser = (floorOffset[2] >= floorOffset[0] && floorOffset[2] >= floorOffset[1]);
if ((nextBBot != 0 || nextBBotLeft != 0 || nextBBotRight != 0)) { // If you'll collide into a tile...
/// Move Up Along Slopes
if (floorOffset[0] >= 0 || floorOffset[1] >= 0 || floorOffset[2] >= 0) { // If you'll collide into a height mask/pixel...
// Snap to the top of the height mask
// Bottom Left
if (floorOffset[0] >= 0 && leftCloser) { // If bottom left colliding, && offset higher than bottom right...
y -= (floorOffset[0] + 1);
// If you're inside a tile...
while (scr_inFloor(tilemap, bbox_left, bbox_bottom + yMove) >= 0) { // + yMove assures this works.
y--; } }
// Bottom
else if (floorOffset[1] >= 0 && middleCloser) { // If bottom right colliding, && offset higher than bottom left..
y -= (floorOffset[1] + 1); // floorOffset[1] = -1; }
// If you're inside a tile...
while (scr_inFloor(tilemap, x, bbox_bottom + yMove) >= 0) { // + yMove assures this works.
y--; } }
// Bottom Right
else if (floorOffset[2] >= 0 && rightCloser) { // If bottom right colliding, && offset higher than bottom left..
y -= (floorOffset[2] + 1); // floorOffset[1] = -1; }
// If you're inside a tile...
while (scr_inFloor(tilemap, bbox_right, bbox_bottom + yMove) >= 0) { // + yMove assures this works.
y--; } }
yMove = 0;
inAir = false;
}
}
// Move Y
y += nYMove;
// Move Down Along Slopes
var yLen = 9; // The max distance from a tile you can be before you snap to it.
// Check if you were on a tile in the last frame, and are currently airborne.
if ((oldBBotLeft || oldBBotRight) && yMove > 0) {
var bBotLeftLen = (scr_inFloor(tilemap, bbox_left, bbox_bottom + yLen) >= 0);
var bBotLen = (scr_inFloor(tilemap, x, bbox_bottom + yLen) >= 0);
var bBotRightLen = (scr_inFloor(tilemap, bbox_right, bbox_bottom + yLen) >= 0);
if (bBotLeftLen || bBotLen || bBotRightLen) {
if (bBotLeftLen && leftCloser) { y += abs(floorOffset[0]) - 1; }
else if (bBotRightLen && rightCloser) { y += abs(floorOffset[2]) - 1; }
}
}
Anyways, if you have any suggestions, I'd be very grateful to hear them out.