multiple Item drops in position of enemy being destroyed (SOLVED)

iBack

Member
Hi, I'm still new to GML and I need help with multiple coin drops in position of where the enemy is destroyed.
I have achieved this in some way, once I destroy multiple enemy in radius coins is dropped in its destroyed position however some times more coins is dropped in another position after the enemies are destroyed.

Here is the code in the collision event:


GML:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);


if _num > 0
    {
    for (var i = 0; i < _num; ++i;)
        {
          

        with (obj_enemy){
              
          
            if (invincible = false) {
            instance_create_layer(x,y,"CoinPickup",obj_coin2);
             instance_destroy(_list[| i]);
          
            }
          
          
            }
          
        }
    }
  
  

ds_list_destroy(_list);
as you can see this works once I create a instance_create_layer.

the problem i have is, some times once i destroy the instance the coins appear in position of enemy being destroyed but coins will also appear across the stage (no the radius of the attack does not reach that side of the stage so i dont understand why more coins are appearing).

Hope someone can help. Thank you.
 
Last edited:

Xer0botXer0

Senpai
You say coins are sometimes spawning outside of the radius of the dead enemy, the enemy is called obj_enemy, which is what you're referencing in that code there..

I believe when you reference the object itself rather than the instance, you may get a random instance ID instead of the specific one you're looking for.
In this scenario it would mean that the coins are spawning near a different enemy instance.
 

Simon Gust

Member
The base of the idea is fine but the execution doesn't quite do what you think it does.
You want to change the scope using the with() statement, which is fine. But you need to submit an id instead of an object_index, as now you are looping over every enemy, no matter if it was hit or not.
Basically, it's creating a lot more coins that it should.
The id you wanted to input in with is already stored in _list[| i].
Code:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);
if _num > 0
{
    for (var i = 0; i < _num; ++i;)
    {
        var current_enemy = _list[| i];
        with (current_enemy) 
        {
            if (invincible == false) 
            {
                instance_create_layer(x,y,"CoinPickup",obj_coin2);
                instance_destroy(current_enemy);
            }
        }
    }
}
ds_list_destroy(_list);
 

iBack

Member
The base of the idea is fine but the execution doesn't quite do what you think it does.
You want to change the scope using the with() statement, which is fine. But you need to submit an id instead of an object_index, as now you are looping over every enemy, no matter if it was hit or not.
Basically, it's creating a lot more coins that it should.
The id you wanted to input in with is already stored in _list[| i].
Code:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);
if _num > 0
{
    for (var i = 0; i < _num; ++i;)
    {
        var current_enemy = _list[| i];
        with (current_enemy)
        {
            if (invincible == false)
            {
                instance_create_layer(x,y,"CoinPickup",obj_coin2);
                instance_destroy(current_enemy);
            }
        }
    }
}
ds_list_destroy(_list);
When you say 'current_enemy', what do you mean? all i know is the object name, so in this case obj_enemy.



GML:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);


if _num > 0
    {
    for (var i = 0; i < _num; ++i;)
        {
           
            //instance_destroy(__list);
        with (obj_enemy)
               
            var current_enemy = _list[| i];
            if (invincible == false) {
            instance_create_layer(x,y,"CoinPickup",obj_coin2);
              instance_destroy(current_enemy);
           
            }
           
           
            }
           
        }
    }
   
   

ds_list_destroy(_list);
If i use this example i get the same problem with coins appearing outside where the enemies are destroyed, remember the coins should only drop in position of where the enemies are destroyed in their respected position, so if 4 enemies are destroyed, 4 coins in their last positon should appear (which does happen) but its just more appears outside this area and i just dont understand.

If i then use your solution, the game starts however, once i attack the enemy the game freezes and says, "

___________________________________________
############################################################################################
ERROR in
action number 1
of Step Eventobj_enemy
for object water_balloon_test:

local variable <unknown built-in variable>(-1610512629, -2147483648) not set before reading it.
at gml_Object_water_balloon_test_Collision_obj_enemy (line 15) - with (current_enemy){
############################################################################################
gml_Object_water_balloon_test_Collision_obj_enemy (line 15)"
 

iBack

Member
The base of the idea is fine but the execution doesn't quite do what you think it does.
You want to change the scope using the with() statement, which is fine. But you need to submit an id instead of an object_index, as now you are looping over every enemy, no matter if it was hit or not.
Basically, it's creating a lot more coins that it should.
The id you wanted to input in with is already stored in _list[| i].
Code:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);
if _num > 0
{
    for (var i = 0; i < _num; ++i;)
    {
        var current_enemy = _list[| i];
        with (current_enemy)
        {
            if (invincible == false)
            {
                instance_create_layer(x,y,"CoinPickup",obj_coin2);
                instance_destroy(current_enemy);
            }
        }
    }
}
ds_list_destroy(_list);
you said "you need to submit an id instead of an object_index". where do i find the id?
 

