Enemy can't avoid members of a Group if it is also a member.

I want all enemies to avoid physical objects.

I put all physical objects in a group called “Solid”.

I tested this idea with only one enemy in a scene.

I used this code (I replaced For each objects “Base” with For each objects “Solid”):
forum.compilgames.net/viewtopic. … 236#p34238

If the enemy is not a member of the “Solid” group, that code works. If the enemy is also a member, the code doesn’t work.

The reason the “enemy” object must also be a member of the “Solid” group is that the game will have more than one enemy. I want each enemy to avoid all other enemies.

I searched the forum for “multiple instances” and read all of these search results:
forum.compilgames.net/search.php … mit=Search

People in those pages say I should create Object Variables and check for them.

I created a “For Each” loop that should only function for each member of the “Solid” group that DOESN’T have an Object Variable called “enemy-instance-number” that equals 1. I only added that variable to the “enemy” object, but the loop still doesn’t work if the enemy is a member of the “Solid” group.

How can I fix this?

Is this a glitch in the “Group” feature of Gdevelop?

I know GDevelop can get confused with multiple instances as to which one to apply an action to. If you are asking it to check how close all objects in the group Solid are to something that is also in that group, it may always find a self-match as being closest. Depending on what your action is that may cause problems.

It might be simpler to do a collision check between two ‘enemy’ objects and then use the separate two objects action.

Yeah, the classic problem “Find nearest Solid to Solid → move Solid around Solid with an angle ‘Solid.angleTo(Solid) + 180’” thing :smiley:
You want to find the nearest Solid to Enemy, did you try?:

[code]For each Enemy:
Conitions: No conditions (always)
Actions: Do = 999999 to variable “NearestDistance”

    Conditions: Distance between Enemy and Solid is below Variable(NearestDistance)
    Actions: Do = Enemy.Distance(Solid) to the variable NearestDistance

    Conditions: Distance between Enemy and Solid is = Variable(NearestDistance)
    Actions: Move Enemy away Solid or something[/code]

If this doesn’t work (ok, I’ve tried it, it doesn’t work :frowning:), try to save the data you need and play with variables instead checking Solid-Solid data, as you want to check distance you have to save the Solid position:
NearestAtoA.zip (21.2 KB)

I tried to add the code in your zip file to my project and it didn’t work. I tried to rename many of the options from “Solid” to “enemy” and it still didn’t work.

I don’t understand the math in your code. I don’t know what “sqrt()” and “pow()” do. I don’t know how Square Roots are related to distance, and I don’t know what the abbreviation “pow” stands for.

Should I try to compare the “X” and “Y” combination of each object to every other object? I don’t know how to do that. For example, imagine that I want the distance that causes an enemy to escape to be 300 pixels. If the enemy is at position 150x150, and an obstacle is at position 200x200, how could I compare those two sets of numbers?

If the X and Y numbers of each object could be combined to become one number, I could use an event like this: “For Each enemy, if an object is less than 300 away, enemy will move away.”

I might have an inferior brain because my comprehension of math is horrifically inadequate. Hahahahaha.

Distance between a point (x1, y1) and another point (x2, y2) is = sqrt( (x1-x2)^2 + (y1-y2)^2 ) :wink:
From the formula, pow(something, 2) = something^2

distance between enemy and obstacle = sqrt( (150-200)^2 + (150-200)^2 ) if distance < 300 >> avoid obstacle

Note that there are two scenes in the example, the second scene is the good one, the debug objects has been deleted. If you need it I can try to modify the example this way:
*Rename Solid to Enemy
*Add an Obstacle object
*Add Enemy and Obstacle to a group called Solid
*Move the Enemy objects to get away from the closest Solid, if the distance is below X

This is your setup, right?

This is how your code is used in my project:

Does your Square Root code only work for objects that have the same length and width?

