GMS 2.3+ How to make sure the player is carrying two objects at once?

ElCheTibo

Member
I'm currently working on a game project that let the player carry two objects at once in his hands. It's a 2D platformer and I've already figured out most of the code by myself.
Everything is working pretty well but when I try to pick up two objects, the first object disappeared and is replaced with the second one...

A Reddit user suggested me to put the following lines in my code :
GML:
// CREATE EVENT
swords = [2];
nbOfSwords = 0;

// STEP EVENT
// Picking up swords

var _len = array_length(swords);
if pickUp // 'E' is pressed and the object is picked up
{
    if _len < 2
    {
        var _pick_up_dist = 32;
        var _nearest_dist = _pick_up_dist;
        var _nearest_bottle = noone;
        // Look for nearest sword to pick up
        for(var i = 0; i < instance_number(oSword); i++) {
            var _sword = instance_find(oSword, i);
           
            show_debug_message("_sword typeof: " + typeof(_sword)); // These lines are just
            show_debug_message("_sword: " + string(_sword)) // for debugging purposes
           
            if _sword.pickedUp
            {
                continue;
            }
            var _dist = point_distance(x, y, _sword.x, _sword.y);
            if _dist < _nearest_dist
            {
                _nearest_dist = _dist;
                _nearest_sword = _sword;
            }
        }
        // Found the nearest sword, add to swords[]
        if _nearest_sword
        {
            swords[_len] = _nearest_sword;
            _nearest_sword.pickedUp = true; // a bool in the Create event of oSword
        }
    }
}
// Moving picked up swords to hand positions
var _dist = 15;
for(var i = 0; i < _len; i++) {
    _sword.x = x + _dist - (_dist * 2 * i); // x position
    _sword.y = y + _dist; // y position
}
The majority of the code is running correctly but the "moving the objects to hands" is where the issue is.
When I try to run the project, the debug pop-up says :
local variable <unknown built-in variable>(-1610512697, -2147483648) not set before reading it.
at gml_Object_oPlayer_Step_0 (line 81) - _sword.x = x + _dist - (_dist * 2 * i); // x position
After some troubleshooting, I've noticed that the problem is the ".x" and ".y" that follows the "_sword".
I cannot think of another solution to place them in the player's hands, because that may be too advanced for my beginner level

Can you help me to fix these pesky bugs ? It's been bothering me for days now...
 
Last edited:

Umaro

Member
Local variables are deleted automatically (your sword object is one), plus it seems like there could be some situations where the object isn't even created, since the creation code is inside an if statement but the movement code is outside of it.
 

Nidoking

Member
You didn't define _sword in the for loop. You shouldn't need to, since they're in the swords array, and that's what you'll want to use. You also didn't update _len after adding to the array, so it's going to be missing the last element.
 

ElCheTibo

Member
Update: I rewrote the code without the array sytem. It's working correctly but the swords either won't follow the player's movement or disappears after the player picks up another sword :/
 

Nidoking

Member
Which is accurate? Is it working correctly, or is there a problem as you described in the very next sentence?

Also, if you've rewritten the code, then what you've posted here is no longer representative of what you're working with, so you'll have to show what you've done if you want anyone to help you.
 

ElCheTibo

Member
Which is accurate? Is it working correctly, or is there a problem as you described in the very next sentence?

Also, if you've rewritten the code, then what you've posted here is no longer representative of what you're working with, so you'll have to show what you've done if you want anyone to help you.
My bad

Here is the oPlayer code

GML:
// Create event

nbOfSwords = 0;

// Step event

var _pick_up_dist = 64;
var _nearest_sword = instance_nearest(x, y, oSword);
var _dist = 15;

if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, oSword)) && (pickUp) // pickUp = keyboard_check(ord("E"))
{   
    var _sword = _nearest_sword;
    
    if (nbOfSwords < 0)
    {
        nbOfSwords = 0;
    }
    else if (nbOfSwords > 2)
    {
        nbOfSwords = 1;
    }
}
and the oSword code

GML:
// Step event (there's nothing in the Create event)

