• 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!

SOLVED Collision Rectangle not detecting objects when collision masks of sprites do not overlap

D

Dragoen_Mage

Guest
I am trying to implement a modular movement boost system in a 2D platformer. I wrote a script that should detect when a box drawn by the collision_rectangle that is 1 pixel larger on each side (34w x 66h) than the sprite of my player object with the origin point centered (32w x 64h) overlaps with another object, then pull two variables from that object to set the player objects boost multiplier. The script works with objects that the player can walk through so that the sprites collision masks overlap. Objects that stop the player object on collision do not update the boost multiplier. The objects that the player object can collide with are all child objects of my oWall object. Am I just misunderstanding how the collision_rectangle works?

Script Code

Code:
///@func scBoost(X1,Y1,X2,Y2,obj)
///@arg Left edge
///@arg Right edge
///@arg Top edge
///@arg Bottom edge
///@arg Object

var X1 = argument[0]
var Y1 = argument[1]
var X2 = argument[2]
var Y2 = argument[3]
var obj = argument[4]

if (collision_rectangle(X1,Y1,X2,Y2,obj,false,false))
{
        vboost=obj.vboost
        hboost=obj.hboost
}
Script Call with movement modification

Code:
//boost check in step event

vboost=1
hboost=1
xleft = x-17
xright = x+18
ytop = y-34
ybottom = y+33

scBoost(xleft,ytop,xright,ybottom,oBoost_Up);
scBoost(xleft,ytop,xright,ybottom,oBoost_Down);
scBoost(xleft,ytop,xright,ybottom,oBoost_Right);
scBoost(xleft,ytop,xright,ybottom,oBoost_Left);

//Horizontal Movement

var move = (key_right - key_left) * hboost;

hsp = move * walkspeed;

//Jump
vsp = vsp + grv
if (place_meeting(x,y+1,oWall)) && (key_jump) && (doublejump==0)
{
    vsp = -8 * vboost;
    doublejump = 1;
}
Collision Code Curtsy of Shaun Spalding

Code:
//Horizontal Collision
if (place_meeting(x+hsp,y,oWall))
{
    while (!place_meeting(x+sign(hsp),y,oWall))
    {
        x = x + sign(hsp);
    }
    hsp= 0;
}

x=x+hsp

//Vertical Collision
if (place_meeting(x,y+vsp,oWall))
{
    while (!place_meeting(x,y+sign(vsp),oWall))
    {
        y = y + sign(vsp);
    }
    vsp = 0;
    doublejump = 0;
}

y=y+vsp
 

Alexx

Member
Code:
var obj = argument[4]
Is more than one instance of that object present in the room?
 
Last edited:

FrostyCat

Redemption Seeker
The problem is obvious if you know the difference between objects and instances and the proper procedures for handling collisions.
NEVER access a single instance by object ID if multiple instances of the object exist. This includes attempts to reference or set object.variable (which is inconsistent across exports) and using with (object) to apply actions to it (this encompasses all instances of the object instead of just the one you want). Verbally, "Dog's colour" makes sense with one dog, but not with multiple dogs.
Collision-checking functions: instance_place() and instance_position() are the instance-ID-oriented analogues of place_meeting() and position_meeting(). Functions that start with collision_ all return instance IDs. Save that instance ID into a variable (e.g. var inst_enemy = instance_place(x, y, obj_enemy);), then use that as the subject to work with (e.g. inst_enemy.hp -= 10;). Note that these functions return noone upon not finding a collision. Always account for this special case whenever you handle collisions this way.
Code:
///@func scBoost(X1,Y1,X2,Y2,obj)
///@arg Left edge
///@arg Top edge
///@arg Right edge
///@arg Bottom edge
///@arg Object

var inst = collision_rectangle(argument0, argument1, argument2, argument3, argument4, false, false);
if (inst != noone)
{
    vboost = inst.vboost;
    hboost = inst.hboost;
}
Also, if you make a common parent object for those four boost types, you can check just the parent instead of making 4 separate checks.
 
D

Dragoen_Mage

Guest
Thanks for the replies,

Is more than one instance of that object present in the room?
Yes, there are multiple instances of each object. I didn't think that was the problem because the script/boost code work in a previous, less clean variant, but it sounds like it is.

The problem is obvious if you know the difference between objects and instances and the proper procedures for handling collisions.
I was hoping to bypass the need to reference individual instances by having the specific objects for each case, but it sounds like that is not workable from reading your post. I guess it is time to sit down and rewrite the collision and boost sections.

