• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Struggling with pulling blocks that I can push

Okay, so I'm trying to be able to pull blocks. I have a pull state for the player character that can only trigger if they're in collision with the object that I want to pull. I have the player moving freely but all push/pull objects move along a grid. When I push the blocks, they move along the grid and have a delay before they move (which is what I want) that I've accomplished through timers. At first I tried to use alarms, but it was far too annoying having to manage a bunch of tiny events , so, yeah, timers.

this is the collision I have with the par_pushblock. (I want it to be able to have many different sprites which is why it's a parent object)

var timer_frames = 31;


if (place_meeting(x+1, y, par_pushblock)) && right {
with (other) {
timerR -=1
if timerR <=0 {
MoveBlock(directions.right);
}
if timerR <=-1 {
timerR +=timer_frames
}
}
}
if (place_meeting(x-1, y, par_pushblock)) && left {
with (other) {
timerL -=1
if timerL <=0 {
MoveBlock(directions.left);
}
if timerL <=-1 {
timerL +=timer_frames
}
}
}


if (place_meeting(x, y+1, par_pushblock)) && down{
with (other) {

timerD -=1
if timerD <=0 {
MoveBlock(directions.down);
}
if timerD <=-1 {
timerD +=timer_frames
}
}
}

if (place_meeting(x, y-1, par_pushblock)) && up {
with (other) {
timerU -=1
if timerU <=0 {
MoveBlock(directions.up);
}
if timerU <=-1 {
timerU +=timer_frames
}
}
}
and this is the script the timers are triggering.

var dir = argument0;
var components = global.components[dir];
var dx = components[0];
var dy = components[1];

if (state == states.still) {
x_from = x_pos;
y_from = y_pos;

x_to = x_pos + dx;
y_to = y_pos + dy;

x_pos = x_to;
y_pos = y_to;

state = states.pushed;
}
Anyways, long story short: the problem I have is that when I write code that checks for a collision with the player while the sprite index is the pulling sprite, neither the block nor the player move. I tried using show_debug_message(timerU) for the pulling but it doesn't even appear.

I'm assuming that the collision with the block from above it is overriding whatever the pulling does. I tried disabling collisions with the player when they enter the pull state but then it just keeps the pull state and the collision can't check because of the collision being disabled.

This is really stumping me :(
 
Off the top of my head, when I have done push / pull blocks it has been like this (assuming it's an active player event, rather than simulating physics):

Code:
if active
{var is_crate = instance_position(x + hspeed, y, obj_crate);
if is_crate != noone
{
is_crate.x = x + (is_crate.sprite_width / 2) // or whatever way you can use to get the distance to separate the crate from the object manipulating it
}
}
'active' is just a variable set to true / false when a key is held down i.e the player exerts the control, and is really just manipulating the crates x position. Very basic, but it works for both push and pull.

If you wanted them to be able to push without pressing a button (just by continually walking into it) then that could maybe be done like this:
Code:
[CODE]
var is_crate = instance_place(x + hspeed, y, obj_crate);
if is_crate != noone
{with (is_crate) // then goes to the crate id
if force < 1
{
force += 0.1 // or whatever
}
else
{if !place_meeting(x + other.hspeed, y, obj_wall) // looks to see if the crate can actually move, by doing it's own collision check using the hspeed of the player
{
x += other.hspeed // would add a basic "force" to the crate
}
}
}
[/CODE]

I'm not sure how you'd reset 'force' in the crate when not in collision, but you could use it as a way of controlling the crate responding. It would delay the movement for a certain amount of time. This would then just bump the crate along....I think :)

EDIT: The last one works, and the object will stop when it can't move. Looks a bit off though, as there is quite a lot of overlap between the player and the object when the push starts happening.

I changed it to instance_place, but not sure if that fixed it. As my whole movement in my project to test this has some extra code for the player:

Code:
if !place_meeting(x+hSpeed, y, obj_crate)
{
x += hSpeed;
}
else
{
if (!place_meeting(x+sign(hSpeed), y, obj_crate))
{
x += sign(hSpeed);
}
else
{
var is_crate = instance_place(x + hSpeed, y, obj_crate);
if is_crate != noone
{
with (is_crate) // then goes to the crate id
{
if force < 1
{
force += 0.1;
}
else
{
if !place_meeting(x + other.hSpeed, y, oWall) // looks to see if the crate can actually move, by doing it's own collision check using the hspeed of the player
{
other.x += sign(other.hSpeed) * push_spd; // push_spd is a variable in the crate that determines how quickly it is pushed
x += sign(other.hSpeed) * push_spd;
}
}
}
}
}
}
Here it is just for obj_crate, but I would do a parent for the crates and walls, so that the first part of the player movement collision checking works for everything.
 
Last edited:
Okay, that's some good stuff! I do like how it checks collision between the wall and the crate through the same lines of code but the nature of my problem appears to be very specific: it's a whole clash of how the player moves freely versus how the push/pull blocks move along a grid and I don't know how to make the player move along the same grid at the same time as the block.
 
I need to get a bit more info to figure out your end result. When I set up the project I kind of assumed it was side on, and limited to pushing / pulling to the left or to the right.

grid.png
Do you want it to move instantly to the correct next grid "cell" like in the picture above? I.E it's a top down view, or something like that?
 
The game is a top-down view, yeah, in a Link's Awakening sort of perspective. I don't want it to move instantly. If you look at the push/pull blocks from Link's Awakening or any other 2D Zelda, they usually have a bit of a delay before they start moving. Here's how I had it in a previous build before I restarted the grid system from scratch
Here is my grid macro
Code:
gml_pragma("global", "PUSHBLOCKGRID()")

#macro TILE_WIDTH 16
#macro TILE_HEIGHT 16

enum directions {
    right,
    up,
    left,
    down
}

global.components = []
global.components[directions.right] = [1,0];
global.components[directions.up] = [0, -1];
global.components[directions.left] = [-1, 0];
global.components[directions.down] = [0, 1];
This script then operates based on the macro
Code:
var dir = argument0;
var components = global.components[dir];
var dx = components[0];
var dy = components[1];

if (state == states.still) {
    x_from = x_pos;
    y_from = y_pos;

    x_to = x_pos + dx;
    y_to = y_pos + dy;
    
    x_pos = x_to;
    y_pos = y_to;
    state = states.pushed;
}
and then this is pretty much the collision event with par_pushblock that is in o_player but it just gets repeated with slightly different variables.

Code:
var timer_frames = 31;


if (place_meeting(x+1, y, par_pushblock)) && right  {
    with (other) {
            forceR = 1;
            if forceR == 1 {
            timerR -=1
            if timerR <=0 {
                MoveBlock(directions.right);
            }
            if timerR <=-1 {
                timerR +=timer_frames
            }
            
        }
    }
}
and last but not least, the step event for the par_pushblock object. This makes it so that it moves 16 pixels at a slow pace to give a sense of pushing. I don't know if I should just stick with the newer style of doing it (which has been proving to be harder but on paper, it seems like it would be more universal) or just try to repurpose this method to work for pulling. I got the structure of this code via YouTube through a tutorial, but when I look at this code it just seems like it has an unnecessary amount of work in it and that the newer method I'm attempting will have less work in the long run but requires more figuring out from myself.

Code:
if (state == states.pushed) {
    walk_anim_time += delta_time / 1000000;
    
    var t = walk_anim_time / walk_anim_length;
    
    if (t >= 1) {
        walk_anim_time = 0;
        t = 1;
        state = states.still;
    }
    
    var _x = lerp(x_from, x_to, t);
    var _y = lerp(y_from, y_to, t);
    
    x = _x * TILE_WIDTH;
    y = _y * TILE_HEIGHT;
}
Again, stumping the heck out of me
 
Top