Closed verekia closed 1 year ago
I managed to get it working using earcut: https://github.com/mapbox/earcut
const allPoints = [...outerPoints, ...centralObstaclePoints]
const triangles = earcut(allPoints.flat(), [outerPoints.length]).map(index => allPoints[index])
const groupedTriangles = triangles.reduce((acc, cur, i) => {
if (i % 3 === 0) {
acc.push([])
}
acc[acc.length - 1].push(cur)
return acc
}, [])
const navmesh = new NavMesh(groupedTriangles)
Hi @verekia,
Thanks for reporting that!
I have to check to be sure, but I believe the library will handle counterclockwise polygons as outer boundaries and clockwise polygons as holes, so you might be able to use that.
The editor most likely ensures everything is counterclockwise so it's hard to use if you need holes.
I will check when I have some more time!
Thank you for your answer! I am trying the following polygons:
const polygons = [
// outer, counterclockwise
[
[0, 0],
[500, 0],
[500, 500],
[0, 500],
],
// inner, clockwise
[
[100, 100],
[100, 400],
[400, 400],
[400, 100],
],
]
const navmesh = new NavMesh(polygons)
Is this what you mean? With this code, it seems like the inner square is not creating a hole. The resulting path goes through the inner square.
Sorry for coming back so late.
I checked, not I do not handle holes correctly right now. Your best bet, is to use earcut
directly before passing the data to nav2d
. earcut
has a explicit holes
parameter.
After that, pass the triangulated data to nav2d
and it should solve your issue.
Thank you for your answer @frapa
I am already using earcut to triangulate with holes, but the pathfinding seems off when there are holes.
For context, I am using nav2d on the game https://minimana.io The monsters on the map run after the character, and I use nav2d pathfinding at every frame.
This is what the map looks like, with the navmesh in blue, and the triangles generated by earcut in red.
In this video example, I made a hole, and I am running around it. You can see that the monster sometimes takes the wrong path (when it starts turning counter-clockwise). The monster was closer to me clockwise, but it decided to go the other way:
https://github.com/frapa/nav2d/assets/522007/8432c033-fe57-4545-86b7-876f8b0dccb8
I have noticed this behavior whenever I have holes.
You can see it here as well:
https://github.com/frapa/nav2d/assets/522007/e8e8b8ca-e899-4b1c-9849-857a889518a1
(This bridges area is in the middle of the map on the screenshot above, but the blue navmesh is covering the bridges)
If you think the issue comes from nav2d, I would be happy to offer a bounty for a fix, as this is pretty important for this kind of game :)
Feel free to reach out to me on Discord or Twitter (verekia) if you want to have a chat :)
Oh, thanks for a link to the game, it's great to see the library is useful. It seems also plenty fast!
Also, great videos showing the problem. This isn't a bug with the library, actually nav2d
is working fine here. The problem is that path finding works with these steps:
To do (1) it will use the triangle centroids for a heuristic of how long the path is, but it's just an heuristic so it can get the wrong estimate, such as in this case. Typically, path-finding algorithms are focused on speed, because it is an expensive operation and games usually need performance, so it's typical to sacrifice some accuracy for a path that's good enough. This is what nav2d
is doing here.
In other words, try to count the triangles between the characters, and you will see that it's actually taking the path with the least amount of triangles, only they are larger, so it leads to a longer path effectively.
To solve this issue, you have 2 options:
earcut
is built for speed just like nav2d
but it sacrifices triangulation quality to achieve it. You see this in the number of thin elongated triangles you have in the mesh. Additionally, you actually don't need to triangulate each time, so you can basically do a high-quality triangulation every time you change the map of your game, then simply load the already triangulated high quality navigation mesh. I would recommend going this way, as you are sure to encounter far less issues.One optimization we could add here is that we can add a flag to tell nav2d
to avoid triangulation, to save additional load time when the navigation mesh is already triangulated.
Thank you so much for your answer!
I switched to https://github.com/r3mi/poly2tri.js, which creates a much cleaner mesh and works better with nav2d
's pathfinding!
This library is fantastic! I managed to get pathfinding working very easily for a game. Thank you so much @frapa.
But I have a question. How would you recommend adding holes to a navmesh?
Let's say we have a square:
But I don't want the whole square to be walkable. I would like to have a smaller inner square obstacle, for instance:
I managed to get this case working in the online editor by creating 2 polygons and connecting them: Shaped like
[
and]
.That's fine for a simple case like this, but for a video game with a complex map and many obstacles in the middle of the map, I am not sure how to proceed. This method would be very tedious. Any recommendation?