Legacy GM I'm having some difficulty with the code for collision with moving platforms.

I

Ian Kottra

Guest
Hello, I am a novice aspiring game designer currently learning the ins and outs of Game Maker 1.4,

I have decided to start off with a basic 2D platformer along the lines of Super Mario World. One of the things that I'd ultimately like to accomplish is having some kind of universal collision system that allows for level mechanics like the ones in the videos below to be implemented.

(0:56)
(12:11)

Here is the code I am currently using for collision with stationary objects:

if(place_meeting(x+hspd, y, obj_platform) || place_meeting(x+hspd, y, obj_solidHazard)) {
while(!place_meeting(x+sign(hspd), y, obj_platform) &&

place_meeting(x+sign(hspd), y, obj_solidHazard)){
x += sign(hspd);

// While player is not up against wall, move towards wall.
}
hspd = 0;
}

// Move Player Horizontally: Left or right a certain number of pixels per step.
x += hspd;

//Vertical Collision
if(place_meeting(x, y+vspd, obj_platform) || place_meeting(x, y+vspd, obj_solidHazard)){
while(!place_meeting(x, y+sign(vspd), obj_platform) && !place_meeting(x,

y+sign(vspd), obj_solidHazard)) {
y += sign(vspd);
}
vspd = 0;
}
// Move Player Vertically: Up or down a certain number of pixels per step.
y += vspd;


Generally, it works just fine. The while loop keeps the player object from clipping into child objects of obj_platform and obj_solidHazard, assuming that they don't move at all. If an object is moving, then what happens is that either the player object gets stuck in place as the object passes through it, or the game crashes, presumably as a result of an infinite loop. I am satisfied with my basic platforming movement, which is based on hspd increasing and decreasing depending on the arrow keys being pressed and held and vspd increasing and decreasing based on the space key being pressed and held.

If anyone has managed to pull off what I am hoping to, then I would greatly appreciate some tips.
 

sp202

Member
I'm having trouble understanding what exactly the special case is. Is the moving platform moving into the player? Or is the player on top of the platform and colliding with another wall?
 

Ting_Thing

Member
Moving platform have been a pain for me, you're definitely not alone.

If an object is moving, then what happens is that either the player object gets stuck in place as the object passes through it
Personally, I've always made my moving platform jump-through. This would prevent your character from getting stuck or trapped.

or the game crashes, presumably as a result of an infinite loop.
You can run GMS in debug mode, and you will still be able to pause the game to look at your code even if the game is stuck in an infinite loop. That should help you discover exactly what is going on.

Basically moving platforms require an extra layer of movement code to be added on addition to your standard moving code. You would check that the character is standing on the moving platform, and then add the hspeed and vspeed of the moving platform onto the character. The trick is getting the platform and the character perfectly in sync to prevent glitches. You may also want to make sure that the platform doesn't move the character into the wall, ceiling, or floor that the character would get stuck.

Good luck!
 
I

Ian Kottra

Guest
I'm having trouble understanding what exactly the special case is. Is the moving platform moving into the player? Or is the player on top of the platform and colliding with another wall?
It's the former. I've kept the moving platforms I've had my player object interact with away from walls and have been simply jumping into them from the side. With my current code, this event results in the player object freezing in midair and the platform passing through them. In a different iteration of this code that I scrapped, the game froze as soon as the player and platform came in contact with each other.

Personally, I've always made my moving platform jump-through. This would prevent your character from getting stuck or trapped.!
I more-or-less understand how jump-through platforms work from YouTube tutorials, but what I have more of an interest in is creating shifting environments alone the lines of the ones in Super Mario World. Stuff where the player can be pushed horizontally by moving walls. I'd also like to implement rotating platforms (after I implement slopes, that it).
 

SQGTDev

Member
It's the former. I've kept the moving platforms I've had my player object interact with away from walls and have been simply jumping into them from the side. With my current code, this event results in the player object freezing in midair and the platform passing through them. In a different iteration of this code that I scrapped, the game froze as soon as the player and platform came in contact with each other.


