I'm using a implementation of the RDP algorithm to eliminate unnecessary verts on a given A* path. If you're not familiar with RDP there is a Wikipedia article about it.
https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
Here's my implementation:
const CULL_THRESHOLD: = 1.0
static func _rdp(verts: Array) -> Array:
if verts.size() <= 2: return verts
var d_max: = 0.0
var index: = 0
for i in range(1, verts.size() - 1):
var d: float = point_line_distance(verts[i], verts.front(), verts.back())
if d <= d_max: continue
index = i
d_max = d
if d_max < CULL_THRESHOLD:
return [verts.front(), verts.back()]
var path: Array = _rdp(verts.slice(0, index))
path.pop_back()
return path + _rdp(verts.slice(index, verts.size() - 1))
static func point_line_distance(point: Vector3, start: Vector3, end: Vector3) -> float:
var n: float = abs((end.x - start.x) * (start.z - point.z) - (start.x - point.x) * (end.z - start.z))
var d: float = sqrt(pow(end.x - start.x, 2) + pow(end.z - start.z, 2))
return n / d
It works and makes my paths look quite a bit more organic and... sane. My question though is there are sometimes key points on paths that I wouldn't want this algorithm to remove. For example when traversing stairs, I've noted my actors sometimes approach the stairs from an angle and then get hung up on them.
One thing that might work is if I'm calculating point_line_distance
on all three axis including y
. But I haven't been able to really figure out how to do that in the function.
Calculating the third axis would mean that the point isn't eliminated if it's directly before or directly after an incline. Anyone have any ideas? I'd like not to have to remove this.