I tested it with an enemy that is 85 pixels wide and 85 pixels tall, and I compared it to a wall that’s 85 pixels wide and 718 pixels tall, and the enemy doesn’t avoid it unless it’s moving near the top of that wall. If I add more than one wall in the game, the code seems to only focus on one wall instead of all of them, but I might be wrong about that.

I want enemies to always avoid all physical objects in the game, including other enemies. I also only want them to avoid objects that are in front of them. If an enemy is very close to a object, BUT it’s on their side (or behind them), I don’t want the avoidance code to be activated. How should I achieve that?

In the nasty picture below, the enemy SHOULDN’T run away from the wall because it’s alongside of it (the wall will never be in its view zone while it’s moving in this direction):

example 1 - enemy should not avoid this wall because it is moving alongside it.png
In the picture below, the wall SHOULD be avoided because it will soon be within its view zone. The width of the view zone should be the full width of the front of the enemy, like the orange lines in the pictures, and I want the distance of the view zone to be chosen with this variable in my first picture: “nearest-point-before-solid-object-must-be-avoided”.

Is this goal possible with this engine?

If this engine can do the ideas above, I also want to know how to wisely choose the path for the enemy’s next movement. If walls or other enemies are in its view zone, and the enemy must turn, how do I allow it to pick the most effective turn to avoid the object? For example, in my third picture, the enemy has a clearer path on the left instead of the right, so how would I modify the Events to allow it to wisely move left instead of right during that instance?

I know this engine includes Pathfinding, but the Wiki page for that feature says a Pathfinding enemy is not able to avoid obstacles that have moved after the enemy starts moving on its computed path, and I want my enemies to also avoid other enemies that are constantly moving.

I don’t think you need the “pick all solid” action. That’s really for simultaneously changing all objects of a type e.g. deleting them all, whereas you are working through them one-by-one with a for loop.

Rather than constantly calculating distances between objects, a completely different approach is to use a tiny invisible object positioned just in front of the enemy object that acts like a cat’s whiskers to detect a solid object just before the enemy object hits it. If you create a new point on your enemy object’s sprite that is on its far right (and not in the hitbox), then you can place the invisible object at that point.

If you call the point “check” and the object ‘checker’, you’d have an event like:

No conditions   |   Do = enemy.PointX(check); enemy.PointY(check) to position of  checker 

And then one to detect if the checker object has collided with anything in the Solid group:

checker is in collision with Solid   |   Stop the object enemy 

In this case it just stops the enemy moving forwards, but you could make it rotate, reverse, or whatever else.

This is fine for one enemy only, but if you have many enemy object instances then each checker object instance will need to be linked to the correct enemy instance. You can do this at the start of the scene, using the “Link” action and then in the main game cycle you would need the “Take into account” condition.

Something like this might be the end result:

Take into account all "enemy" linked to checker  |   Do = enemy.PointX(check); enemy.PointY(check) to position of  checker 

I’m not sure if those will definitely work as I’ve had difficulty dealing with linked objects when I’ve tried in the past.

The other way of linking things is with object variables. You’d give your enemy object and your checker object a variable called “ID” and then give one enemy instance and one checker instance the same number, before increasing the number and giving it to two more instances - and so on. This could also be done in a for loop, or you could do it manually to each instance placed on the scene.

Then you’d need to check for matching ID numbers in a for loop.

checker.Variable(ID) = enemy.Variable(ID)  |   Do = enemy.PointX(check); enemy.PointY(check) to position of  checker 

It gets trickier when doing the collision check as although it will automatically select the colliding checker, the action needs to be communicated to the right enemy instance.

checker is in collision with Solid           |   Stop the object enemy
Variable ID of enemy =  checker.Variable(ID) |

And this may go wrong if two enemy instances collide head-on!

1 Like

Ah, now I know what you want to do, yeah checking distance is not an option because you can’t test the distance to the closest point, just to the center or another fixed point.

GD is great solving things with extra objects, so I agree with MattLB idea, just create a little rectangle and put it in front of the enemy, link them, finally check if the rectangle hits something and rotate the enemy to avoid it :slight_smile:

1 Like