GMS 2 I don't understand the collision_rectangle_list function...

Hey comrades.
I hated the collision_rectangle_list function because I never understood how tf it worked.
But sadly, I need to understand it now, since I can't use anything else instead. Breh.

At first I tried to use an array as the list (the manual suggests to, and since I'm better with them, I tried with them first) but it does not seem to work.
It always displays the error: "collision_rectangle_list argument 8 incorrect type (array) expecting a Number (YYGI32)" no matter what I do.

This is the code in Step Event:
Code:
var list = [0,1,2]
var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,list,true)
Then, exhausted, I tried using a DS list instead (creating a variable in the Create Event always called "list"), and it does not seem to work either.
The game starts, but even tho I collide with something the list value remains 0.

What am I doing wrong? And thanks for the help comrades.
 

chamaeleon

Member
ds_lists and arrays are not interchangble. They are distinctly different, and any function expecting one of them as an argument will not do anything remotely correct if you pass the other type instead. If you look at the documentation for collision_rectangle_list(), perhaps you can better describe what you don't understand about the example at the bottom of the page. In any case, just because you feel more comfortable using arrays over ds_lists, does not mean that functions expecting a ds_list will gracefully accept an array. You need to give any function exactly the type of argument it expects, nothing else.
 
Last edited:
Ok, got it. Can't use array's for this thing.
Now, how does the DS list work?

I tried again, and as it should, the collision_rectangle_list gives me the number of the instances the object is colliding with.
But where do I find the ID's of the instances collected? I mean, just like collision_line does. Where are the instance IDs?

If I read the variable (through draw_text) on which I assigned the list it just says 0.

Code:
list = ds_list_create() //This is in the Create Event

var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,list,true) //This is in the Step Event
 

chamaeleon

Member
Including the code I pointed you to in my previous post
GML:
var _list = ds_list_create();
var _num = collision_rectangle_list(x - 100, y - 100, x + 100, y + 100, obj_Enemy, false, true, _list, false);
if _num > 0
    {
    for (var i = 0; i < _num; ++i;)
        {
        instance_destroy(_list[| i]);
        }
    }
ds_list_destroy(_list);
What do you expect _list[| i] to be in this example code given that it is used as an argument to the function instance_destroy()?
 

FrostyCat

Member
Once again, read the Manual entry on collision_rectangle_list. It will tell you that the colliding instance IDs are inserted into the list, and the example at the bottom of the page shows how to access them.
You supply a DS list too, so the id values of any instances that are colliding with the calling instance will be added to the end of the given list. You can clear the list before calling this function so that it only contains results from this function call. You also have the option to order the instances based on their distances from the centre of the rectangular area to their origins. The function returns the number of instances found, or 0 if none are found.
Example:
GML:
var _list = ds_list_create();
var _num = collision_rectangle_list(x - 100, y - 100, x + 100, y + 100, obj_Enemy, false, true, _list, false);
if _num > 0
    {
    for (var i = 0; i < _num; ++i;)
        {
        instance_destroy(_list[| i]);
        }
    }
ds_list_destroy(_list);
The code above will check a rectangular area 100 pixels around the calling instance position for collisions with instances of "obj_Enemy". If there are any collisions, then the pre-created list is looped through and each instance that was in the collision is destroyed.
 

chamaeleon

Member
Here's a function for you to debug content in a ds_list
GML:
function print_list(list) {
    var str = "";
    var i = 0;
    repeat ds_list_size(list) {
        if (str != "")
            str += ", ";
        str += string(list[| i]);
        i++;
    }
    show_debug_message("List id " + string(list) + " contains [" + str + "]");
}
GML:
var list = ds_list_create();
ds_list_add(list, 1, 2, 3, 4, 5);
print_list(list);
ds_list_destroy(list);
Console output
Code:
List id 0 contains [1, 2, 3, 4, 5]
 
Here's a function for you to debug content in a ds_list.
Things like "print_list" does not exist as function for some reasons, it just creates a variable called like that. Same goes for "str" and "[| i]", which I don't even know what are in the first place. I just want to display the content of the DS list on the screen, kinda like an array would show up.

Like, ok, you said that doing:
Code:
ds_list_add(list, 1, 2, 3, 4, 5);
...creates the list. So that means when I use collision_rectangle_list, the ID are place in order in 1, 2 and 3, right?
Like 1 is the first ID, 2 is the second ID etc...
But how can I read what is 1, 2, 3 etc?

