Step event collision doesn't work

So in my game, I can't use Collision Event for obj_enemy because obj_enemy needs to be marked as Solid, and that will stop it upon any collision.
So I put the following in Step event to work around it:

GML:
if place_meeting(x,y,obj_limit){
if escape=false{
direction = image_angle+180
}
}
The idea is, when obj_enemy has var escape=false, it cannot pass through obj_limit, but when escape is true then it can. When it can't, I want it to change direction to where it came from, and thus stay inside the obj_limit boundaries (the object is basically a big empty rectangle)
It does detect the collision when I, for example, make it show_message() upon collision between obj_enemy and obj_limit, but if I put any collision code there, (speed = 0, etc.) it doesn't work and obj_enemy just passes right through.
So how to make obj_enemy stop upon collision with obj_limit, or turn around.

Any help much appreciated.
 
Last edited:
Im trying to have an object detect a collision with another object in Step Event:

GML:
if place_meeting(x,y,obj_limit){
direction = image_angle+180
}
and then turning it around if it collides. However this never works, it does detect the collision (i checked with f.ex. playing a message upon collision) but it never plays any collision events that I place there, like set speed=0, or the turning the object around one that I have up there.
Position_meeting(), same thing...

Ideas?
 

chamaeleon

Member
Im trying to have an object detect a collision with another object in Step Event:

GML:
if place_meeting(x,y,obj_limit){
direction = image_angle+180
}
and then turning it around if it collides. However this never works, it does detect the collision (i checked with f.ex. playing a message upon collision) but it never plays any collision events that I place there, like set speed=0, or the turning the object around one that I have up there.
Position_meeting(), same thing...

Ideas?
Provide evidence that it does not work, perhaps in the form of show_debug_message() before, inside and after the if statement, along with the values of direction and image_angle.
 
came up with a workaround. still bothers me tho... why didn't place_meeting() work there.
I can recreate it here afterwards, provide pictures or smth, but basically the topic is solved. Just haunts the back of my head now!!

Basically, obj_limit is a big empty rectangle, inside of which instances of obj_enemy spawn, and I wanted them to not be able to pass outside obj_limit other than on certain cases only.
I was able to register a collision (when obj_enemy touches obj_limit, more specifically the boundaries of the rectangle) with position_meeting(), but place_meeting() kept registering a collision constantly for the entire obj_limit's hitbox, (the rectangle square) not just the edges which are the only part drawn in the sprite. so that confused me.
Also neither position_meeting() or place_meeting() in Step event ever registered any events which affects obj_enemy's movement, like the one in my code above. Even if I put:

GML:
if place_meeting(x,y,obj_limit)
{
speed=0
}
or the likes, the enemies just passed through.

confusing, i know... i struggled to explain it well.
 

HGCD

Member
If your obj_limit is a big empty rectangle then it's collision mask is probably just a box covering the entire sprite, it would be better to create 4 rectangular objects stretched out to create an outer boundary, but to be honest there are better ways to do this if you're trying to just create a room boundary. Like for example checking the sprite x and y plus the halfwidth / height of the sprite (note that you can actually just use bbox_left/bbox_right/bbox_top/bbox_bottom to get the in-world coordinates of each corner of your object, which will account for any scaling the object has) against the room limits (eg. 0, 0, room_width, room_height)

Hope this helps =)
Good luck
 
If your obj_limit is a big empty rectangle then it's collision mask is probably just a box covering the entire sprite, it would be better to create 4 rectangular objects stretched out to create an outer boundary, but to be honest there are better ways to do this if you're trying to just create a room boundary. Like for example checking the sprite x and y plus the halfwidth / height of the sprite (note that you can actually just use bbox_left/bbox_right/bbox_top/bbox_bottom to get the in-world coordinates of each corner of your object, which will account for any scaling the object has) against the room limits (eg. 0, 0, room_width, room_height)

