Wall avoidance AI (SOLVED)

Hello, in my 2d top view game i have enemies that track and follow the player once he get too close to them, but my problem is, when the player hide behind a wall, the enemie just go against the wall and doesn’t avoid it. I need my enemies to avoid the wall and keep tracking the player but don’t know how to do it. I can give you some visual of my problem and if needed the script of my “enemie” game object and more.

image

You need to apply a path finding algorithm that can find the shortest path from point A to point B (theory: https://www.wikiwand.com/en/Pathfinding visualization: https://qiao.github.io/PathFinding.js/visual/) . This is quite easy if your map is tile/grid based. Moku, is a Defold tilemap solution with path finding: Moku, Map utility & auto-tile module

3 Likes

Can i still use the Moku extension even if i don’t use tiles for my game ?

I don’t think this solution would work in my case, because first i have 2 player and it seems like this extension only can “track” 1 object, also i don’t use a tilemap and i think there’s a easier solution, wich would consist to add 2 trigger 64 pixel on the left and on the right if m’y enemie, then when he is in contact with a wall he go where the trigger detect no wall.

I’m sorry for the grammar and others mistakes, it’s the autocorrect on my phone

Pathfinding can be a little tricky depending on what you want to do and what elements you are using to calculate the path. If your objects are irregular placed, with irregular shapes and even worse some shapes are dynamic and might be moving around, well then it can be a little harder.

You might wanna try polygon pathfinding like: https://www.groebelsloot.com/2015/12/24/pathfinding-part-1
Maybe precalculate paths?

It’s too little information about the game to really fully help you out here.

2 Likes

Maybe this could help you on your way if you would like to use a tilebased pathfinding in a quite noncomplex way:
I’m now assuming you are using losely placed objects with collision shapes. Just like in this image (eg. walls, table etc)
1

What if you pregame (or pre-runtime?) checked for collisions in a gridbased way and then stored that info in a table. Like this: Green = no collision, Red = collision.
2

With that info you can take all the squares that contains all green four corners and make those “tiles” walkable, store this in table.
3

Now you have a tilegrid to try you pathfinding on. The grid size you choose will let the units cut corners more efficient but will make it heavier on calculations and memory.

8 Likes

Thanks a lot for the time you took to give me a solution adapted to my case. I will now try this solution and give you a feedback if it worked or not. :+1:

3 Likes

You are going to require some kind of graph structure to do any kind of meaningful pathfinding (I believe). Just checking for walls at some arbitrary distance, and moving based on that information wont actually get you around obstacles. It will just make your enemy jitter around like an idiot :stuck_out_tongue:

Moku should be able to handle what you want, since youre going to probably create that invisible grid structure anyways, as outlined in the prior post. Im not sure what you mean with “tracking” 1 object, as youre free to call the pathfinding function whenever, and however many times you wish.

The one reason I can think to not use moku, is because it will add some small unnecessary overhead, since you wont be using it to store any kind of tile values. This can probably be circumvented by creating your own map structure instead of letting moku build it, but that requires an understanding of how it works underneath the hood.

edit: actually no there is no unnecessary overhead, since you need to store walkable and non walkable tiles anyways.

I don’t disagree with the anything else in your post, but actually I’ve gotten some surprisingly good behavior using only raycasts. If you treat their results like soft springs you won’t have any jitter (at worst a gently wavering), and if you add some conditions based on which rays report hits and which directions are open, you can have AIs that maneuver smoothly around walls, corners, and through doorways. Of course they will still get stuck in concave areas and can’t plan ahead, it’s not a replacement for pathfinding, but you can get some pretty ‘intelligent’ and natural movement that way, and it requires no extra information about the environment.

1 Like

Fair enough. I guess my issue is specifically that of not being able to plan ahead, but I suppose that is not always strictly required. (And yes if it does work for ones specific needs, I can see it looking pretty nice and “springy”)

But the thought of enemies getting stuck on walls, or getting lost bothers me immensely :stuck_out_tongue:

2 Likes

Hi, so i finally managed to do something that approximately work “without problem”. I first tried with the solution that @andreas.strangequest gave me too create a grid etc… but it was too hard for me :sweat:. I then tried the solution of @britzl and changed everything in my game by using tiles and tilesmap instead of gameobject, so i could use Moku. But there’s a lot of things i didn’t hunderstood in the fonctionnement of Moku even with the gitHub files, so i wasn’t able to use it :confused:.

The solution that worked for me is :
In the update function of my enemie script, i added a ray_cast that only search for wall gameobject at 64pxl in front of him :

        if self.wall == false then
		physics.ray_cast(go.get_world_position(), go.get_world_position() + self.velocity*64,{hash("wall")})
	end
	if self.t <= 0 and self.wall then 
		self.wall = false
		self.t = 0.75--continue to follow the player after 0.75sec if there's no wall in front of him
	elseif self.t > 0 then
		self.t = self.t - dt
	end

Then in the ray_cast_response i change a ‘self.wall’ variable to stop the ray_cast and in the same time i call this little function :

local function avoid(self, position, dt)
	if math.floor(position.y) == math.floor(go.get_world_position().y) and self.wall and self.velocity == vmath.vector3(0, 0 ,0) then
		if go.get_world_position().y >= go.get_world_position("/player").y then
			self.velocity = vmath.vector3(0, -1, 0)
		else
			self.velocity = vmath.vector3(0, 1, 0)
		end
	elseif math.floor(position.x) == math.floor(go.get_world_position().x) and self.wall and self.velocity == vmath.vector3(0, 0 ,0) then
		if go.get_world_position().x >= go.get_world_position("/player").x then
			self.velocity = vmath.vector3(-1, 0, 0)
		else
			self.velocity = vmath.vector3(1, 0, 0)
		end
	end
end

I admit Moku is not very easy to use, but thats the price of its power (well, and my lack of experience writing code for others :P). If what you have works fine, then obviously stick with it, but if you require more predictive pathfinding, ill be glad to help you get moku set up.

4 Likes