If I use this:
Code:
draw_text_transformed(10,10,list,1.5,1.5,0)
...how can I read the inside of it? As you said, it just shows the ID of the list.

I need to find the ID of the instance to read it's variable, like this:
Code:
c_alt = list[1].dist
c_perm = list[2].perm
c_antiperm = list[3].antiperm
I can't figure out how the system of DS lists work, even tho is stated that is something similar to an array...
 

chamaeleon

Member
Things like "print_list" does not exist as function for some reasons
That's why I implemented one. And included it's code for you. And an example of its use. And its output to the console.
...creates the list. So that means when I use collision_rectangle_list, the ID are place in order in 1, 2 and 3, right?
This is just for my example. Creating a list with those elements has absolutely nothing, zero, to do with your code and instances. It was just an example of displaying content of a list.
Code:
c_alt = list[1].dist
c_perm = list[2].perm
c_antiperm = list[3].antiperm
I can't figure out how the system of DS lists work, even tho is stated that is something similar to an array...
They are similar to arrays. They are not arrays though. You cannot use the array notation for accessing an entry in a ds_list. You *must* use the function ds_list_find_value() or the pipe (|) accessor.
GML:
c_alt = list[| 1].dist
c_perm = list[| 2].perm
c_antiperm = list[| 3].antiperm
Examine each line carefully and compare it with your version. The only difference is the use of the pipe accessor. But it is a crucial difference that tells GMS that list is a ds_list and not an array.
 
Sorry for being late, but it was... late yesterday, like midnight or something.
By the way, all good now! I understood how to see them, how to display them and how to use them! Thank you SO much comrade!
 
Don't mind this, is just to make sure the notification arrives I think. Farts.
Hold on I still have a problem.

There's this object called "muro", which is the object that collision_rectangle_list has to check and list.
There's a "lista" variable which basically holds the DS list, and then there's "c_muro" which is just the variable related to the collision_rectangle_list thing.

Code:
lista = ds_list_create() //Create Event

var c_muro = collision_rectangle_list(x+100,y-100,x-100,y+100,muro,true,true,lista,true) //Step Event
Every instance of "muro" has an important variable called "dist", that changes for every instance of the object. One "muro" can have "dist" equal to 100, some to 200 and so on.
For some reasons, even tho the collision_rectangle_list does not collide with any "muro", if I check the value of "dist" in "lista", it always says the "dist" of the first "muro" placed in the room instead of being unidentified or something.

Code:
lista.dist
I checked the list of "lista" with the accessories you told me to use ( lista[|1] , lista[|2] , lista[|3] etc...) but they always say "undefined" if they don't collide with any "muro". If I check lista.dist[|1] it gives me an error, obviously, since is always "undefined" if there is no collision.

YET, the lista.dist is always the dist of the first "muro".
I don't get it...

What is "lista" itself even supposed to be? Apparently is different from "lista[|1]", but how? And why?

Thank you again comrade if you are willing to continue the thread.
 

chamaeleon

Member
(A simple @ chamaeleon in the text would suffice for notification purposes, no need to quote and put words in my mouth :) ).

I copied your code in haste when changing it to ds_list form. If you want to get three values from the closest instance in the rectangle, you use index 0, assuming sorting by distance.

In some event when you wish to test for collision within a rectangle
GML:
var list = ds_list_create(); // no need for it to be an instance variable, unless you intend to refer to its content outside the scope of this code
var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,list,true);
if (c_muro > 0) {
    // get the closest instance from the ds_list
    c_closest_instance = list[| 0];
    // grab three instance variables from the closest instance to the center of the rectangle
    c_alt = list[| 0].dist; // or c_closest_instance.dist
    c_perm = list[| 0].perm; // or c_closest_instance.perm
    c_antiperm = list[| 0].antiperm; // or c_closest_instance.antiperm
    // additional code that may use the values of these variables
}
ds_list_destroy(list);
I have no idea if your code needs these variables outside this if statement. Can be local variables if not, perhaps they should be instance variables if they are used outside the if statement for various game play mechanic needs, in which case I have no idea what suitable default values are.