switch (oPlayer.nbOfSwords)
{
    case 1:
        x = oPlayer.x + 15;
        y = oPlayer.y + 15;
        break;   
            
    case 2:
        x = oPlayer.x - 15;
        y = oPlayer.y + 15;
        // For some reason, it doesn't work well when I put a break instruction here
}
What I want to do, is to make sure both swords instances coexists in the player's hands and them to follow the player's movement.

For now I managed to make one sword at a time stick to the player's hand, but as soon as he pick another one, the first sword disappears
 

Nidoking

Member
switch (oPlayer.nbOfSwords)
Both swords are doing this. How many different numbers of swords can the player have at the same time? I don't mean "the player can have zero, one, or two swords, so three options". I mean how many of those three options can the player have at the same time? Can the player have one sword and also, at the same time, have two swords?
 
My bad

Here is the oPlayer code

GML:
// Create event

nbOfSwords = 0;

// Step event


////////////////////////////////////////////////////////////////////////
var _pick_up_dist = 64;                                                      ///////////
var _nearest_sword = instance_nearest(x, y, oSword);           /////////////////// Put this stuff INSIDE your if statement at the beginning of it, it doesn't need run every frame
var _dist = 15;                                                                  /////////////
////////////////////////////////////////////////////////////////////////
if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, oSword)) && (pickUp) // pickUp = keyboard_check(ord("E"))         //////////////Change this for just if(pickUp), and check for place meeting in a next if statement inside of it
{ 
    var _sword = _nearest_sword;
  
    if (nbOfSwords < 0)
    {                   
        nbOfSwords = 0;
    }
    else if (nbOfSwords > 2)
    {
        nbOfSwords = 1;
    }                                             ////////////////What happens if nbOfSwords == 0, 1 or 2?!? This code returns true from -0.0000000000001 downwards and from 2.0000000001 upwards, but says nothing about what to do if I have 0, 1 or 2 swords.
}
I added comments to your code. Just ask if you have any questions about it! :)
 

ElCheTibo

Member
Both swords are doing this. How many different numbers of swords can the player have at the same time? I don't mean "the player can have zero, one, or two swords, so three options". I mean how many of those three options can the player have at the same time? Can the player have one sword and also, at the same time, have two swords?
The player can have up to 2 swords in both hands. It's either 0, 1 or 2 swords.

I added comments to your code. Just ask if you have any questions about it! :)
You suggested me to put the if (place_meeting) inside the if (pickUp) statement. But why, and how should it work? Which condition would the game check first? I tried your suggestion but the issue stays the same

I wrote the nbOfSwords as a switch statement and moved it into the Step event of oPlayer :

GML:
switch (nbOfSword)
{
    case 1:
        _sword.x = x + _dist;
        _sword.y = y + _dist;
        break;   
            
    case 2:
        _sword.x = x - _dist;
        _sword.y = y + _dist;
}
 

Nidoking

Member
The player can have up to 2 swords in both hands. It's either 0, 1 or 2 swords.
You gave me exactly the answer I said I didn't want. I'm asking is it possible for the player to have one sword AND two swords at the same time? Because you've done this:
switch (oPlayer.nbOfSwords)
Suppose the player has two swords. When the first sword determines its position, how many swords does the player have? When the second sword determines its position, how many swords does the player have?
 
