public static new PathNNConstraint Walkable {
get {
return new PathNNConstraint {
constrainArea = true
};
}
}
This causes GC each time its called, which is every few frames by our audio occlusion logic.
public static new PathNNConstraint Walkable {
get {
return new PathNNConstraint {
constrainArea = true
};
}
}
This causes GC each time its called, which is every few frames by our audio occlusion logic.
Hi
This is hard to get away from, unfortunately.
I cannot just return the same instance every time, because NNConstraint is a class, and therefore mutable. Using the same instance would break a ton of code that people are using.
In the future, I may change the NNConstraint to be a struct instead.
Per-frame allocations are something we can’t have so perhaps there is some way to work around this? For example, could you allow us to pass through our own cached PathNNConstraint instead of you creating a new one on each call for .Walkable? Surely there is some way this can be avoided.
You could change this line in the Path.cs file’s Reset
method.
nnConstraint = PathNNConstraint.Walkable;
If you remove it, the NNConstraint will never be recreated. However, then you must ensure that you never assign a custom NNConstraint to a path, and never keep a reference to one in a path.
For most common cases, this works out of the box. But it can lead to hard to debug issues if those preconditions do not hold.
Interesting, OK. Could I do something like creating a custom class inheriting from either ABPath
and/or Path
to achieve a similar outcome without needing to edit the Path.cs
file?
This is how I am kicking off the path look-up every few frames:
NNConstraint m_NNConstraint;
OnPathDelegate m_OnPathComplete;
void Awake() {
...
m_OnPathComplete = OnPathComplete;
m_NNConstraint = NNConstraint.Walkable;
}
void ProcessSource(OcclusionAudioSource source) {
var node = AstarPath.active.GetNearest(source.Transform.position, m_NNConstraint).node;
if (node != null && PathUtilities.IsPathPossible(m_LocalNode, node)) {
var path = ABPath.Construct(start, end, m_OnPathComplete);
path.enabledTags = m_Seeker.traversableTags;
path.Claim(this);
AstarPath.StartPath(path);
m_Sources[path.pathID] = source;
}
}
...
void OnPathComplete(Path path) {
// Just in case this component was destroyed while paths were being calculated
if (!this) return;
var source = m_Sources[path.pathID];
if (source != null) {
if (path.error) {
return;
}
m_Seeker.PostProcess(path);
float pathDistance = path.GetTotalLength();
float linearDistance = Vector3.Distance(m_Transform.position, source.Transform.position);
source.Occlusion = Mathf.Clamp01((pathDistance / linearDistance) - 1);
source.PassedThroughSurfaceType = ObjectSurfaceType.None;
m_Sources.Remove(path.pathID);
path.Release(this);
}
}
You might be able to. But I’m not quite sure if you’d need access to private fields in the base classes. Might not be possible for that reason.
Hmm, yeah, turned out to be a bit tricky to override some things.
How about if you just added a new public bool to Path
like shouldKeepNNConstraint
? Then in Reset
do not reset the nnConstraint
if that is set to true
?
Then we can easily do:
var path = ABPath.Construct(start, end, m_OnPathComplete);
path.shouldKeepNNConstraint = true;
I really don’t want to do that because it’s very easy to shoot yourself in the foot with such a feature.
Hmm OK, I understand. Even if its opt-in, though? Regardless, it would be great if we could figure out a way to fix/avoid this GC as your package runs so well performance-wise but having these regular allocations is a shame. Especially when they can be avoided easily (if we hack your code, which we’d prefer not to so we can continue to update).
Just want to chime in and say that I would also like a way to opt-in to avoid these allocations. I posted about this a while ago: Allocations when calling AIBase.SearchPath? (5.0.5 Pro)
The constant allocations have been one limiting factor for me in the past when trying to significantly ramp up the number of pathfinding agents I have active at any given time. It’d be really nice to eliminate it.
Hi
I’m working on some updates which would eliminate these allocations. Tons of code to refactor. Right now up to 66 files changed, and 2000 lines of code modified, and I’m only halfway through!