If you want to do something with all instances in the rectangle
GML:
var list = ds_list_create(); // no need for it to be an instance variable, unless you intend to refer to its content outside the scope of this code
var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,list,true);
var i = 0;
repeat c_muro {
    // get the i'th instance from the ds_list
    c_closest_instance = list[| i];
    // grab three instance variables from the i'th instance
    c_alt = list[| i].dist; // or c_closest_instance.dist
    c_perm = list[| i].perm; // or c_closest_instance.perm
    c_antiperm = list[| i].antiperm; // or c_closest_instance.antiperm
    // additional code that may use the values of these variables
    i++;
}
ds_list_destroy(list);
 
Last edited:
YET, the lista.dist is always the dist of the first "muro".
I don't get it...

What is "lista" itself even supposed to be? Apparently is different from "lista[|1]", but how? And why?
As to this, the answer is quite simple. lista is a variable. It holds the numeric index of the list that you stored in it. When you create your first list, it's index is 0, the second list gets the index of 1 and so on. Funnily enough, this is the same for all ds_* structures (as well as objects). If you create your first ds_map, it's index will be 0, the second will have index of 1. This is why you need the accessor. The pipe accessor | literally tells the computer "Ok, you are looking for a list with the numeric index stored in this variable".

So when you type lista[| 0], the computer looks at lista, sees that it has a value of 0, then it looks at the pipe and goes "Oh, they want to access a list with the integer index stored in lista!" Then it looks at the number after the pipe, 0, and goes "Ok, in that list, they want me to access position 0!"

If, instead, you simply refer to lista.dist then because you aren't supplying a position in the list or the pipe accessor, the computer has no idea you are looking for a list with index 0, instead it goes "Oh, the coder wants to access the object with index 0 using dot notation", exactly as though you are going obj_muro.dist. It's coincidental that the first object created is an instance of "muro" and thus it is a valid operation. if you had created things in a different order, then the game would probably crash as the object with index 0 might not have a variable called dist and therefore trying to read lista.dist would throw a "variable does not exist" error.

You cannot simply read "all" the contents of a list (or even a single item in a list) without telling the computer that you are trying to access a list with the | accessor and a position in the list you want to access. list.variable is never going to be a valid operation on a list. You always need an accessor and a position (or a function and a position/value, such as is the case for ds_list_find_value() and ds_list_find_index()). Without that, the computer has no idea you are trying to read a list, and thus will never associate the integer index stored in the variable with the appropriate list integer index.
 
Last edited:
You cannot simply read "all" the contents of a list (or even a single item in a list) without telling the computer that you are trying to access a list with the | accessor and a position in the list you want to access. list.variable is never going to be a valid operation on a list. You always need an accessor and a position (or a function and a position/value, such as is the case for ds_list_find_value() and ds_list_find_index()). Without that, the computer has no idea you are trying to read a list, and thus will never associate the integer index stored in the variable with the appropriate list integer index.
Ok, this explains very good why it does not work. I thought that the coincidence was actually a normal thing for some reasons...
Anyway, the problem is that I need to check more than ONE instance's "dist" at the same time, and asking to "lista[|0]" will just check one, which is the first one it gets in contact with.

I tried asking both "lista[|0]" and "lista[|1]" for the "dist" variable, but the problem is that collision_rectangle_list decides to store the same ID twice instead of leaving the second one empty for another instance of "muro". Basically this will make the second instance of "muro" that it collides un-read because "list[|1]" will be occupied by a copy of "lista[|0]".
I basically need collision_rectangle_list to check every "dist" of "muro" it comes in contact with, without collecting the same ID twice.
 
What are you trying to do with the distance and how are you reading multiple values from the list? collision_list_rectangle() should not be storing multiple id's of the same instance and it has never done so for me. I imagine that something is wrong with your logic.

EDIT: I think chamaeleon probably hit the nail on the head.
 
Last edited:
I imagine that something is wrong with your logic.


This would only happen if you call collision_rectangle_list() more than once with the same list, without clearing the list.
The collision_rectangle_list() function is in the Step Event like this:
Code:
var c_muro = collision_rectangle_list(x-100,y-16,x+100,y+16,muro,true,true,lista,true)
...and yes, I'm always using the same list, which is "lista".

When I check the various [|0], [|1], [|2] etc... they get ALL get the same ID, unless the rectangle makes collision with 2 different instances at the same time.
 
