SOLVED Setting Variables to Objects through ds_lists

Hello. I am trying to create an inventory system that displays information based off the object you currently have selected. I've gotten the ability to show information to work, but I need to create a variable to set that value to. What I'm trying to do is print out this list of objects, the objects that are in your inventory, when you open your inventory:
Code:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){
    instance_create_depth(0,0,0,global.inventoryObj[|q]);    
}
this creates all the objects in the inventory, but if I try to set an object to a variable, like this:
Code:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){
    instance_create_depth(0,0,0,global.inventoryObj[|q]);
    //Setting each object a variable
    if(q == 0){
    global.item1 = global.inventoryObj[|0]
    }
    if(q == 1){
    global.item2 = global.inventoryObj[|1]
    }
}
it only sets it to the object ID, then seems to continuously add 1 to it even after it leaves the for loop.
I've also tried putting these variables in the create event:
Code:
global.item1 = global.inventoryObj[|0]
global.item2 = global.inventoryObj[|1]
global.item3 = global.inventoryObj[|2]
global.item4 = global.inventoryObj[|3]
but this sets it to a number that doesn't correlate with the object ID. The value is consistent with the object, i.e. there is a paper you can pick up and it's value is always 39, and a key's value is always 29. I'm not sure where these numbers are coming from though.
But what my goal is is to set the global.itemx variables to an actual object, not the object ID. That way I can call variables defined in the object in your inventory.

This is version 2.3.2.426(I'm getting this from the console, is this a reliable way to find the exact version?)

Hope this makes sense!
 

Vusur

Member
You are mixing up instances and objects. Your thought is almost correct. Lets look at this:

GML:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){
    instance_create_depth(0,0,0,global.inventoryObj[|q]);
}
You are creating an instance of the object global.inventoryObj[| q] each loop, but never stored them. They are in your game and at the right position, but there is no easy way to call them now. They are "floating around" (not really, you can get them back, but we ignore this for now).

Now we look at this:
GML:
 //snip
global.item1 = global.inventoryObj[|0]
You already noticed, that you store the object ID here which is correct if the list contains object IDs but not what you want. It's not what you created. What you want is the instance ID. So the information, you never stored in an array or somewhere else.

An easy fix for you:

GML:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){
   someStorage[| q] = instance_create_depth(0,0,0,global.inventoryObj[|q]);
}
someStorage[..] has now the instance IDs. This translates to:

GML:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){

    //notice the new var _inst! We only need it locally. 
    var _inst =instance_create_depth(0,0,0,global.inventoryObj[|q]);
 
    //Setting each instance(!!) a variable
    if(q == 0){
    global.item1 = _inst;
    }
    if(q == 1){
    global.item2 = _inst;
    }
}
or even simpler, making global.item into a list:

GML:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){

    //notice the new var _inst!
    var _inst =instance_create_depth(0,0,0,global.inventoryObj[|q]);
 
    //Setting each instance(!!) a variable
    global.item[q] = _inst;
}
or even shorter but still readable:

GML:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){

    //Setting each instance(!!) a variable
    global.item[q] = instance_create_depth(0,0,0,global.inventoryObj[|q]);
}
Now you can use global.item1.x; global.item1.someOtherVariable; or with listsglobal.item[| 0].x; global.item[| 0].speed

Are you familiar with other programming languages like C++ or Java?
They have classes (the definition of an object) and objects (the actual thing). In a naive way, objects in GML are classes and instances are objects. I know, confusing (not entirely correct).

Edit: I throw some manual pages in about Instances and Objects :)
 
Last edited:
Thanks for all the help! So I put in the global.item[q] variable like this:
Code:
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){

    //Setting each instance to a variable
    global.item[q] = instance_create_depth(0,0,0,global.inventoryObj[|q]);
}
Now I'm trying to recall this information in a separate object, although my setup may not be correct. I have a variable called "choices" which determines which selection you are on. Then, in when the inventory gets created, this little cloud pops up as the selection tool. Through this instance you can select an item in your inventory and get info from it like this
Code:
if(keyboard_check_pressed(vk_space) && instance_exists(Inv_Display) && !instance_exists(InvSelect)){
        instance_create_depth(cam_coordsx+60,cam_coordsy,-10002,InvSelect);
        x=cam_coordsx+70
        y=cam_coordsy+45
        global.saveChoice = global.choices;
        global.choices = 0;
        if(global.saveChoice == 0){
            global.selected = global.item[0]
        }
        if(global.saveChoice == 1){
            global.selected = global.itm[1]
        }
        //Etc
}
The InvSelect object lets you get 3 values out of an instance, whether you want info on it, if you want to use it, or drop it. There is one other object that pops up that gives you this info. My current issue is it cannot find an instance of the object you have selected. It sets 3 variables:
Code:
var _info = global.selected.info
var _consume = global.selected.consume;
var _drop = global.selected.drop;
Then depending on what option you choose(if you want to see info on it, consume it, drop it) it sends the text in a block of code like this
Code:
if(global.choices == 0){
    messageText = string_copy(_info, 1, messageChar);
//Send text 1 char at a time
if(messageChar <= string_length(_info)){
    messageChar += charSpeed;
    //Skip text
    if(keyboard_check_pressed(ord("E"))){
        messageChar = string_length(_info);
        messageChar -= charSpeed;
    }

}
}
I've tested it on individual instances, but if I set it to a variable first like I've done already the game can't find the instance of the object.
 
