ricardojmendez / UnitySteer

Steering, obstacle avoidance and path following behaviors for the Unity Game Engine
https://numergent.com/tags/unitysteer/
Other
1.2k stars 275 forks source link

Feature request: prevent SteerForPath skipping waypoints #46

Open elitvynov opened 7 years ago

elitvynov commented 7 years ago

Hi, current implementation of SteerForPathSimplified2D uses closest way-point to the vehicle and could skip some points. This happens for complicated paths, for example, with loops. What do you think about adding a flag to SteerForPathSimplified2D (or different SteerForPathBehavior) that will force vehicle to visit every way-point from array in straight order?

Thanks.

ricardojmendez commented 7 years ago

Hi!

Sure, that's a characteristic of that behavior. Extending it to behave that way has been on my mind, but hasn't been a priority. Feel free to submit a pull request!

Cheers,

Ricardo

elitvynov commented 7 years ago

Ok, I will implement this in my game, and then submit a pull request

ricardojmendez commented 7 years ago

Perfect, thanks. Should be straightforward to extrapolate from the current code: instead of getting the next closest point in the path, get the next closest point in the current path segment.

Cheers!

elitvynov commented 7 years ago

I'm not sure I understand the difference between next closest point in the path and the next closest point in the current path segment. For example Vector2Pathway::SegmentCount returns Path.Count so it looks like point in the path and point in the current segment is the same thing.

What I'm trying to do now, is adding a bool variable SteerForPathSimplified2D::_traverseContinuity. Then adding if statement to SteerForPathSimplified2D::CalculateForce(), so if _traverseContinuity is falls, then I calculate pathDistanceOffset and DistanceAlongPath as usual. If _traverseContinuity is true, then I get next point from path's IList Path variable, and return steering to seek this target point. Also I need to listen OnArrival action to understand, when vehicle can move to the next point (increment index variable to get next point from path)

Are my thoughts correct, or I missing something? I just started to investigate in UnitySteer source so I could not understand some basic ideas.

Cheers

ricardojmendez commented 7 years ago

Welp, sorry, my bad. I was thinking of the original implementation. SteerForPathSimplified does not do that anymore (and I added a big comment about it, too). It was a while ago.

Your general logic is correct, with a caveat. Keep in mind that the point to aim for is calculated by the pathway class, and it may not be a straight line (in the case of SplinePathway, which is usually the default, it isn't). We would not want the Steering behavior ignoring what the pathway considers is its arc and steer on a straight line, just because we want it to touch on waypoints.

If you want to make sure you touch on every waypoint, I'd say it'd be cleaner to clamp pathDistanceOffset to the distance still left in the current segment, instead of just seeking the next point. This may require extending the IPathway interface, as well as the inherited classes.

elitvynov commented 7 years ago

By segment you mean length between two points, right? For Vector2Pathway this is straight line, and for SplinePathway it could be arc. If yes, I'm not sure solution with clamp pathDistanceOffset will solve the problem. Screenshot of path example. With current implementation algorithm chooses Point 7 after Point 2. I think this happens because distance and direction to Point 7 is more desirable than to Point 3. Do you think clamping pathDistanceOffset to the distance still left in the current segment will solve the problem? Currently I can tune _predictionTime and _minSpeedToConsider to force vehicle choose right sequence for this particular path, but this is bad decision in general because I will have about 20 different paths for AI and they will skip Points here and there.

ricardojmendez commented 7 years ago

This shouldn't really be an issue of "desirability", but I can see what might be throwing you off here. It's not really an issue of speed, but related to the path backing over itself.

If you see here the behavior is memory-less, and the vehicle estimates how far it is along the path by its current position. MapPointToPathDistance would indeed pick the closest point in the path to the vehicle's current position, so if for any reason #7 is closer than #3, it doesn't really know if it's moving from 2->3 or from 6->7.

There are two options I see here:

Let me know if that clears things up.

elitvynov commented 7 years ago

I have tried to calculate DistanceAlongPath using position of next point's index, and updating this index when OnArrive action happens, but in this case Vehicle visit few points and then start to move around point by circle and never arrive to it. It looks like it's not so easy to modify SteerForPathSimplified2D like I though before :) I think I will return yo this investigation after I finish prototyping my game, because movement by path is only small part of behaviors I planned to use.

ricardojmendez commented 7 years ago

but in this case Vehicle visit few points and then start to move around point by circle and never arrive to it

A combination of factors can lead to a vehicle stopping on exactly one point, much like it'd happen with a real-world vehicle, including:

A larger arrival radius will likely help.