You wrote this:
GML:
////////////////////////////////////////////////////////////////////////
var _pick_up_dist = 64;                                                      ///////////
var _nearest_sword = instance_nearest(x, y, oSword);           /////////////////// Put this stuff INSIDE your if statement at the beginning of it, it doesn't need run every frame
var _dist = 15;                                                                  /////////////
////////////////////////////////////////////////////////////////////////
if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, oSword)) && (pickUp) // pickUp = keyboard_check(ord("E"))         //////////////Change this for just if(pickUp), and check for place meeting in a next if statement inside of it. Also, what happens if we are 60 pixels TO THE RIGHT or UNDER  the sword (sword is NOT between x and x+64 then) That code wont run ;) (hint, hint)
{
    var _sword = _nearest_sword;

    if (nbOfSwords < 0)
    {               
        nbOfSwords = 0;
    }
    else if (nbOfSwords > 2)
    {
        nbOfSwords = 1;
    }                                             ////////////////What happens if nbOfSwords == 0, 1 or 2?!? This code returns true from -0.0000000000001 downwards and from 2.0000000001 upwards, but says nothing about what to do if I have 0, 1 or 2 swords.
}
With my suggestions, it would look like this:
GML:
if(pickUp){     //If you press E

   var _pick_up_dist = 64;       //Notice how all this code now runs ONLY if you press "E", and not 60 times per seconds
   var _nearest_sword = instance_nearest(x, y, oSword);   
   var _dist = 15;                                                     

//This will still bug if you are to THE RIGHT of the sword, tho, you have to check if it's between x-pick_up_dist and x+pick_up_dist. Same for y.
   if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, _nearest_sword ))       //Now that we know we pressed E, it's time to check for a collision, which is taxing on the computer. Your game may run slow if you have too many collisions check. We check for only one instance of sword (the nearest), instead of going through them all
   {
      // var _sword = _nearest_sword;       //This variable is a duplicate of _nearest_sword, we don't need it

   //Now I would get rid of this whole shady and pretty useless if statement for a clean, nice switch like this. Sorry, I don't knoiw how to indent code in this thing, tab will **** my things up.
      switch(nbOfSwords) {
      case 0:
         //what to do if you have 0 swords
         break;

     case 1:
        //what to do if you have 1 swords
        break;

     case 2:
     //what to do if you have 2 swords
     break;
     }
  }   //Dont forget to close everything, this is the closing bracket of if (place_meeting)
}//This is the closing bracket of if(pickUp)
The reson why move it is, as I wrote in the comment of my version, it prevents a lot of checks every step. This way, the step event only checks if you pressed the E key, and ONLY runs the rest of the code if that's the case.
You don't really need to know where the nearest sword is when you're running, hacking bad guys and jumping around, do you? Well, that code you were doing was doing that. One of the basics is to never run code unless you need to, especially code like collision check, which is a cpu burden compared to checking an input. Hope that makes sense to you

And the last part I ditched altogether to replace for a nice switch statement. I assumed you could ONLY have 0, 1 or 2 swords, but if not, just add/remove cases accordingly.
I suggest you use switch whenever you can if you're going to have more than 2 "elses" in a "if" statement. Sometimes not possible, but most of the time it is.
 
Last edited:

ElCheTibo

Member
You gave me exactly the answer I said I didn't want. I'm asking is it possible for the player to have one sword AND two swords at the same time? Because you've done this:


Suppose the player has two swords. When the first sword determines its position, how many swords does the player have? When the second sword determines its position, how many swords does the player have?
I'm sorry to misunderstand you. English is not my first language so I didn't know what were you trying to say to me.
To answer your question, the first sword determines its own position and the number of swords the player have. The sword's positions are based on the number of swords.

You wrote this:
GML:
////////////////////////////////////////////////////////////////////////
var _pick_up_dist = 64;                                                      ///////////
var _nearest_sword = instance_nearest(x, y, oSword);           /////////////////// Put this stuff INSIDE your if statement at the beginning of it, it doesn't need run every frame
var _dist = 15;                                                                  /////////////
////////////////////////////////////////////////////////////////////////
if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, oSword)) && (pickUp) // pickUp = keyboard_check(ord("E"))         //////////////Change this for just if(pickUp), and check for place meeting in a next if statement inside of it. Also, what happens if we are 60 pixels TO THE RIGHT of the sword (sword is NOT between x and x+64 then) That code wont run ;) (hint, hint)
{
    var _sword = _nearest_sword;

    if (nbOfSwords < 0)
    {               
        nbOfSwords = 0;
    }
    else if (nbOfSwords > 2)
    {
        nbOfSwords = 1;
    }                                             ////////////////What happens if nbOfSwords == 0, 1 or 2?!? This code returns true from -0.0000000000001 downwards and from 2.0000000001 upwards, but says nothing about what to do if I have 0, 1 or 2 swords.
}
With my suggestions, it would look like this:
GML:
if(pickUp){     //If you press E

   var _pick_up_dist = 64;       //Notice how all this code now runs ONLY if you press "E", and not 60 times per seconds
   var _nearest_sword = instance_nearest(x, y, oSword);   
   var _dist = 15;                                                     

//This will still bug if you are to THE RIGHT of the sword, tho, you have to check if it's between x-pick_up_dist and x+pick_up_dist. Same for y.
   if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, _nearest_sword ))       //Now that we know we pressed E, it's time to check for a collision, which is taxing on the computer. Your game may run slow if you have too many collisions check. We check for only one instance of sword (the nearest), instead of going through them all
   {
      // var _sword = _nearest_sword;       //This variable is a duplicate of _nearest_sword, we don't need it

   //Now I would get rid of this whole shady and pretty useless if statement for a clean, nice switch like this. Sorry, I don't knoiw how to indent code in this thing, tab will **** my things up.
      switch(nbOfSwords) {
      case 0:
         //what to do if you have 0 swords
         break;

     case 1:
        //what to do if you have 1 swords
        break;

     case 2:
     //what to do if you have 2 swords
     break;
     }
  }   //Dont forget to close everything, this is the closing bracket of if (place_meeting)
}//This is the closing bracket of if(pickUp)
The reson why move it is, as I wrote in the comment of my version, it prevents a lot of checks every step. This way, the step event only checks if you pressed the E key, and ONLY runs the rest of the code if that's the case.
You don't really need to know where the nearest sword is when you're running, hacking bad guys and jumping around, do you? Well, that code you were doing was doing that. One of the basics is to never run code unless you need to, especially code like collision check, which is a cpu burden compared to checking an input. Hope that makes sense to you