Hope this helps =)
Good luck
hey, thanks for response, yeah, admittedly the way I've implemented it (the limits) is crude... it worked real well until now, that I came up with a certain feature that featured these obj_limits deeper.
I think the collision mask in obj_limit is set to Precise, and thus it's only composed of the drawn edges of the rectangle sprite, and not the whole thing. (correct me if Im wrong)
With obj_enemy, their collision masks are edited so that the Masks are a bit smaller than the sprites themselves.
So could the fault be in the collision masks, why it doesn't detect any physical collision between the two? (or at least implement it)
 

HGCD

Member
Precise collision can be tricky, and it's really slow, so for big volumes it's going to cause a lot of wasted processing because it operates per pixel, so instead of 4 operations for each axis, you'll be doing hundreds or thousands, and the more objects you have in your world checking for that collision will multiply that. But if you want to just get something working make sure both objects are using a precise collision mask, and I know there are some functions that specifically have a precise argument (eg. collision_rectangle()) but I'm not really sure, I just remember the few times I've played with it it's taken some tweaking to get working.

if your player is just using a rectangular collision mask it's honestly way easier (and cheaper), to just do something like this:
GML:
if ((bbox_left <= 0) || (bbox_right >= room_width))
    {
    // Change X direction
    }
if ((bbox_top <= 0) || (bbox_bottom >= room_height))
    {
    // Change Y direction
    }
You may want to snap the moving object back to a position where it's touching but not colliding, otherwise it can get caught in the volume and collide over and over each frame which may get it stuck.
To do that you'd just get the difference between the collision edge and the object's touching edge and subtract that from the object's position.
 

Hypotakt

Member
I solved this stuff in my current project as followed:
GML:
//;; FUNCTION FOR BEING BLOCKED BY WALL ;;

//BLOCK LEFT
if( blocking_objects(x - speed, y) )
{
    while( blocking_objects(x - speed, y) )
    {
        x++;
    }
}

//BLOCK RIGHT
if( blocking_objects(x + speed, y) )
{
    while( blocking_objects(x + speed, y) )
    {
        x--;
    }
}

//BLOCK TOP
if( blocking_objects(x, y - speed) )
{
    while( blocking_objects(x, y - speed) )
    {
        y++;
    }
}

//BLOCK BOTTOM
if( blocking_objects(x, y + speed) )
{
    while( blocking_objects(x, y + speed) )
    {
        y--;
    }
}
And then you will need the custom script blocking_objects() too:
Code:
//;; SCRIPT BLOCKING OBJECTS ;;

//Checks collisions with blocking objects;
//scr_blocks = array with blocking objects, ret_bool = result of place_meeting();
var scr_blocks;
var ret_bool = false;

scr_blocks[0] = tree_obj;
scr_blocks[1] = enemy_common_obj;
scr_blocks[2] = player_obj;

for(var scr_block = 0; scr_block < array_length_1d(scr_blocks); scr_block++){
    ret_bool = place_meeting(argument[0], argument[1], scr_blocks[scr_block]);
    if(ret_bool){
        break;
    }
}

return ret_bool;
You get the idea? The first code checks if there is place_meeting() from any direction - and if it is, push against the opposite direction until it's false again.
The script blocking_objects() is basicly an extended version of place_meeting(), supporting multiple objects which are blocking. If you like this solution, then you could
optimize it for your project, like using lists/maps instead of arrays (arrays are fine, but whatever) in the blocking_objects(). Also, you could support multiple objects
for the first code, if you put it into a script and give id as argument[0]. Then you can check id.x / id.y / id.speed, which makes the thing for dynamic :)

If you have any questions left, feel free to ask.

- cheers
 

Nidoking

Member
Wow, that custom function definitely needs to be replaced with a common parent for all objects that something can collide with.
 
Yeah, I just create a "par_block" object with no code. Then in any code controlling movement you check whether movement will collide them with par_block and if so stop them.
 

chance