Simon Gust

Member
When you type with (obj_enemy)
Everything inside the next { and } will run inside every instance of obj_enemy. It doesn't matter if they were in that list you generated, they will run regardless.
That's why you made the list in the first place, so you know which enemy isntances are hit.
ID is a unique identifier for every instance. One enemy could have the id 100001, another could have 100014 and so on.
With these IDs you can directly alter instances like setting hp of a single enemy or in your case spawn a coin at that enemy's x and y.

Example
Code:
var enemy = instance_place(x, y + 20, obj_enemy);
the code I have written will try to find an enemy instance 20 pixels below the player. If an enemy is found, the variable "enemy" will hold the ID of that enemy instance.

Code:
var enemy = instance_place(x, y + 20, obj_enemy);
with (enemy)
{
   y -= 100;
}
Using the with() statement I can get access to that enemy instance's y variable.
Alternatively
Code:
var enemy = instance_place(x, y + 20, obj_enemy);
enemy.y -= 100;
does the same thing. (without guarantee of not getting errors)

There are some functions that will specifically you the id of an instance.
Such as instance_place(), instance_position(), collision_line() and some more.
Then there are functions like collision_circle_list() which will put ids in a provided list.
To access every id in that list you use a for-loop (to loop through the list).
Code:
for (var i = 0; i < _num; ++i;)
{

}
here "i" is the current iteration or position of the list the code is in.
Then you take out the id of the list like this
Code:
var current_enemy = _list[| i];
And now, "current_enemy" (you can name it what you want) holds an id of an enemy.
Now you can use a with() statement as shown above to alter that enemy's code and make him do things. Without having to write this inside the code of obj_enemy.
 

iBack

Member
When you type with (obj_enemy)
Everything inside the next { and } will run inside every instance of obj_enemy. It doesn't matter if they were in that list you generated, they will run regardless.
That's why you made the list in the first place, so you know which enemy isntances are hit.
ID is a unique identifier for every instance. One enemy could have the id 100001, another could have 100014 and so on.
With these IDs you can directly alter instances like setting hp of a single enemy or in your case spawn a coin at that enemy's x and y.

Example
Code:
var enemy = instance_place(x, y + 20, obj_enemy);
the code I have written will try to find an enemy instance 20 pixels below the player. If an enemy is found, the variable "enemy" will hold the ID of that enemy instance.

Code:
var enemy = instance_place(x, y + 20, obj_enemy);
with (enemy)
{
   y -= 100;
}
Using the with() statement I can get access to that enemy instance's y variable.
Alternatively
Code:
var enemy = instance_place(x, y + 20, obj_enemy);
enemy.y -= 100;
does the same thing. (without guarantee of not getting errors)

There are some functions that will specifically you the id of an instance.
Such as instance_place(), instance_position(), collision_line() and some more.
Then there are functions like collision_circle_list() which will put ids in a provided list.
To access every id in that list you use a for-loop (to loop through the list).
Code:
for (var i = 0; i < _num; ++i;)
{

}
here "i" is the current iteration or position of the list the code is in.
Then you take out the id of the list like this
Code:
var current_enemy = _list[| i];
And now, "current_enemy" (you can name it what you want) holds an id of an enemy.
Now you can use a with() statement as shown above to alter that enemy's code and make him do things. Without having to write this inside the code of obj_enemy.
What would be the best way for me to go about doing this?
because the code i wrote works, its just some times coins appear in another area.
 

Simon Gust

Member
As I expected, when you shoot that crystal (I guess), a coin spawns on every enemy.
This is because you're using the with (obj_enemy) instead of with (_list[| i]).

Code:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);
if _num > 0
{
    for (var i = 0; i < _num; ++i;)
    {
        with (_list[| i]) 
        {
            if (invincible == false) 
            {
                instance_create_layer(x, y, "CoinPickup", obj_coin2);
                instance_destroy();
            }
        }
    }
}
ds_list_destroy(_list);
or if you just don't want to use the with statement
Code:
var _list = ds_list_create();
var _num = collision_circle_list(x, y, 200, obj_enemy, false, true, _list, false);
if _num > 0
{
    for (var i = 0; i < _num; ++i;)
    {
        var enemy = _list[| i];
        if (enemy.invincible == false)
        {
            instance_create_layer(enemy.x, enemy.y, "CoinPickup", obj_coin2);
            instance_destroy(enemy);
        }
    }
}
ds_list_destroy(_list);
 

iBack

Member
Thank you, putting the variable on "with (_list [ | i])"; this worked (since like you've explained, this includes the id of the instance index ). thank you very much for the help.
 
Top