How can I trim a path to be shorter?

My RVO Controllers shake back and forth as they approach their targets when the targets also have RVO Controllers on them. Aron said this is because I’m setting to target to the middle of them. The RVO Controllers then jerk back and forth as they try to go around the controller while also trying to enter it.

How can I trim my path so that it’s X distance away from the center? I tried modifying p/path in OnPathComplete() in Seeker.cs with this but it didn’t work/

The trim is working correctly, but the path doesn’t seem to be updating correctly once I trim the final waypoint and remove the excessive ones after it. This is my OnPathComplete at the moment:

    void OnPathComplete(Path p, bool runModifiers, bool sendCallbacks) {
        if (p != null && p != path && sendCallbacks) {
            return;
        }

        if (this == null || p == null || p != path)
            return;
        //////////
        Debug.Log("vectorPath Count before trim - " + p.vectorPath.Count);
        p.vectorPath = TrimPath(p.vectorPath, p.GetTotalLength(), 5f);
        Debug.Log("vectorPath Count after trim - " + p.vectorPath.Count);

This is my TrimPath() code:

 public List<Vector3> TrimPath(List<Vector3> pts, float lengthToEnd, float maxLength)
        {
            Debug.Log("NEW PATH -----------------------------------");
            Debug.Log("Entering TrimPath()");
            //For length testing
            var totalLength = 0f;
            var waypointLength = 0f;
            Debug.Log("Start totallength is " + totalLength.ToString());
            Debug.Log("Start waypointlength is " + waypointLength.ToString());
            Debug.Log("Start waypoint count is " + pts.Count.ToString());
            Debug.Log("Distance to final point is " + lengthToEnd.ToString());

            //Add up each waypoint length and check if it's over our max length
            for (int i = 0; i < pts.Count - 1; i++)
            {
                //Calcualte length of current waypoint section to the next. Ex, (1, 1, 1,) distance from (0, 0, 0) is (1, 1 ,1)
                waypointLength = Vector3.Distance(pts[i], pts[i + 1]);
                Debug.Log("i = " + i.ToString());
                Debug.Log("Current totallength is " + totalLength.ToString());
                Debug.Log("Current waypointlength is " + waypointLength.ToString());
                Debug.Log("Current maxlength is " + maxLength.ToString());


                //If the current waypointLength will put us over max length, recalculate it so that it doesn't
                if (totalLength + waypointLength > maxLength)
                {
                    Debug.Log("Total length + next waypoint length is greater than max length - " + (totalLength + waypointLength));
                    //Get the fraction of the size that we actually need it to be. Ex if max is 8, current total is 6, but next waypoint is 4 (giving us 10 instead of 8)...
                    //The fraction will be 0.5. Waypoint (4) needs to be cut in half then, in this case (6 + 2 = 8)
                    float fraction = (maxLength - totalLength) / waypointLength;
                    Debug.Log("Fraction is " + fraction);
                    //Cut wthe current point by the fraction above. Lerp because it's 3d
                    Debug.Log("Before Lerp " + pts[i + 1].ToString());
                    pts[i + 1] = Vector3.Lerp(pts[i], pts[i + 1], fraction);
                    Debug.Log("After Lerp " + pts[i + 1].ToString());
                    //If there are more points, remove them
                    Debug.Log("Removing the rest of the points since we are over max length");
                    Debug.Log("Count before RemoveRange " + pts.Count);
                    pts.RemoveRange(i + 2, pts.Count - (i + 2));
                    Debug.Log("Count after RemoveRange " + pts.Count);
                    //return;
                }
                totalLength = totalLength + waypointLength;
            }
            return pts;
        }

Now I know that I’m modifying the right path because if I force it to null then my character doesn’t move. So why does trimming the ends off not correctly update the path?

Hi

I would recommend that you change the destination instead of trying to trim the path. That will be much simpler:

float marginDistance = 1.0f;
ai.destination = enemy.position + (transform.position + enemy.position).normalized * marginDistance;

If you are using the AIDestinationSetter script, you should remove it and use this code instead.

The reason I didn’t do that is because it will put the destination on the side that is in-between my player and the enemy. But what if my player needs to walk around an obstacle and end up on the other side of the enemy? The destination would be on the wrong side.

I suppose that won’t be a big deal since the paths get recalculated regularly anyways. Right?

Also, any idea why my “post processing” trim didn’t work as intended?

As long as the obstacles are larger than about the radius of a character I think the destination code should still work.

If you are using the RichAI movement script, it simply will not work as the RichAI script doesn’t use the vectorPath output at all.
For the AIPath script it should work, but you also need to adjust the path.endPoint and path.originalEndPoint fields and set them to where the path ends after your modification.

Thank you. This was driving me nuts. I knew the problem had to be something like that but I couldn’t comprehend how the path was being used by the RichAI or RichPath.

1 Like

I needed to adjust the equation a bit because it was always putting the target at a static place away from the objects like so: https://imgur.com/a/mBbujak.

This is the equation I ended up using in Destination Setter:
if (target != null && ai != null) ai.destination = target.position + (marginDistance * (transform.position - target.position).normalized);

However, it still seems like something is “off”. Now they dance in front of each other permanently instead reaching their destination like so: https://imgur.com/a/oUOBKVg. To be specific, rich.endReachedDistance is never being triggered.

And well finally… they are still jerking! :slight_smile: Also, is it a bug that End Reached Distance doesn’t seem to do anything on the RichAI controller?

At this point I’m trying to determine if I give up on this specific and move forward with my prototype or not. I’ll need to fix this later but am curious as to why this hasn’t been a problem for others making RTS style units. :question:

Do people just usually run their own custom movement scripts or something? I was really hoping to use RichAI and the RVO controller if possible but editing the transform position is causing them to not reach their destination while still causing the jittery rotation as they reach each other.

I also realize now that I didn’t make it clear that I would have players and enemies walking into each other to fight, not just stationary objects for the player to hit. I assume this makes things more difficult?

Would it make sense to just use endReachedDistance instead and fix the jittery rotation in some other way?

Edit; Yet another thing I’m realizing is that I’ll need to take the opposing unit’s velocity into account to know to stop soon than endReachedDistance. Any thoughts on how to do that appropriately? Else they run into each other even if path update is set to happen very often.