No problem. Just removed it on my copy, so all good to me.
Oh, okay -- I see. One thing that would be helpful in the documentation would be a visual key for "what stuff like that means." I don't know what an unwalkable node would look like, for sure; I have seen some that are red underneath obstacles, I think. But I wouldn't swear to it.
Okay, that makes a lot of sense -- and in a generalized sense, doesn't bother me. However, as you might expect, this absolutely tanks the performance when there are a lot of such errors being thrown. I'd love an option that doesn't require a recompile that disables those messages on a given AStarPath class instance. It's the sort of thing I wouldn't want to turn off globally everywhere all the time, or have to constantly compile and recompile to test, but at the same time it can make things unplayably slow if left on right now. The ability to have a bit more nuance would be useful. Obviously I can just comment out the line or whatever on my own, but still.
On the topic of Linecast, I get that is convenient, but isn't that universally a GC allocator? Or have they added non-allocating versions of that yet? Linecast in general seems to have some funky edge cases, so I figure that if you do a RaycastNonAlloc (I think that's the method) and then just look in the resulting array for the closest hit to your position, you might wind up with better results.
Actually, frankly, if you know what you're testing against, then you might be able to just look and see if that thing is in the list. Just some musings based on past experiences with that.
4.1.5. I think that the reason that I was getting this is that I was temporarily setting the destination/target to be the place they were already at, to trigger a new cycle before heading out. That obviously wasn't working out all that well, and I abandoned that approach. I've not had a reason to turn off "slow when not facing target" since then, so I don't know if that is still something that would happen or not.
Technically "Look rotation viewing vector is zero" is an issue that you absolutely will get in some edge cases no matter what you do if the inputs aren't checked first, so putting in a quick if statement to prevent that would be worthwhile for someone else I'm sure.
Basically just check if x y and z on the value being passed into Quaternion.LookRotation are at-least-one-nonzero. You can compare to != Vector3.zero, but I don't like that because Vector3.zero can be an allocating reference (boxing, as unity inits it poorly inside there -- I've filed a bug report on that and similar issues with them, but they've not responded), and since you can basically also avoid the overloaded CompareTo call with what is essentially inlining on your part.
Wow that was more text than I needed to write for such a simple thing. But those little bits add up in those things that are called so very commonly.
Yep, I was mistaken; you've cleared that up earlier in this post. The smaller values do provide better results in general, but you're all good on that particular bit. This was in my post-video tweaking.
Yes, this helped in that they were not moving prior to that at all. BUT, please let me clarify below a bit more:
Correct. They wouldn't move at all, or in some cases would after 10-300 seconds or so. There are a couple of thing about this that was biting me:
- I had my own separate code going "am I at the destination?" since yours wasn't seeming to do what I expected at all times. I've since removed my code, but what was happening was that my code was kicking in faster than the path would be returned. By having if ( !this.pathPending ) prior to my own code, that made it work okay even when it took longer on the secondary threads to generate a valid path.
When the random wander point chosen was close enough, then they were able to get to it before my code stomped on yours. So that was my bad, but basically a big message saying DON'T BOTHER IT IF pathPending IS TRUE would be a good thing in the documentation.
- Even post-that, however, I've been confused about the purpose of destination versus target on RichAI. I'd been using AIPath prior to that, because it seemed simpler and a "rich AI" didn't sound like the sort of thing I wanted. The fact that the RichAI is actually "works really well with navmeshes AI" is another thing documentation should have in the FAQ, potentially.
At any rate, I'd just been setting target when using AIPath, and all was well in the prior tests I'd been doing. When I switched to RichAI and started using the AIDestinationSetter class as your tutorial documentation suggested, I noticed that was just setting the destination instead of also setting the target. So I started doing that also.
When doing that, THEN my AIs would just stand around infinitely if I didn't call if ( !this.pathPending ) this.SearchPath(); directly. Even then, my AIs were not reacting to changes in direction on the intervals that I was expecting, so my chaser AIs were not keeping up with me anymore. I started setting both destination and target, and STILL calling if ( !this.pathPending ) this.SearchPath(); and all is now well. Probably overkill, but my framerate is still north of 110 in a fairly complex environment with 30ish AIs, so I'm happy for now.
I've noticed that basically what you have going on is a coroutine that gets started early and then loops endlessly. That seems... risky. I don't know, I've just been averse to putting sim-dependent code in coroutines, since exception handling can be odd and the ability to override timing and such is low.
For that loop, why not just have it call in Update a method that counts down timeUntilNextRepath, and sets that to the new value just like you do with the coroutine, etc? The difference would be minimal, but I could set timeUntilNextRepath = 0 to force an immediate next-frame recalculation without having duplicate recalcs like I may be causing now. And you also lose the overhead of coroutines on this particular bit.
I use couroutines a fair bit, but it's just a personal preference of mine to avoid them in "sim code," so to speak.
Let me go through and just make a rough list in a minute, in a second update to this since this post is already getting long. The documentation is pretty good as it is, but I'm a really experienced AI programmer, and know 2D pathfinding inside and out, and there were a lot of things I found unclear. I'm relatively new to 3D pathfinding, aside from using node trees and things which basically are dimensionless and so an extension of the 2D algorithms I'd already used.
Sweet, that's what I was looking for -- thanks. I appreciate the message being there, actually. Having it say how to change the default would also be welcome as an addition so that someone like me could go in there and adjust it. I'd rather spend a bit of extra RAM on what I'm guessing are null array entries if unused rather than go through array expansion immediately on level load. Kind of like initializing a List<> with some starting value other than their default 16, for instance.
You do great work, I just want to say, by the way.