Last edited:

Vusur

Member
Just a small tip: If you editing code in your posts and you are using the </>, you can choose a "language". Switch it to gml so the code gets some colors. If you do it manually or wanna edit later in -> "["CODE=gml] (without "")
Makes it easier to read, because colors have an intutive meaning. It's ok, thou :)

I see how you wanted to do this and I think I also see the problem. First we take this code.

GML:
if(keyboard_check_pressed(vk_space) && instance_exists(Inv_Display) && !instance_exists(InvSelect)){
        instance_create_depth(cam_coordsx+60,cam_coordsy,-10002,InvSelect);
        x=cam_coordsx+70
        y=cam_coordsy+45
        global.saveChoice = global.choices;
        global.choices = 0;
        if(global.saveChoice == 0){
            global.selected = global.item[0]
        }
        if(global.saveChoice == 1){
            global.selected = global.itm[1]
        }
        //Etc
}
So you press space, there is an Inv_Display instance and currently no InvSelect instance in the room. If all this is true, you are creating and InvSelect. As a side-note, do you destroy this instance at any point? Because if not, this if statment will only be true once. Also, is it correct, that you wanna set x and y for the instance, that is running this code or did you wanted setting x and y for the newly created InvSelect instance? Because those a two different instances (objects :p ).

Also, you created an instance again, but you didn't store it. In this case, it's not THAT bad, because there can only be one instance of it. We can retrieve quite easely. How? We will see if it's even needed.

The most important part is probably this: global.selected = global.item[0]. You stored the instance ID in selected. This has nothing to do with InvSelected. This is important for the next code block:

GML:
var _info = global.selected.info
var _consume = global.selected.consume;
var _drop = global.selected.drop;
Is this code block in InvSelected? If not, InvSelected still hasn't something to do here. It's still floating around and only knows about the stuff, that is global or set in its creation code.

You are accessing the values stored in the instances that we previously stored in global.item[...]. Do those instances have a variable called info, consume or drop? So a long road back to instance_create_depth(0,0,0,global.inventoryObj[|q]). Have the objects in this inventoryObj list those variable defined and something assigned(for example the create event)? Because this is what you are calling.

That leads to two questions:
First: What does InvSelected actually do?
Second: What should be stored here( _info, etc). Something from the inventory objects or actually something from InvSelected or a string?
 
I do destroy InvSelect. It gets destroyed by pressing Q and then returns the option tool to the item you had selected(the main purpose for the saveChoice) variables.

InvSelect pops up another menu which gives you the choice to either eat the item, get some info on it, or drop the item. Pressing space on one of these options opens up a textbox, called Invformation(sorry for the confusion here)


This object is what is trying to retrieve the values from the what's in your inventory.
In var _info = global.selected.info I am trying to get a string, called info, out of the object that is currently selected, which should be stored in global.selected.

I kinda made it a bit more confusing earlier, but I did not put in any code from the InvSelect item. The first block is the inventory UI menu, which creates the selection tool. Using the selection tool, you create InvSelected then through InvSelected you create Invformation:

GML:
var cam_coordsx = camera_get_view_x(view_camera[0]);
var cam_coordsy = camera_get_view_y(view_camera[0]);
if(keyboard_check_pressed(ord("Q"))){
       instance_destroy();
}

