• Hey! Guest! The 39th GMC Jam will take place between November 26th, 12:00 UTC and November 30th, 12:00 UTC. Why not join in! Click here to find out more!

[Solved]Help with pushing puzzle

rawket

Member
So I have two log objects, one vertical and one horizontal. I have made them able to roll based on their orientation but I want to make it so that pushing from the end allows you to slide them but only if they are fully on a certain type of object and there is room on that object for them to slide. Their aligned on a 16x16 grid. So for example (G means grass(grass isn't an object just a lack of the slideable object), S means slideable surface) SSSS a log could slide across this if the log was three squares long but couldn't slide across this SGSS and in the first example it couldn't slide across it if the log was 4 squares long because there isn't room. I can figure out how to push the log but I cant figure out how to make the log tell if it is fully on the slideable object and if it has room to move. I want to make a variable that when true, you can slide the log, and when false you cannot. And in order for it to be true each 16x16 square must be occupied by the slideable object under the log plus an extra 16 pixels of length to the slideablle object to give room for the log to slide.

The image I've attached should show the cases for which the log can or cannot move the brown rectangles are the slideablle surface object and the log is labelled, it's the sectioned black rectangle. In the top left, it can't move because there is no slideable object. Top right can't slide because the log isn't fully on slideable objects. Bottom left because there isn't any slideable surface beyond either end to give it room. And in the bottom right it can slide because the log is totally on a slideable surface object and there is room beyond one end. Also the slideable surface objects are merely for function, they do not move only the log moves. And the surface objects will be invisible. If there is a way to do this that's what I'm trying to do or maybe there is a better way?

Here is the code for one of those logs, specifically the horizontal one. The vertical one is pretty much identical just with variables swapped out to make it work vertically rather than horizontally.

Create Event:----------------------------------------------------------------------
logLen = ((bbox_right - bbox_left) / 16) - 1;
rolling = 0;
img = 0;
hsp = 0;
vsp = 0;
moved = 0;

Step Event:----------------------------------------------------------------------
depth = -y;
if rolling == 0
{
if (abs(bbox_top - obj_player.y) <= 1) || (abs(obj_pllayer.y - 9 - bbox_bottom) <= 1)
{
alarm[0] = 10;
rolling = 1;
}
}else if rolling == 2
{
if (moved < 16) && (vsp != 0)
{
moved++;

}
else
{
moved = 0;
vsp = 0;
rolling = 0;
}
scr_moveAndCollide();
if vsp > 0
{
if (img >6) img = 0;
img += 0.5;
}
else if vsp < 0
{
img -= 0.5;
if (img < 0) img = 6;
}
}

Draw Event:-------------------------------------------
draw_set_alpha(0.25);
draw_set_color(c_black);
draw_rectangle(bbox_left + 1, y - 1, bbox_right - 1, y + 4, 0);
draw_rectangle(bbox_left, y - 1, bbox_right, y + 3, 0);
draw_set_alpha(1);
draw_set_color(c_white);
for(i = 1; i < logLen; i++)
{
draw_sprite(spr_logMid_rollV, img, x + (i * 16) - 1, y);
}
draw_sprite(spr_logLeft_rollV, img, x, y);
for(i = 1; i < logLen; i++)
{
draw_sprite(spr_logMid_rollV, img, x + (i * 16), y);
}
draw_sprite(spr_logRight_rollV, img, x + 1 + logLen * 16, y);

Allarm 0:-----------------------------------------------------
rolling = 2;
if (abs(bbox_top - obj_player.y) <= 1) && (obj_player.key_down) && (!obj_player.key_left) && (!obj_player.key_right) && (obj_player.x > bbox_left) && (obj_player.x < bbox_right)
{
vsp = -1;
}
if (obj_player.y > y) && (obj_player.key_up) && (!obj_player.key_left) && (!obj_player.key_right) && (obj_player.x > bbox_left) && (obj_player.x < bbox_right)
{
vsp = 1;
}
 

Attachments

Last edited:

TheouAegis

Member
You need a for-loop to check every 16 pixels along the log. As soon as you detect an unslideable surface, break the loop. If you checked the entire length and there were no issues, move the log.

You should post your working code also so we can see how your code is structured.
 

rawket

Member
You need a for-loop to check every 16 pixels along the log. As soon as you detect an unslideable surface, break the loop. If you checked the entire length and there were no issues, move the log.

You should post your working code also so we can see how your code is structured.
I figured I'd need a for loop, main question I guess is, is there a function that would check if an objects bouding box is over a point so i can check every 16 pixels in the loop if a certain object is over that point?

And good point I'll edit the original with the code of one of the logs
 

TheouAegis

Member
If you have a vertical log, check x+16*sign(hspeed),y+i (where i is 0 to log length incremented 16 pixels). Do that when you start to push. If you want to check on every step (not necessary, but to each their own), then if the origin is centered you can check x+9. If not centered, you can do (bbox_right+bbox_left>>1)+9.
 

rawket

Member
If you have a vertical log, check x+16*sign(hspeed),y+i (where i is 0 to log length incremented 16 pixels). Do that when you start to push. If you want to check on every step (not necessary, but to each their own), then if the origin is centered you can check x+9. If not centered, you can do (bbox_right+bbox_left>>1)+9.
The main issue is I'm not sure how to check if that coordinate is inside the bounding box the slide surface object, I know how to get the coordinates of where to check but how to check if that coordinate has the slide object over it as well as the log is the issue. like is there a function like object_overlapping_point(obj_slide, x, y)? for for every run through the loop it does that function and if at any time it returns false it makes it not slideable. The idea here is to make it so that the log will roll whenever unobstructed but only be able to slide if fully on top of the slide object. I thought about checking if the log was inside the bounding box of the slide surface but then the only way I could think to wright it would be something like this

canSlide = true;
for(i = 0; i < loglen; i++)
{
if !((x + (16 * i) < obj_slide.bbox_right) && (x + (16 * i) > obj_slide.bbox_left) && (y < obj_slide.bbox_bottom) && (y > obj_slide.bbox_top))
{
canSlide = false;
}
}

Problem here is that I could make an entire circle around a log out of slide surface blocks, none of which come in contact with the log and the log would still register as being able to slide.
 
Last edited:
If you want to check the parent colliding object to see if it already has a different object inside of it, why not just set a global variable. So when the slide object goes over, set a global flag so that we can use that to check against. Then in your other object that is also colliding you can just check if that flag is set or not.... No?
 

rawket

Member
If you want to check the parent colliding object to see if it already has a different object inside of it, why not just set a global variable. So when the slide object goes over, set a global flag so that we can use that to check against. Then in your other object that is also colliding you can just check if that flag is set or not.... No?
Um not sure I understand, Imma make an image to explain better. The slide object can't move. This should show the cases for which the log can or cannot move the brown rectangles are the slideablle surface object and the log is labelled, it's the sectioned black rectangle. In the top left, it can't move because there is no slideable object. Top right can't slide because the log isn't fully on slideable objects. Bottom left because there isn't any slideable surface beyond either end to give it room. And in the bottom right it can slide because the log is totally on a slideable surface object and there is room beyond one end. Also the slideable surface objects are merely for function, they do not move only the log moves. And the surface objects will be invisible. If there is a way to do this that's what I'm trying to do or maybe there is a better way?
 

Attachments

TheouAegis

Member
Um not sure I understand, Imma make an image to explain better. The slide object can't move. This should show the cases for which the log can or cannot move the brown rectangles are the slideablle surface object and the log is labelled, it's the sectioned black rectangle. In the top left, it can't move because there is no slideable object. Top right can't slide because the log isn't fully on slideable objects. Bottom left because there isn't any slideable surface beyond either end to give it room. And in the bottom right it can slide because the log is totally on a slideable surface object and there is room beyond one end. Also the slideable surface objects are merely for function, they do not move only the log moves. And the surface objects will be invisible. If there is a way to do this that's what I'm trying to do or maybe there is a better way?
So does it need a slippery surface completely under it AND to the side in order to slide, or just a slippery surface to the side, or a slippery surface to the side and at least one adjacent slippery surface under it? By the looks of it, you'd only need a for-loop to check for obstacles while rolling (e.g., if the player pushed up or down on the log, check for obstacles every 16 pixels) along the log. But if the player is trying to scoot the log over (in this case, from left-to-right or right-to-left), then you don't need a for-loop. If the log is to the right of the player, check if there is a slippery surface at bbox_right+1; if the log is to the left, check for a slippery surface at bbox_left-1. If you require an adjacent slippery surface, check if there's one at bbox_right or bbox_left.

If you do need the log to be completely on a slippery surface, then you'll need a for-loop. What I would do is just find the horizontal and vertical midpoints, calculate the length and width of the log, check if the log is oriented horizontally (log_width > log_height) or vertically (log_height > log_width), then check if the player is pushing in a direction that would make the log roll or if the player is pushing in a direction to make it slide; if making it slide, loop through the log segments from bbox_left+i or from bbox_top+i (depending on orientation), breaking the loop if a segment is not on a slipper surface; then check if the loop was not broken prematurely (e.g., if i==log_width) and then check from which side the player is pushing from, then check for a slippery tile in the direction the player is pushing -- if the player is pushing right, check at (bbox_right+1,ymid); if the player is pushing left, check at (bbox_left-1,ymid); if the player is pushing down, check (xmid,bbox_bottom+1); if the player is pushing up, check (xmid, bbox_top-1).
 

rawket

Member
So does it need a slippery surface completely under it AND to the side in order to slide, or just a slippery surface to the side, or a slippery surface to the side and at least one adjacent slippery surface under it? By the looks of it, you'd only need a for-loop to check for obstacles while rolling (e.g., if the player pushed up or down on the log, check for obstacles every 16 pixels) along the log. But if the player is trying to scoot the log over (in this case, from left-to-right or right-to-left), then you don't need a for-loop. If the log is to the right of the player, check if there is a slippery surface at bbox_right+1; if the log is to the left, check for a slippery surface at bbox_left-1. If you require an adjacent slippery surface, check if there's one at bbox_right or bbox_left.

If you do need the log to be completely on a slippery surface, then you'll need a for-loop. What I would do is just find the horizontal and vertical midpoints, calculate the length and width of the log, check if the log is oriented horizontally (log_width > log_height) or vertically (log_height > log_width), then check if the player is pushing in a direction that would make the log roll or if the player is pushing in a direction to make it slide; if making it slide, loop through the log segments from bbox_left+i or from bbox_top+i (depending on orientation), breaking the loop if a segment is not on a slipper surface; then check if the loop was not broken prematurely (e.g., if i==log_width) and then check from which side the player is pushing from, then check for a slippery tile in the direction the player is pushing -- if the player is pushing right, check at (bbox_right+1,ymid); if the player is pushing left, check at (bbox_left-1,ymid); if the player is pushing down, check (xmid,bbox_bottom+1); if the player is pushing up, check (xmid, bbox_top-1).
The log has to have a slip surface fully underneath and at least one square on either side in order to slide. I have the log rolling totally working, the sliding is the only thing left to get working and in fact I can make it slideable right now if I want but the only issue is making it ONLY slideable in the condition just stated. And the thing I need to know is how to get the log to check if there is a slip surface under every square and one on one side or the other. I know how to do the for loop to check coordinates every 16 pixels but, how do i check those coordinates to see if there is a slip surface underneath covering those coordinates and return a true or false depending?
 

TheouAegis

Member
Code:
var mid = mean(bbox_bottom,bbox_top);
for(var i=bbox_left; i < bbox_right; i+= 16;)
if !place_meeting(i, mid, obj_slide) break;
if i < bbox_right || obj_pllayer.bbox_top > bbox_bottom || obj_pllayer.bbox_bottom < bbox_top exit;
if obj_pllayer.x > bbox_right && place_meeting(bbox_left-1,mid,obj_slide) x-=1;
else
if obj_pllayer.x < bbox_left && place_meeting(bbox_right+1,mid, obj_slide) x+=1;
 

rawket

Member
OH I think I get it, that seems great I'll give that a try. Just wondering though what does place_meeting actually do? I have used the place_meeting function before but I don't actually know what it does, I was following a tutorial when I used it. Also whoops my keyboard has a double typing issue it's just "player" not "pllayer"
 

TheouAegis

Member
Waaiiiit! LOL i did use place meeting, didn't I? Whoops.

In that code, replace place_meeting with position_meeting.
 

TheouAegis

Member
OH I think I get it, that seems great I'll give that a try. Just wondering though what does place_meeting actually do? I have used the place_meeting function before but I don't actually know what it does, I was following a tutorial when I used it. Also whoops my keyboard has a double typing issue it's just "player" not "pllayer"
place_meeting moves the instance to the coordinates specified and checks for a full bounding box collision.

position_meeting ignores the calling instance's bounding box and checks if there is a target ta the specified coordinates.

Edit: double-post. See post above this one - it's important.
 

rawket

Member
Ah lol ok got it and thanks for the explanation I think this is definitely gonna help. There are still soooo many functions I haven't learned.
 

rawket

Member
place_meeting moves the instance to the coordinates specified and checks for a full bounding box collision.

position_meeting ignores the calling instance's bounding box and checks if there is a target ta the specified coordinates.

Edit: double-post. See post above this one - it's important.
Ah lol ok got it and thanks for the explanation I think this is definitely gonna help. There are still soooo many functions I haven't learned.
 

rawket

Member
place_meeting moves the instance to the coordinates specified and checks for a full bounding box collision.

position_meeting ignores the calling instance's bounding box and checks if there is a target ta the specified coordinates.

Edit: double-post. See post above this one - it's important.
WOOO it works! Thank you!
 
Top