Also, if you make a common parent object for those four boost types, you can check just the parent instead of making 4 separate checks.
They do have a common parent currently to make the movement related collisions work, but I prefer to make my code fit the processor space available. :oops:
 
D

Dragoen_Mage

Guest
I rewrote the collision scripting for both vertical and horizontal collisions and have run into a new problem. When the oPlayer object collides vertically and in some cases horizontally the the game enters a loop and locks up. I end up having to go into the task manager and kill the game preview. I think it has to do with the ds_lists I am creating as part of the collision events. I rewrote the code to reference individual instances instead of the object using the ds_list and then when done destroy the ds_list, but once the player instance touch the ground the core on the processor maxes out and memory usages jumps. I don't really understand ds_lists, but from what i read in other posts on this forum my code shouldn't be doing this.

Horizontal Collision
Code:
///@func scHcollide(Player,Object)
//@arg Colliding Instance ID
//@arg Object To Collie With

var objinst = 0;
var inst = argument[0]
var obj = argument[1]
var instx = inst.x;
var insty = inst.y;
var insthsp = inst.hsp;
var hcollide_list = ds_list_create();
var count = instance_place_list(instx + insthsp,insty,obj,hcollide_list,false);

while (count !=0)
{
    objinst = ds_list_find_value(hcollide_list,count-1);
    var objinstcollide = objinst.collide;
    if (objinstcollide = true)
    {
        while (!instance_place(instx+sign(insthsp),insty,objinst))
        {
            inst.x = instx + sign(insthsp)
        }
    inst.hsp = 0;
    }
    count = count-1;
}
ds_list_destroy(hcollide_list)
Vertical Collision
Code:
///@func scVcollide(Player,Object)
//@arg Colliding Instance ID
//@arg Object To Collie With

var objinst = 0;
var inst = argument[0]
var obj = argument[1]
var instx = inst.x;
var insty = inst.y;
var instvsp = inst.vsp;
var vcollide_list = ds_list_create();
var count = instance_place_list(instx,insty + instvsp,obj,vcollide_list,false);

while (count !=0)
{
    objinst = ds_list_find_value(vcollide_list,count-1);
    var objinstcollide = objinst.collide;
    if (objinstcollide = true)
    {
        while (!instance_place(instx,insty+sign(instvsp),objinst))
        {
            inst.y = insty + sign(instvsp)
        }
    inst.vsp = 0;
    }
    count = count-1;
}
ds_list_destroy(vcollide_list)
 

Nidoking

Member
Code:
while (!instance_place(instx+sign(insthsp),insty,objinst))
{
    inst.x = instx + sign(insthsp)
}
Look very carefully at this part. You are modifying inst.x, but then doing your checks with instx. instx is not changing, ever. I recommend eliminating the instx and insty variables entirely, because they do nothing for you. Just use inst.x and inst.y directly for both set and get lines. The same thing will happen for insthsp and instvsp.
 
D

Dragoen_Mage

Guest
Not creating individual variables for each of the calling instance variables cleans up the scripts I wrote, but it hasn't solved the game locking up when the player touches the floor. I did find an interesting tidbit while looking through the debug, the player object ends any fall .1 pixels into the floor. I tried to move the player to outside the floor instance, but the memory leak crashes the game before that adjustment to the players y coordinate takes effect. I also tried capping the players downward movement speed to see if the acceleration in the y direction was causing the masking overlap and that didn't solve the problem either.

You are modifying inst.x, but then doing your checks with instx. instx is not changing, ever.
A little off-topic, but wouldn't instx and insty be redefined each time the script was called to be the current inst.x and inst.y respectively?
 

Nidoking

Member
A little off-topic, but wouldn't instx and insty be redefined each time the script was called to be the current inst.x and inst.y respectively?
Yes. However, you're not calling the script from inside the while loop that's in the script. Within the while loop, there is nothing changing the values of those variables.
 
D

Dragoen_Mage

Guest
Okay, I figured out my collision issue! I stepped through the scVcollide script in the debugger and found that if I am in collision with more than one instance the script loops because I have set the inst.vsp = 0 before checking for collisions with additional object. After that the inst.vsp doesn't affect the inst.y so !instance_place() never flips to false(true? booleans confuse me, ) and the whole script gets stuck in an endless loop in the while statement. Now to fix that and add the boost variable pickup off of collided objects in the instance list and I should be home free.
 
D

Dragoen_Mage

Guest
Once I sat down and read through the debugger part of the manual I figured out the stop button. Tbh I almost always have the task manager floating around somewhere on screen becuase I play "stable" modded minecraft packs. I just default to ending programs with it when they misbehave and will continue to until Microsoft forces me to change my ways by removing the task manager.
 
Top