predictably random
Forum Staff
Moderator
I've merged two of your topics. Please don't post multiple topics about essentially the same issue. It's not fair to other members.
 
I solved this stuff in my current project as followed:
GML:
//;; FUNCTION FOR BEING BLOCKED BY WALL ;;

//BLOCK LEFT
if( blocking_objects(x - speed, y) )
{
    while( blocking_objects(x - speed, y) )
    {
        x++;
    }
}

//BLOCK RIGHT
if( blocking_objects(x + speed, y) )
{
    while( blocking_objects(x + speed, y) )
    {
        x--;
    }
}

//BLOCK TOP
if( blocking_objects(x, y - speed) )
{
    while( blocking_objects(x, y - speed) )
    {
        y++;
    }
}

//BLOCK BOTTOM
if( blocking_objects(x, y + speed) )
{
    while( blocking_objects(x, y + speed) )
    {
        y--;
    }
}
And then you will need the custom script blocking_objects() too:
Code:
//;; SCRIPT BLOCKING OBJECTS ;;

//Checks collisions with blocking objects;
//scr_blocks = array with blocking objects, ret_bool = result of place_meeting();
var scr_blocks;
var ret_bool = false;

scr_blocks[0] = tree_obj;
scr_blocks[1] = enemy_common_obj;
scr_blocks[2] = player_obj;

for(var scr_block = 0; scr_block < array_length_1d(scr_blocks); scr_block++){
    ret_bool = place_meeting(argument[0], argument[1], scr_blocks[scr_block]);
    if(ret_bool){
        break;
    }
}

return ret_bool;
You get the idea? The first code checks if there is place_meeting() from any direction - and if it is, push against the opposite direction until it's false again.
The script blocking_objects() is basicly an extended version of place_meeting(), supporting multiple objects which are blocking. If you like this solution, then you could
optimize it for your project, like using lists/maps instead of arrays (arrays are fine, but whatever) in the blocking_objects(). Also, you could support multiple objects
for the first code, if you put it into a script and give id as argument[0]. Then you can check id.x / id.y / id.speed, which makes the thing for dynamic :)

If you have any questions left, feel free to ask.

- cheers
wow, thats a mighty code. I got the idea, i need to try this out. Nevermind that I kinda managed to solve my issue now, but I always aim to make the collisions in my game smoother so I'll try and learn from yours! thanks
 
I managed to solve the issue with making the enemy avoid (mp_potential_step_obj) the limits but cancel that and have another movement code play when it means to escape. so then, it ignores the mp_potential_step, just sets a new speed and direction value for obj_enemy and moves through the obj_limit. No Collision event needed.
thanks for all your trouble, and answers to this topic
I got a lot of use from your replies
 
Precise collision can be tricky, and it's really slow, so for big volumes it's going to cause a lot of wasted processing because it operates per pixel, so instead of 4 operations for each axis, you'll be doing hundreds or thousands, and the more objects you have in your world checking for that collision will multiply that. But if you want to just get something working make sure both objects are using a precise collision mask, and I know there are some functions that specifically have a precise argument (eg. collision_rectangle()) but I'm not really sure, I just remember the few times I've played with it it's taken some tweaking to get working.

if your player is just using a rectangular collision mask it's honestly way easier (and cheaper), to just do something like this:
GML:
if ((bbox_left <= 0) || (bbox_right >= room_width))
    {
    // Change X direction
    }
if ((bbox_top <= 0) || (bbox_bottom >= room_height))
    {
    // Change Y direction
    }
You may want to snap the moving object back to a position where it's touching but not colliding, otherwise it can get caught in the volume and collide over and over each frame which may get it stuck.
To do that you'd just get the difference between the collision edge and the object's touching edge and subtract that from the object's position.
yeah, my way is kind of cavemans version of rectangular collision, but felt easier when I first needed to implement it. i think now that i managed to solve my issue, Ill update it
 
Top