I more-or-less understand how jump-through platforms work from YouTube tutorials, but what I have more of an interest in is creating shifting environments alone the lines of the ones in Super Mario World. Stuff where the player can be pushed horizontally by moving walls. I'd also like to implement rotating platforms (after I implement slopes, that it).
The collisions in Super Mario World and New Super Mario Bros. rely on five invisible lines: one for the player's left, right, top, bottom and a slope line (at the center position of the bottom line) that is usually a single pixel wide. You would use the floor line to react with the edges of platforms, and the slope line to react with slopes.
Instead of using place_meeting, use collision_lines to detect obstacles. Not only does this run much faster than using place_meeting, but it gives you more control over how you react to the walls and ground and such. You can crush the player by detecting if both wall sensors are triggered, or if both the floor and ceiling sensors are triggered.
For moving platforms, move the platforms in their Begin Step events, and move the player in the Step event. Get the platform's ID and move the player based on the platform's x - xprevious and y - yprevious. This is all you have to do, since the player will automatically handle walls pushing them around thanks to collision_line while loops for the left/right sensors.
Another thing, Semi-Solid Platforms (that's what Mario Maker calls jump through platforms) snap you on top if you jump close to the top of them but you're half a block away. This makes jumping on them easier as well as being unable to glitch through them and fall down. This can be accomplished by another while loop that pushes the player up when they detect a Semi Solid Platform around 8 or 16 pixels at most above their Floor/Slope sensors.
 
I

Ian Kottra

Guest
The collisions in Super Mario World and New Super Mario Bros. rely on five invisible lines: one for the player's left, right, top, bottom and a slope line (at the center position of the bottom line) that is usually a single pixel wide. You would use the floor line to react with the edges of platforms, and the slope line to react with slopes.
Instead of using place_meeting, use collision_lines to detect obstacles. Not only does this run much faster than using place_meeting, but it gives you more control over how you react to the walls and ground and such. You can crush the player by detecting if both wall sensors are triggered, or if both the floor and ceiling sensors are triggered.
For moving platforms, move the platforms in their Begin Step events, and move the player in the Step event. Get the platform's ID and move the player based on the platform's x - xprevious and y - yprevious. This is all you have to do, since the player will automatically handle walls pushing them around thanks to collision_line while loops for the left/right sensors.
Another thing, Semi-Solid Platforms (that's what Mario Maker calls jump through platforms) snap you on top if you jump close to the top of them but you're half a block away. This makes jumping on them easier as well as being unable to glitch through them and fall down. This can be accomplished by another while loop that pushes the player up when they detect a Semi Solid Platform around 8 or 16 pixels at most above their Floor/Slope sensors.
Huh, I didn't know about this at all. I'll have to try this out to see how well I can make it work.

I really appreciate the advice!
 
I

Ian Kottra

Guest
Quick update: I've been able to recreate the same collision with stationary objects using collision_line with the following code:

//Collision Left
if(collision_line(bbox_left + hspd, bbox_top, bbox_left + hspd, bbox_bottom, obj_platform, false, true)) {
while(!collision_line(bbox_left + sign(hspd), bbox_top, bbox_left + sign(hspd), bbox_bottom, obj_platform, false, true)) {
x += hspd/16;
}
hspd = 0;
}
// Collision Right
if(collision_line(bbox_right + hspd + .5, bbox_top, bbox_right + .5 + hspd, bbox_bottom, obj_platform, false, true)) {
while(!collision_line(bbox_right + sign(hspd), bbox_top, bbox_right + sign(hspd), bbox_bottom, obj_platform, false, true)) {
x += hspd/16;
}
hspd = 0;
}

// Move Player Horizontally: Left or right a certain number of pixels per step.
x += hspd;

//Collision Top
if(collision_line(bbox_left, bbox_top + vspd, bbox_right, bbox_top + vspd, obj_platform, false, true)) {
while(!collision_line(bbox_left, bbox_top + sign(vspd), bbox_right, bbox_top + sign(vspd), obj_platform, false, true)) {
y += sign(vspd);
}
vspd = 0;
}
// Collision Bottom
if(collision_line(bbox_left, bbox_bottom + vspd, bbox_right, bbox_bottom + vspd, obj_platform, false, true)) {
while(!collision_line(bbox_left, bbox_bottom + sign(vspd), bbox_right, bbox_bottom + sign(vspd), obj_platform, false, true)) {
y += sign(vspd);
}
vspd = 0;
}
// Move Player Vertically: Up or down a certain number of pixels per step.
y += vspd;

I'll keep working on this to see what I can do with moving platforms.

EDIT: Actually, I ended up having problems with collisions on only the right side of the player object. A was able to resolve the issues with some minor edits to the code.
 
Last edited by a moderator:
I

Ian Kottra

Guest
Alright, I managed to make moving platforms push my player object around using the following code.

//Collision Left
if(collision_line(bbox_left + hspd_final, bbox_top, bbox_left + hspd_final, bbox_bottom, obj_platform, false, true)) {
var platLeft = collision_line(bbox_left + hspd_final, bbox_top, bbox_left + hspd_final, bbox_bottom, obj_platform, false, true);
while(!collision_line(bbox_left - 1, bbox_top, bbox_left - 1, bbox_bottom, obj_platform, false, true)) {
x += hspd_final/16; // While player object is not up against wall, move towards wall.
}
x += platLeft.x - platLeft.xprevious;
hspd_final = 0;
}
// Collision Right
if(collision_line(bbox_right + hspd_final + .5, bbox_top, bbox_right + hspd_final + .5, bbox_bottom, obj_platform, false, true)) {
var platRight = collision_line(bbox_right + hspd_final + .5, bbox_top, bbox_right + hspd_final + .5, bbox_bottom, obj_platform, false, true);
while(!collision_line(bbox_right + 1, bbox_top, bbox_right + 1, bbox_bottom, obj_platform, false, true)) {
x += hspd_final/16; // While player object is not up against wall, move towards wall.
}
x += platRight.x - platRight.xprevious;
hspd_final = 0;
}

// Move Player Horizontally: Left or right a certain number of pixels per step.
x += hspd_final;

//Collision Top
if(collision_line(bbox_left, bbox_top + vspd, bbox_right, bbox_top + vspd, obj_platform, false, true)) {
var platAbove = collision_line(bbox_left, bbox_top + vspd, bbox_right, bbox_top + vspd, obj_platform, false, true);
while(!collision_line(bbox_left, bbox_top + sign(vspd), bbox_right, bbox_top + sign(vspd), obj_platform, false, true)) {
y += sign(vspd);
}
y += platAbove.y - platAbove.yprevious;
vspd = 0;
}
// Collision Bottom
var platBelow = collision_line(bbox_left, bbox_bottom + vspd, bbox_right, bbox_bottom + vspd, obj_platform, false, true);
if(collision_line(bbox_left, bbox_bottom + vspd, bbox_right, bbox_bottom + vspd, obj_platform, false, true)) {
while(!collision_line(bbox_left, bbox_bottom + sign(vspd), bbox_right, bbox_bottom + sign(vspd), obj_platform, false, true)) {
y += sign(vspd);
}
y += platBelow.y - platBelow.yprevious;
vspd = 0;
}
// Move Player Vertically: Up or down a certain number of pixels per step.
y += vspd;


However, one issue that has occurred is that the player object appears to clip through vertically moving platforms when positioned on top of them and the platform is moving upwards (but not downwards). So I can't move at all. If anyone has any idea of why this might be occurring, I would appreciate the assistance.

Note that I'm using the following code for straight moving platforms:

Angle += AngleIncrement;

posX = cos(Angle) * AngleMultiplierX;
posY = cos(Angle) * AngleMultiplierY

x += posX;
y += posY

Changing the value of AngleMultiplierX and AngleMultiplierY allows me to determine whether the platform moves horizontally, vertically, or diagonally.


 
Top