And the last part I ditched altogether to replace for a nice switch statement. I assumed you could ONLY have 0, 1 or 2 swords, but if not, just add/remove cases accordingly.
I suggest you use switch whenever you can if you're going to have more than 2 "elses" in a "if" statement. Sometimes not possible, but most of the time it is.
Thanks a lot for your explanations. I rearranged my code, now it looks like this :
GML:
var _nearest_sword = instance_nearest(x, y, oSword);
var _sword = _nearest_sword;
var _dist = 15;

if (pickUp)
{   
    var _pick_up_dist = 64;
    
    if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, _nearest_sword)) && (place_meeting(x - _pick_up_dist, y - _pick_up_dist, _nearest_sword))
    {
        nbOfSwords++;
        switch (nbOfSwords)   
        {
            case 1:
                _sword.x = x + _dist;
                _sword.y = y + _dist;
                break;   

            case 2:
                _sword.x = x - _dist;
                _sword.y = y + _dist;
                break;
        
            case 3:
                nbOfSwords = 1;
                break;
        
            default:
                nbOfSwords = 0;
                break;
        }   
    }
}
It sure looks more clean !
Unfortunately, the swords still don't coexist within the player's hands :confused:
 
Thanks a lot for your explanations. I rearranged my code, now it looks like this :
GML:
if (place_meeting(x + _pick_up_dist, y + _pick_up_dist, _nearest_sword))
You did not fix this part. What if it's 63 pixels BEHIND me? or OVER me? you only check for x+64 and y+64.
Make it a rectangle around the player, or something man. Aside from doing it all for you, I can't really do more than telling you where the bugs are!

And you did it wrong.
You STILL check for instance_nearest EVERY STEP. You STILL have a dublicate variable.
GML:
var _nearest_sword = instance_nearest(x, y, oSword);
var _sword = _nearest_sword;
var _dist = 15;
This goes INSIDE the if(pickup)
Are you sure both _nearest_sword and _sword are both local variables?
 
Last edited:

Nidoking

Member
I'm sorry to misunderstand you. English is not my first language so I didn't know what were you trying to say to me.
To answer your question, the first sword determines its own position and the number of swords the player have. The sword's positions are based on the number of swords.
Yes. The swords' positions are based on the number of swords. If you have one sword, it will be at x + _dist, y + _dist. If you have two swords, they will be at x - _dist, y + _dist. When you have two swords, you have two swords. When you have two swords, you do not have one sword, because you have two swords. You cannot have one sword at the same time as you have two swords. You have two swords. So, you do not have one sword. You instead have two swords. Since you do not have one sword, the swords will not be in the position where they would be if you had one sword. They will only be in the position where they would be if you had one sword if you have one sword. But when you have two swords, you do not have one sword, because you have two swords. Do you understand?
 
Top