Game Object overshooting target location

I’m working on a basic 2D platformer where NPCs chase the player and I’ve been bashing my head against a problem for days.

I use A* pathfinding to chart a path from the Guard to the player. It’s supposed to stop a certain distance away from the player if they’re not moving (playerClosingDistance). Currently what happens, however, is that in some cases the Guard will stop at the right distance, and sometimes it’ll overshoot, landing either right next to the player, on the player, or even passing through and turning around in rare cases.

Option 1
It could be as a result of the movement script on its own:

if (Mathf.Abs(distanceToPlayer) > playerClosingDistance)
        {
             // General Movement
                     
            body.velocity = new Vector2(direction.x * speed, body.velocity.y);

            anim.SetBool("Running", true);

        }
        else
        {
            // Stop running
            body.velocity = new Vector2(0, body.velocity.y);
            anim.SetBool("Running", false);
        }

Is that likely to be the problem? If so, what changes can I make?

Option 2
If it’s not the problem, my other areas of consideration are the use of the A* pathfinding itself.

A few salient parts of the script:

public void Start()
    {
        InvokeRepeating("UpdatePath", 0f, pathUpdateSeconds);
    }
private void UpdatePath()
    {

        if (targetTransform == playerTransform) // for offsetting to player mid-body
        {
            targetTransformWithOffset = new Vector2(targetTransform.position.x, targetTransform.position.y + playerHeightOffset);
        }

        if (followEnabled && TargetInDistance() && seeker.IsDone())
        {
            seeker.StartPath(body.position, targetTransformWithOffset, OnPathComplete);
        }
    }
private void FixedUpdate()
    {

        // If there's no target, don't go anywhere
        if (targetTransform == null)
        {
            followEnabled = false;
        }
        else
        {
            followEnabled = true;
        }

        // Target in Distance?
        if (TargetInDistance() && followEnabled)
        {
            PathFollow();
        }
   
    }
private void PathFollow()
    {
     
        if (path == null)
        {
            // We have no path to follow yet, so don't do anything
            return;
        }


        // reached end of path
        if (currentWaypoint >= path.vectorPath.Count)
        {
            return;

        }

    
        Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - body.position).normalized; // means that no matter the waypoint distance it only looks at the direction




        // Movement Options
        // Player is the target - only one for now
        if (targetTransform == playerTransform)
        {
            float distanceToPlayer = Vector2.Distance(transform.position, playerTransform.position);
                                                                                                  
            playerIsTarget(distanceToPlayer, direction);

        }
}

I don’t know if any of these are non-standard; I followed a tutorial and made some basic edits for flexibility. I’m hoping it’s something easy to fix, but I’ve tried everything I can think of except workarounds instead of fixes (e.g. slowing the guard on approach to the player, repelling them a certain distance from player, etc.)

Find out what’s happening first.

Since you only pathfind every X amount of time, I’ll bet that your guy is just going to an old location where the target USED to be when he pathfinded to it.

Otherwise…

Time to start debugging! Here is how you can begin your exciting new debugging adventures:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the names of the GameObjects or Components involved?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: How To - Capturing Device Logs on iOS or this answer for Android: How To - Capturing Device Logs on Android

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

If your problem is with OnCollision-type functions, print the name of what is passed in!

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

“When in doubt, print it out!™” - Kurt Dekker (and many others)

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

1 Like

It’s a problem with your movement script. In video games everything moves in steps and sometimes the steps don’t always align nicely with targets etc. An easy way to solve it is by making your guard slow down a little (take smaller steps) as they approach the closing distance.

1 Like

So I have been doing a lot of attempts at Debugging! My issue is partly that I couldn’t figure out a way to identify where the issue was arising as it was all fairly cotemporaneous. i.e. if it’s pathfinding and moving at the same time, and all are triggering successfully, it’s harder to pin down what’s causing something that occurs as a result of both.

I’ve not used Debug.Break() before though so I’ll add that to my repertoire!

I’ve tried fiddling around with pathfinding timings to counter for something like this with no luck - but I’ll take a stab at using Debug.Break to see if I can ID it further.

This is top of my list of workarounds - if it’s a standard issue that’s not unique to me I’m happy to go down that route. I had just hoped to fix the issue at its root cause, but if it’s just part of how all this works for everyone then I can live with it.

A very common case… I get called in to debug weird errors in huge complicated games with massive levels and hundreds (or thousands) of moving parts… if I cannot figure it out, I keep deleting parts of the game, checking to make sure the issue still exists, until it is only the tiniest piece of data left that manifests the problem.

In the case of pathfinding this often means making an ultra simple test level with one enemy and one platform and iterate on that until you find the problem.

With one enemy and one player, you can print out every variable related to each one every frame and get to the bottom of it quickly.

You might even make a fake player that is under computer control and moves in a known pattern, just so you can focus on watching what the log output is as you observe the game, waiting for the bug to manifest. Debug.Break() let’s you instantly pause the game when interesting things happen.

EDIT: obviously I am using source control so I can delete ANYTHING I want while I work, then with one click it is all back without any damage. ALWAYS work with source control or you are crippling your ability to work with the project.

PROPERLY CONFIGURING AND USING ENTERPRISE SOURCE CONTROL

I’m sorry you’ve had this issue. Please consider using proper industrial-grade enterprise-qualified source control in order to guard and protect your hard-earned work.

Personally I use git (completely outside of Unity) because it is free and there are tons of tutorials out there to help you set it up as well as free places to host your repo (BitBucket, Github, Gitlab, etc.).

You can also push git repositories to other drives: thumb drives, USB drives, network drives, etc., effectively putting a complete copy of the repository there.

As far as configuring Unity to play nice with git, keep this in mind:

https://discussions.unity.com/t/736093/3

I usually make a separate repository for each game, but I have some repositories with a bunch of smaller test games.

Here is how I use git in one of my games, Jetpack Kurt:

https://discussions.unity.com/t/807568/3

Using fine-grained source control as you work to refine your engineering:

https://discussions.unity.com/t/826718/2

Share/Sharing source code between projects:

https://discussions.unity.com/t/719810/2

Setting up an appropriate .gitignore file for Unity3D:

https://discussions.unity.com/t/834885/5

Generally the ONLY folders you should ever source control are:

Assets/
ProjectSettings/
Packages/

NEVER source control Library/ or Temp/ or Logs/
NEVER source control anything from Visual Studio (.vs, .csproj, none of that noise)

Setting git up with Unity (includes above .gitignore concepts):

It is only simple economics that you must expend as much effort into backing it up as you feel the work is worth in the first place. Digital storage is so unbelievably cheap today that you can buy gigabytes of flash drive storage for about the price of a cup of coffee. It’s simply ridiculous not to back up.

If you plan on joining the software industry, you will be required and expected to know how to use source control.

Source control does require learning, but there are TONS of tutorials and courses and online reference.

You should strive to use source control as well as you use your file/folder system.

“Use source control or you will be really sad sooner or later.” - StarManta on the Unity3D forum boards

1 Like