Repeat for each Instance of "Object Group" doesn't allow different Variable Values

Dear GDevelop Community,

I am trying to put multiple similar Objects in a group to have a simpler code. Unfortunately it seems to work differently, than I expect.

I would like the PlayerUnit-Objects to move towards the EnemyUnit-Objects based on their AttackRange:


The Object Group PlayerUnits contains Objects with different Variables for their AttackRange (e.g. Archer.Stats.AttackRange = 600, Defender.Stats.AttackRange = 50).
The code works fine, once I remove the Archer-Object from the Object Group. As soon as the Group contains both Objects (Archer and Defender) they don’t move.
It also works, when I have different code snippets for each UnitType individually. That just doesn’t make use of the Object Group then.

(PS. Additionally: Right now I have all pathfinding, different states, attacks, movements etc. twice in my code. Once for all PlayerUnits, and once for all EnemyUnits. It’s the exact same code for both! Is there a way, that I can make my code work in both ways)

Any help is appreciated :slight_smile:

For your last question, if you have all pathfinding, different states, attacks, movements, etc for your PlayerUnits and EnemyUnits you can make a new group called Units, add all your PlayerUnits and EnemyUnits to that group and condense the code you have twice by changing it to apply to Units rather than once for PlayerUnits and the same again for EnemyUnits. It is ok to have objects that are already in a group, be in another different group of objects. It is very useful in many situations, for example when you want all MenuObjects to behave this way, but only the MenuButtons to behave this way, or whatever.

For your first question, you can successfully use objects that have different values of the same variable name in a single group. However, you will need to be more specific in your object picking in events so that GDevelop knows “which” group object you are talking about and “when” and can return the expected value at the correct time. For example I have SortableObjects group with all different values of the same variable names, but I only reference these values when an object is being dragged or was just dropped. This is very precise as only 1 object can be dragged at a time in my project, and there is never an issue of GDevelop not knowing which SortableObject I’m talking about, and just having to guess and pick a value from one of my SortableObjects to apply to all of them.

Your code as written works fine for me. You are saying if the PlayerUnit distance to the enemy is greater than their attack range, move to that enemy. Since there are defenders and archers on the scene and you have given it no more specific instructions on which one you are referring to, GDevelop picks one of their attack ranges to apply to all. In my case it picked the archer attack range. So only the PlayerUnits that are farther away than 600 pixels moved to my enemies. And all the PlayerUnits that were more than 600 pixels away move toward enemies, regardless of their actual defined range.

Then I took your distance condition and didn’t invert it, so now the PlayerUnit distance to the enemy is less than their range. This time GDevelop choose the lowest number, which is the Defender unit range, and applied to all. Now all my PlayerUnits less than 50 pixels away from the enemies moved toward them. (I changed mine to 100, 50 was just too tiny and was not working, and even at 100 I felt like the PlayerUnits had to be practically tripping over the enemy to notice them). So even though the archers have longer range, the game was checking to see if they were 100 pixels away and if they were more than that they didn’t move.

If I moved your condition of distance into the repeat for each PlayerUnit event, it worked as intended. But I think for performance reasons you are wanting it set up differently. Anyway just some thoughts on what is going on.

1 Like

Thank you sooo much! It felt great having that code working, after letting it aside for a few days :slight_smile: Moving the AttackRange-Condition into the ForEachInstance-Event worked! I will find another condition to tune performance!

About my second question there is probably a missunderstanding.
The code lines I am talking about regards the following:

ObjectGroup `PlayerUnits` walk to ObjectGroup `EnemyUnits`
ObjectGroup `PlayerUnits` stop walking when in Range to attack ObjectGroup `EnemyUnits`
ObjectGroup `PlayerUnits` attack ObjectGroup `EnemyUnits`

The second piece of code is the exact opposite:

ObjectGroup `EnemyUnits` walk to ObjectGroup `PlayerUnits`
ObjectGroup `EnemyUnits` stop walking when in Range to attack ObjectGroup `PlayerUnits` 
ObjectGroup `EnemyUnits` attack ObjectGroup `PlayerUnits`

So its excactly the same, but inverted. Ofcourse I have them all in one AllUnitsGroup as well for Y-Sort, Healthbars etc., but the objectpicking doesn’t allow me to do this more efficient, does it?

1 Like

Yeh my bad I misunderstood your second question, you are already doing what I mentioned with your AllUnits group. So I’m going to say there is probably a way to do what you actually meant, but I’m not coming up with anything. Hopefully someone else will know how to condense it.

I don’t know if you know how to write functions but you can create the move events as a function(s) and then call it using player, enemy and enemy, player.

Here’s an example using force. You can use any events. I named it MoveMe

It uses the parameters obj1, obj2 and speed.
This is the function

You would then call the function twice.
This is the scene event sheet

There might be another way to do this. I can’t think of one where you can flip the order of the objects.

I know you’re using the pathfinder. Behaviors can also be used in functions.

A behavior might be easier for some features although you would still need scene events to give it access to the other object. Unless there’s some way to assign the other object just once.

1 Like