if(keyboard_check_pressed(vk_space)){
    if(!instance_exists(Invfomation)){
        instance_create_depth(cam_coordsx+60,cam_coordsy,-12000,Invfomation)
        var listst = Invfomation.messages;
    }
}
(thanks for telling me how to add color :D)
the only other thing this object does is draw its own text in a draw event which is just:
GML:
draw_self();
draw_set_font(PixelArtFont);
draw_set_halign(fa_top);
draw_set_valign(fa_top);
var cam_coordsx = camera_get_view_x(view_camera[0]);
var cam_coordsy = camera_get_view_y(view_camera[0]);
var color = make_color_rgb(157,163,165)
//font color
draw_set_color(color);
//draw text
draw_text_ext(cam_coordsx+90,cam_coordsy+45,"Info\n\nConsume\n\nDrop",12,100);
the var _info etc block is stored in Invformation, the same as the block below it.
I did a little debugging earlier, and it seems like the game cannot find the object since the value stored in the global.item variable starts off with the correct id, but then adds 1 to the value every step event the inventory menu is open. I'm not sure what is causing this. I've put every piece of code that effects the global.item variables here, so there shouldn't be random object adding to it.


Hopefully this isn't confusing, I'm not too great at explaining things.

I'll try to add a little summary:
InvSelected allows you to either See info on the item, eat the item, or drop the item. Each item has a variable(not a local one just a normal one) called "info", "consume", and "drop". These are all set to a string i.e. the consume variable for a key is "Why would you want to eat this?" and the info variable is "A key that could unlock something." etc. All of this info is accessed by the Invformation instance, not InvSelected.

If it would help clarify more, I can provide a screenshot of the menu

Edit: I'm pretty sure the code block you originally gave me works perfectly fine for my situation.
GML:
//Create each object in your inventory
for(var q = 0; q < ds_list_size(global.inventoryObj); q++){

    //Setting each instance(!!) a variable
    global.item[q] = instance_create_depth(0,0,0,global.inventoryObj[|q]);
}
I think it's just the fact that 1 keeps getting added onto the instance ID causing it to not be the ID anymore and the game can't find the instance.
 
Last edited:

Vusur

Member
Hmmm...

I'm still confused because we stored the instance IDs in a global. Reading them shouldn't be a problem unless you are resetting global.selected. So if you say that the variables are set in the objects, you should be able to read them.

My advice would be debugging now. Set a break point somewhere here:

GML:
var _info = global.selected.info
var _consume = global.selected.consume;
var _drop = global.selected.drop;
Start the game in debugging (the little bug icon) and "play the game" until it stops. It opens the debugging view and at the bottom, there are some menues like "Variables" or "Instances". Inspect the variables and check, what values
global.selected has and what global.selected.info has. If it's gibberish, try right clicking and "view as ds_list" for lists as example.

Because you played your game until it stops, you will have an expectation. Values that should be there. Like you choosed key, so it should have those strings you mentioned.

There are three outcomes:
  1. You won't reach the break point and your game doesn't stop
  2. The values don't match your expectation
  3. The values are correct
If 1. happens, then there is something wrong before that point. You never execute this part of the code.
If 2. happens, then you might see why. Can you recognice those values? Is there an empty string? Usually check all spots, where you set this variable (i. e. in a different part of the game) and figure out, where the wrong values come from. Empty values/string can be a pain. Because resetting stuff to fast could be the reason or you thought you set them, but you didn't.
If 3. happens, then your logic is correct to this point and the error is the logic after this.

With that, you can slowly find the problem. It doesn't crash, right?
This is faster then me figuring out what to do, change your code and maybe run into the next problem due the changes.

The second breakpoint would be here global.item[q] = instance_create_depth(0,0,0,global.inventoryObj[|q]);. Go step by step through the loop and check global.items afterwards. First rightclick - view as - ds_list; then you see the list entries, then rightclick an entry - view as - instance. This will confirm or not, if my approach worked. Because you should see aaaaaallll the inventory objects with their info/consume/yada yada.

Those are also the only two spots I suspect.

I think it's just the fact that 1 keeps getting added onto the instance ID causing it to not be the ID anymore and the game can't find the instance.
That it adds 1 each loop is correct. Actually, this is a good sign, because that makes the objects and instances "different". This is just how GameMaker handles IDs. Objects start at 1 (?) and instances at 100001. Each new object or instance adds 1 for their own id.
 
Ok, I am beginning to understand this much better.

I went through the debugging and realized that like you said I am mixing up objects and instances. I am looking for the object ID in here:
GML:
var _info = global.selected.info
var _consume = global.selected.consume;
var _drop = global.selected.drop;
But I'm actually giving it the instance ID, so it can't find the object.

I edited this block of code from the option tool and changed the array/list it was referring to:

GML:
if(global.saveChoice == 0){
            global.selected = global.inventoryObj[|0]
        }
After I did that it was looking for the correct value.

And everything worked wonderfully! I think one of the main issues here is that I actually have a variable that keeps the object destroyed, so when you leave a room and come back it doesn't respawn. I'm gonna need to redo this system, but it shouldn't be that bad.

Thanks for putting all this time into helping me with this :D
 
Top