You have to clear the list when it is done, otherwise data from the last step will still be in the list. This is how you would do it if you create the list as an instance variable in the Create Event:

Create Event
GML:
my_list = ds_list_create();
Step Event
GML:
var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,my_list ,true)
// my list now has id's in it, if there has been a collision
var _list_size = ds_list_size(my_list);
for (var i=0;i<_list_size;i++) {
   // Do whatever it is your doing with dist
}
ds_list_clear(my_list);
// my_list is now empty
Cleanup Event
GML:
ds_list_destroy(my_list);
If, instead, you are creating a local variable list each step (less optimised, but probably won't matter), then you'll have to destroy the list each step instead of clearing it:

Step Event
GML:
var my_list = ds_list_create();
var c_muro = collision_rectangle_list(x-60,y-18,x+60,y+18,muro,true,true,my_list ,true)
var _list_size = ds_list_size(my_list);
for (var i=0;i<_list_size;i++) {
   // Do whatever it is your doing with dist
}
ds_list_destroy(my_list);
Personally, I would definitely use the first example, as it's not great to be creating a destroying a list every step for no real reason.
 

chamaeleon

Member
Create a script, perhaps called scr_debug_functions, and put the code below in it
GML:
function print_list(prefix, list) {
    var str = "";
    var i = 0;
    repeat ds_list_size(list) {
        if (str != "")
            str += ", ";
        str += string(list[| i]);
        i++;
    }
    show_debug_message("[" + prefix + "] List id " + string(list) + " contains [" + str + "]");
}
Then you can use it at various places
GML:
var c_muro = collision_rectangle_list(x-100,y-16,x+100,y+16,muro,true,true,lista,true)
print_list("lista", lista);
And you can see if the list contains what you expect every step, or not, over time as steps execute.

If you find the same instance ids stored repeatedly, I suggest adding a ds_list_clear() before the collision check.
GML:
ds_list_clear(lista);
var c_muro = collision_rectangle_list(x-100,y-16,x+100,y+16,muro,true,true,lista,true)
 
You have to clear the list when it is done, otherwise data from the last step will still be in the list. This is how you would do it if you create the list as an instance variable in the Create Event:
Oke I put a ds_list_clear() working everytime the horizontal speed is different from 0. It kinda works, but I need to make some adjustments.
BUT, it works now!

Thank you all again! Maybe I can get this dumb thing working.
 
Oke I put a ds_list_clear() working everytime the horizontal speed is different from 0.
I'm confused? What does the horizontal speed have to do with the list? I think the easiest way for you to do it would just be to clear the list directly before you call the collision_rectangle_list():
GML:
ds_list_clear(my_list);
var num = collision_rectangle_list();
// Whatever you're doing with the list here
It's important that the list is empty before you call collision_rectangle_list(), otherwise it won't work properly. Most of the time, that's done after you've dealt with the data from the list, but since there seems to be something confusion going on, simply clear it before as the easiest way to make sure it's empty.
 
I'm confused? What does the horizontal speed have to do with the list? I think the easiest way for you to do it would just be to clear the list directly before you call the collision_rectangle_list()
It's connected to the collisions. I'm trying to make MULTY collisions with two different horizontal speeds.
hsp_x and hsp_y. If I directly use the ds_list_clear constantly, the values are updated so fast that the only value I can see for lista[|0] and his friends, is just "undefined".

I'll switch back to the normal clearing process once I understand why one specific bug occurs, don't worry.
And if you are wondering: yes, this very bug happens even by just using the normal clearing process. I'm doing it only for debugging sake comrade.
 
If you explain exactly what you are actually trying to do and provide all your code, you'll probably end up getting more/better help to solve the problem.
 
If you explain exactly what you are actually trying to do and provide all your code, you'll probably end up getting more/better help to solve the problem.
Again, COULD.
But I want to do it myself. Don't get me wrong comrade, I appreciate every single thing you guys have done for me since 2018, but I'd rather not end up copy pasting codes and stuff, or even having someone else doing the programming for me. Not only because I would not understand how it works, but also because I don't like it.

Maybe I'll share you the final "working" result if you are interested in giving performance enhancements. Only if I literally have NO other way that I can do it, I'll seek for "extreme" help.
 
Top