GMS 2 dropping items from inventory into game world

afitgera

Member
Hi there. Have searched through the forums and so far been unable to find a solution to my problem so thought I would make a new thread. I apologise if this has been answered, but I was personally unable to find the answer.

So I have a working inventory system, and I am able to drop items into the game world by clicking rmb.

What I would like to do, is also have the option of dropping an item when clicking the lmb outside of the inventory UI.

My code looks like this:
Code:
//drop item into game world
    if(mouse_check_button_pressed(mb_right)){
        inv_grid[# 1, selected_slot] -= 1;
        //destroy item in inventory if it was the last one
        if(inv_grid[# 1, selected_slot] == 0) {
            inv_grid[# 0, selected_slot] = item.none;
        }
   
        //create the item
        var inst = instance_create_layer(obj_player.x, obj_player.y, "Instances", obj_item);
        with(inst){
            item_num = ss_item;
            x_frame = item_num mod (spr_width/cell_size);
            y_frame = item_num div (spr_width/cell_size);
        }
        show_debug_message("dropped an item.")
    }
I realise there may be variables etc there from the create event that aren't explained, and can provide other parts of the code upon request. As mentioned above, pressing the rmb does work and drop the item into the game world, I just would also like to be able to drop the item into the game world by clicking lmb, when the cursor is outside the inventory UI.

I feel like the solution lies somewhere with game makers device_mouse_x/y_to_gui function... and then setting conditions for outside the coords of the inventory UI, but I just can't get it to work.

I really appreciate any time anyone spends looking at this, regardless of if you have a solution or not. I realise any help given is out of the kindness of your heart, and I am not expecting or demanding anything at all.

I am just hoping someone more experienced than myself may have a clever way of editing the code to achieve the desired effect... I sure haven't been able to work it out.

either way, thanks for your time
 

roozilla

Member
Are you saying you want to right click the item and kind of have it attached to the mouse cursor and once you drag the item outside of the inventory window drop it into the game world once the left mouse button is clicked? I think Minecraft had similar behavior no? Or do you mean lmb drag the item and upon release it gets dropped into the game world?

Think of it like this:
Lmb is pressed - you can either destroy item or wait until your item is dragged outside of the inventory window.( I'd say wait until you release the lmb)
Lmb is released - Validate that the mouse.x and mouse.y is outside of your inventory window, destroy item in inventory and create instance in your game world.
If validation fails don't destroy item because it hasnt been dropped

You can store the item you lmb xlicked into a variable until lmb released happens upon release reset it to noone
 
Last edited:
N

NeonBits

Guest
(if you can already drop the item outside inventory)
how bout
Code:
   if ((mouse_check_button_pressed(mb_right)) || (mouse_check_button_pressed(mb_left)))
 

afitgera

Member
Are you saying you want to right click the item and kind of have it attached to the mouse cursor and once you drag the item outside of the inventory window drop it into the game world once the left mouse button is clicked? I think Minecraft had similar behavior no? Or do you mean lmb drag the item and upon release it gets dropped into the game world?

Think of it like this:
Lmb is pressed - you can either destroy item or wait until your item is dragged outside of the inventory window.( I'd say wait until you release the lmb)
Lmb is released - Validate that the mouse.x and mouse.y is outside of your inventory window, destroy item in inventory and create instance in your game world.
If validation fails don't destroy item because it hasnt been dropped

You can store the item you lmb xlicked into a variable until lmb released happens upon release reset it to noone
hello, absolute legend for replying. Thank you!

Yes, sort of like minecraft, except I do not want to have to hold down the lmb. At present, in the code, when I click on an item in the inventory with lmb, it attaches itself to the cursor, then, when lmb is pressed again within the inventory, it will attach itself to whatever slot the cursor was over in the inventory, with working stacking etc. What I want, is when lmb is pressed outside of the inventory UI, it performs a different action, it drops it into the game world, rather than into an inventory slot.

Not sure how well I am explaining myself, so here is more of the code, that dictates the picking up and putting down of items... (in fact, ill just drop the entire step event)

Code:
if(keyboard_check_pressed(ord("I"))) { show_inventory = !show_inventory; }

if(!show_inventory) exit;

mousex = device_mouse_x_to_gui(0);
mousey = device_mouse_y_to_gui(0);

var cell_xbuff = (cell_size + x_buffer)*scale;
var cell_ybuff = (cell_size + y_buffer)*scale;

var i_mousex = mousex - slots_x;
var i_mousey = mousey - slots_y;

var nx = i_mousex div cell_xbuff;
var ny = i_mousey div cell_ybuff;

if(nx >= 0 and nx < inv_slots_width and ny >= 0 and ny < inv_slots_height and i_mousey > 0 and i_mousex > 0){
    var sx = i_mousex - (nx*cell_xbuff);
    var sy = i_mousey - (ny*cell_xbuff);
    
    if((sx < cell_size*scale) and ( sy < cell_size*scale)){
    m_slotx = nx;   
    m_sloty = ny;
    }
}

//set sekected slot to mouse position
selected_slot = min(inv_slots -1, m_slotx + (m_sloty*inv_slots_width));

//pick up item

var inv_grid = ds_inventory;
var ss_item = inv_grid[# 0, selected_slot];

if(pickup_slot != -1){
    if(mouse_check_button_pressed(mb_left)){
        if(ss_item == item.none){
            inv_grid[# 0, selected_slot] = inv_grid[# 0, pickup_slot];
            inv_grid[# 1, selected_slot] = inv_grid[# 1, pickup_slot];
            
            inv_grid[# 0, pickup_slot] = item.none;
            inv_grid[# 1, pickup_slot] = 0;
            
            pickup_slot = -1;
        
        } else if (ss_item == inv_grid[# 0, pickup_slot]){
            if (selected_slot != pickup_slot){
                inv_grid[# 1, selected_slot] += inv_grid[# 1, pickup_slot];
                inv_grid[# 0, pickup_slot] = item.none;
                inv_grid[# 1, pickup_slot] = 0;
            }
            
            pickup_slot = -1;
        } else {
            var ss_item_num = inv_grid[# 1, selected_slot];
            inv_grid[# 0, selected_slot] = inv_grid[# 0, pickup_slot];
            inv_grid[# 1, selected_slot] = inv_grid[# 1, pickup_slot];
            
            inv_grid[# 0, pickup_slot] = ss_item;
            inv_grid[# 1, pickup_slot] = ss_item_num;
            
            pickup_slot = -1;
        }
    }   
}   

else if(ss_item != item.none){
    //drop item into game world
    if(mouse_check_button_pressed(mb_right)){
        inv_grid[# 1, selected_slot] -= 1;
        //destroy item in inventory if it was the last one
        if(inv_grid[# 1, selected_slot] == 0) {
            inv_grid[# 0, selected_slot] = item.none;
        }
    
        //create the item
        var inst = instance_create_layer(obj_player.x, obj_player.y, "Instances", obj_item);
        with(inst){
            item_num = ss_item;
            x_frame = item_num mod (spr_width/cell_size);
            y_frame = item_num div (spr_width/cell_size);
        }
        show_debug_message("dropped an item.")
    }
    
    //dropping picked up item into new slot
    if(mouse_check_button_pressed(mb_left)){
        pickup_slot = selected_slot;
    }
}
I am sure the solution to this is, in fact, not overly complex, I just dont understand the language well enough to tell the program what I want it to do lol, anyways, cheers, champion for taking the time to reply, let me know if you have any ideas.
 

afitgera

Member
(if you can already drop the item outside inventory)
how bout
Code:
   if ((mouse_check_button_pressed(mb_right)) || (mouse_check_button_pressed(mb_left)))
hey there, thanks so much for replying, you have taught me something, I did not know I could use "||' in that manner. In this case, simply clicking lmb is not going to achieve the desired effect, because I only want it to drop the item into the game world when lmb is pressed when the cursor coords are outside of the inventory UI.

legend for replying, thank you so much, let me know if you have any other ideas.

see my reply to roozilla for the entire step event code if it helps. I dont have much experience with the language, so I know what I want to do, but just don't know how to tell game maker to do it lol.
 

roozilla

Member
If you have a variable set equal to your inventory item on lmb click then you need to add a different check to verify that the item is outside of your inventory window. Instead of validating item movement within your inventory window validate that the item is not in the window so that you can create it within the game world.

Aalso it looks like you have a portion with rmb that creates an instance in your game world. You could change that to fit your needs just create a script that validates that the mouse.x and mouse.y is not within your inventories grid. You need to know where your inventories x and y coordinates are for each corner.
 
Last edited:

JQ4386

Member
Hi guys, I have a similar type of problem (I watched the same tutorial that afitgera did, so our script is pretty much identical).
When I press the "drop" button, my item does drop into the game world, but it creates 2 copies instead of 1.
Can someone please help me with this?
Thanks! :D
 

Roldy

Member
Hi guys, I have a similar type of problem (I watched the same tutorial that afitgera did, so our script is pretty much identical).
When I press the "drop" button, my item does drop into the game world, but it creates 2 copies instead of 1.
Can someone please help me with this?
Thanks! :D
I think you would need to provide more information.

Maybe post the code where you 'drop' the item and the code that triggers it.
 

JQ4386

Member
//Drop item into game world
if (mouse_check_button_pressed(mb_middle))
{
inv_grid[# 1, selected_slot] -= 1;
//destory item in inventory if it was the last one
if (inv_grid[# 1, selected_slot] == 0)
{
inv_grid[# 0, selected_slot] = item.none;
}
//create the item
var inst = instance_create_layer(oPlayer.x, oPlayer.y,"Items",oItem);
with (inst)
{
item_num = ss_item;
x_frame = item_num mod (spr_width/cell_size);
y_frame = item_num div (spr_width/cell_size);
}
show_debug_message("Dropped an Item.");
}

Is this enough code? I'm a beginner so I don't know how much you would need xD
 
So you can't just check if the mouse button is pressed, you need to also check to see if the cursor is hovering over an inventory slot. My assumption is that this section of code deals with whether the mouse is hovering an inventory slot or not:
Code:
if(nx >= 0 and nx < inv_slots_width and ny >= 0 and ny < inv_slots_height and i_mousey > 0 and i_mousex > 0){
    var sx = i_mousex - (nx*cell_xbuff);
    var sy = i_mousey - (ny*cell_xbuff);
    
    if((sx < cell_size*scale) and ( sy < cell_size*scale)){
    m_slotx = nx;   
    m_sloty = ny;
    }
}
So I would rewrite that section to something like this:
Code:
var inv_hovered = false;
if(nx >= 0 and nx < inv_slots_width and ny >= 0 and ny < inv_slots_height and i_mousey > 0 and i_mousex > 0){
    var sx = i_mousex - (nx*cell_xbuff);
    var sy = i_mousey - (ny*cell_xbuff);
    
    if((sx < cell_size*scale) and ( sy < cell_size*scale)){
    m_slotx = nx;   
    m_sloty = ny;
    inv_hovered = true;
    }
}
If that code section is the section that determines if the mouse is hovering a slot, then what this does is set a local variable called inv_hovered to false. It then sets inv_hovered to true if sx and sy are within the bounds of a cell, otherwise, inv_hovered remains false. Then later on when you want to drop you simply check for inv_hovered along with the left mouse button check:
Code:
    if(mouse_check_button_pressed(mb_right) || (mouse_check_button_pressed(mb_left) && inv_hovered == false)){
        inv_grid[# 1, selected_slot] -= 1;
        //destroy item in inventory if it was the last one
        if(inv_grid[# 1, selected_slot] == 0) {
            inv_grid[# 0, selected_slot] = item.none;
        }
    
        //create the item
        var inst = instance_create_layer(obj_player.x, obj_player.y, "Instances", obj_item);
        with(inst){
            item_num = ss_item;
            x_frame = item_num mod (spr_width/cell_size);
            y_frame = item_num div (spr_width/cell_size);
        }
        show_debug_message("dropped an item.")
    }
The positioning of where you are setting inv_hovered is key. If I'm wrong in my assumption, you'll have to find the code block that actually tells the mouse if it is hovering an inventory item (that code is definitely already there, otherwise you would not be able to click on items at all) and set inv_hovered to false before that block and then set it to true inside the check for the mouse hovering an item is done.
 

JQ4386

Member
Hi Refresher Towel, I tried adding in the variable "hover" but it didn't seem to solve the problem. What do you think might have caused the double item creation?
 
What do you mean by double item creation? Is this something new since you changed your code or is this a problem that has been happening the whole time?
 

TailBit

Member
It sounds like there could be 2 inventory objects in the room, and you don't have any check that would stop the other one, like checking if slot is empty. (but if there are 2 then something is wrong)
 

Yal

šŸ§ *penguin noises*
GMC Elder
What I would like to do, is also have the option of dropping an item when clicking the lmb outside of the inventory UI.
Use the "Global right clicked" mouse event (which triggers if you click ANYWHERE) and then just check that you currently aren't hovering the inventory UI.
 
Top