SOLVED How to use list for enemy pileup

Roastedzerg

Member
I'm trying to figure out whats going wrong with the enemy pileup code i made using the list data system. It looks like it almost works, as the enemies will sorta work at first and only a couple will attack the player while the others wait, but after about 3 seconds, sometimes immediately, they are all attacking at once. My guess is they are all trying to add themselves to the attack list at the same time and overriding the limit i have set. what might i be doing wrong in my code that could be allowing this to happen?

GML:
/// @function                   scr_pileup_check(player_number, estate, estate backup);
/// @param  {real}  player_number     player we are pileuping onto
/// @param  {real}  estate     state to switch to
/// @param  {real}  estate backup     state to switch to if we cant add id to list
function scr_pileup_check(argument0, argument1, argument2) {

    if(argument0==1)
    {
        if(ds_exists(global.p1_pileup_list,ds_type_list))
        {
            var id_index_check_p1=ds_list_find_index(global.p1_pileup_list,id);
            if(id_index_check_p1==-1)
            {
                if(ds_list_size(global.p1_pileup_list)<6){ds_list_add(global.p1_pileup_list,id);scr_state_switch(argument1);}
                else{if(argument2!=noone){scr_state_switch(argument2);}}
            }
            else{scr_state_switch(argument1);}
        }
        else{return false;}
    }


}

GML:
if(is_near_player)
            {
                if(my_target!=noone&&instance_exists(my_target))
                {
                    scr_pileup_check(my_target.player,estate_attack_basic,estate_idle);
                }
            }

GML:
function scr_pileup_delete() {
    if(ds_exists(global.p1_pileup_list,ds_type_list))
    {
        var id_index_check_p1=ds_list_find_index(global.p1_pileup_list,id);
        if(id_index_check_p1!=-1)
        {
            ds_list_delete(global.p1_pileup_list,id_index_check_p1);
        }
    }


}

GML:
//If we aren't attacking the player remove our id from the pileup lists
if(state!=estate_attack_basic&&state!=estate_attack_lunge)
{
    scr_pileup_delete();
}

My enemies run off a basic state system and when they are told to attack the player they use the pileup check script to see if they are allowed to attack, and if they aren't they go idle. Then, after a successful attack they find and delete their ID from the list to make room for the other enemies. Im trying to figure out how to keep the enemies from jumping into the list at the same time so the limit doesnt get passed in a single step.

Any suggestions? Let me know if i need to elaborate on anything or if something doesn't make sense so i can reword it.

Edit: I realized just now that if i could somehow figure out how to check the list size every few steps to see if its larger than the max size i could then figure out where the enemy executing the code is on the list. And if the enemy is positioned on the list past the max amount of slots on the list delete his slot. How could i go about doing this? Ill keep looking on my end.
 
Last edited:

TheouAegis

Member
Are the enemies being destroyed when they attack the player or at least moving away? These are melee attacks, I presume. There's no point to have the enemy remove itself from the list if it's still standing right next to the player. otherwise the enemy is going to attack, finish its attack, remove itself from the list, and still be standing right next to the player when the next enemy moves in for its attack. Just making sure that's not what's going on.
 

Nidoking

Member
I think the problem is that when the enemy deletes itself from the list, there doesn't seem to be anything setting its state back to the idle state.
 

Roastedzerg

Member
Are the enemies being destroyed when they attack the player or at least moving away? These are melee attacks, I presume. There's no point to have the enemy remove itself from the list if it's still standing right next to the player. otherwise the enemy is going to attack, finish its attack, remove itself from the list, and still be standing right next to the player when the next enemy moves in for its attack. Just making sure that's not what's going on.
So what im trying to get them to do, is attack, then go idle after attack with a timer to buffer till next attack and give other enemies the chance to attack. While the enemies are idle they have code that will push them away from each other and that will also push them away from the player. Hmmm maybe i outta check to make sure ive got a way to keep them from moving towards player if they are still buffering. Of course, that is only loosely connected to this issue, as they can move near him all they want for now, i just need them to take turns in attacking.


I think the problem is that when the enemy deletes itself from the list, there doesn't seem to be anything setting its state back to the idle state.
Oh yeah, i forgot to add this to my explanation:

GML:
//If we aren't attacking the player remove our id from the pileup lists
if(state!=estate_attack_basic&&state!=estate_attack_lunge)
{
    scr_pileup_delete();
}
And no, they are not being deleted, im just removing their instance ID from the list
 

Nidoking

Member
You might just want to use the debugger to look at the contents of the list when it's in the state where too many enemies are attacking. That will at least tell you whether the problem is in the list or the enemies.
 

Neptune

Member
I'm not sure, but this bit of pseudo-code / logic might help?

GML:
var attack_proximity = false;
with(obj_enemy)
{
    if point_dist < 100 && is_attacking {attack_proximity = true;} // a nearby enemy is already attacking ?
}

if (attack_ready && !attack_proximity)
{
    //attack!
}
If their attack speed is not VERY fast, than this method works surprisingly well because instance code runs in succession (like dominos) each step.
 
Last edited:

Roastedzerg

Member
After using the debugger i was able to determine that the enemies are some how bypassing the list check and going straight for the attack on the player. Ill update if i find anything off. Thanks for the suggestion @Nidoking
 

TheouAegis

Member
Are these all the same enemy object? Or are they different objects? I still can't find anything in your code that would cause that behavior other than:
  • One of your enemy objects has the attack state as argument2 due to a typo
  • Somehow global.p1_pileup_list is getting changed (watch the value in the Debugger as a normal variable, not a list)
 

Roastedzerg

Member
They are all separate objects running under the same parent object (obj_enemy_parent)
Ive already checked if any of them could be using argument2 instead of argument1 and didnt find anything suspicious, though i will definitely double check.
I do believe i was watching global.p1_pileup_list as a normal variable, and it didnt change from 1. To debug the list size i used a variable called global.p1_pileup_count and added 1 each time the enemies were supposed to add themselves to the list and subtracted 1 when they were to remove themselves. Oddly enough i found the number only changed rarely and the value changed at random. This tells me somehow they are bypassing the whole system, yet some of them will go through it. Odd. I will continue to look into this.
 

Roastedzerg

Member
Absolutely certain, ive even forced it to 1 to check
Edit: So it looks like when the enemies first pileup everything works, but a second or 2 later everyone is attacking so its breaking soon after starting the pileup for the first time but works initially.
 

Roastedzerg

Member
I fixed it, i needed to have my script scr_pileup_delete() execute after any code within the state that makes the enemy leave the attack or lunge attack state. Rather than checking outside the state systems if the enemy wasn't in the attack or lunge attack state and trying to delete them off the list there. As always, thanks for your help guys. You got me on the right track towards finding the solution. đź‘Ť
 
Top