Support Forum

Kill a path when target is safe?

Hello,

I have just started using this great project, but am having difficulty killing a path.

Basically I have a game object “Child” which is trying to reach the end of a maze before the “Enemy” object can reach it. I am testing with one child game object for now, but I will have multiple. If the children reach the safe zone (game object with circle collider), then I destroy the child gameobject because they are safe.

The problem I have at the moment is that when my child gameobject reaches the safe zone and is destroyed, the Enemy still keeps going on the path to the last known position of the child.

Is there a way to kill the path when the target object is null? I can see from the Debug.Log I have that target is updated to null, but the enemy still continues on the path.

The enemy object has a Seeker component and 2 scripts, below:

Enemy_AI - used to get closest target, update path and destroy child object on trigger

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class Enemy_AI : MonoBehaviour {
    public Transform target;
    private const int IsometricRangePerYUnit = 100;

    Path path;
    int currentWaypoint = 0;

    Seeker seeker;
    Rigidbody2D rb;
    public Level_Config levelConfig;

    void Start() {
        levelConfig = GameObject.Find("Level_Config").GetComponent<Level_Config>();
        seeker = GetComponent<Seeker>();
        rb = GetComponent<Rigidbody2D>();
        InvokeRepeating("UpdatePath", 0f, 0.5f);
    }

    void FindClosestChild() {
        float distanceToClosestChild = Mathf.Infinity;
        Child_AI closestChild = null;
        Child_AI[] allChildren = GameObject.FindObjectsOfType<Child_AI>();
        Debug.Log(target);
        foreach (Child_AI currentChild in allChildren) {
            float distancetoChild = (currentChild.transform.position - this.transform.position).sqrMagnitude;
            if (distancetoChild < distanceToClosestChild) {
                distanceToClosestChild = distancetoChild;
                closestChild = currentChild;
                target = closestChild.GetComponent<Transform>();
            }
        }
    }

    void UpdatePath() {
        if (seeker.IsDone() && target != null) {
            seeker.StartPath(rb.position, target.position, OnPathComplete);
        }
        else if (target == null) {
            seeker.GetCurrentPath().Error();
            path = null;
        }
    }

    void OnPathComplete(Path p) {
        if (!p.error) {
            path = p;
            currentWaypoint = 0;
        }
    }

    void Update() {
        FindClosestChild();

        // Render player in front / behind objects based on Y axis.
        SpriteRenderer renderer = GetComponent<SpriteRenderer>();
        renderer.sortingOrder = -(int)(transform.position.y * IsometricRangePerYUnit);
    }

    public void OnCollisionEnter2D(Collision2D other) {
        if (other.gameObject.tag == "Child") {
            levelConfig.currentCount--;
            Destroy(other.gameObject);
        }
    }
}

Enemy_AIPath - used for 4-directional sprite animation

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class Enemy_AIPath : AIPath {
    public Animator anim;

    protected override void Start() {
        anim = GetComponent<Animator>();
    }

    protected override void Update() {
        base.Update();

        if (Mathf.Abs(velocity.x) > Mathf.Abs(velocity.y)) {
            if (velocity.x > 0) {
                anim.Play("Enemy_Right");
            }
            else {
                anim.Play("Enemy_Left");
            }
        }
        else {
            if (velocity.y > 0) {
                anim.Play("Enemy_Up");
            }
            else {
                anim.Play("Enemy_Down");
            }
        }
    }
}

Any help with this would be greatly appreciated.

Many Thanks,

John

Hi

It looks like you are using a custom movement script.
In that case if you want to stop following the current path and cancel any path request that is in progress then you can do this

ai.SetPath(null);

I would not recommend that you use the seeker.StartPath method if you are also using the AIPath script. Use the ai.destination property instead, or if you have special needs for how the paths are created then you can use ai.SetPath.

Hi Aron,

Thank you for your reply. I had found a workaround which was to Destroy the Enemy_AIPath script and Seeker components, but your way is much nicer, so I have used that.

Do I still need the Seeker if I use destination? I have changed my code in the Enemy_AI script to this which is working. Just want to make sure it is ok?:

void UpdatePath() {
        if (seeker.IsDone() && target != null) {
            //seeker.StartPath(rb.position, target.position, OnPathComplete);
            aiPath.destination= target.position;
        }
    }

Many Thanks,

John

You do not need to use the seeker. The AIPath will request the path from the Seeker for you.

if (target != null) {
     aiPath.destination= target.position;
}

Hi Aron,

Thank you for confirming. I guess I still need the Seeker component though? I tried to remove it from the Inspector and was told I cannot remove because the Enemy_AIPath script depends on it.

Many Thanks,

John

Yes. But you rarely have to use it in your script. The AIPath script will use it internally.

Thanks Aron,

That is great, it is working perfectly. Tomorrow I will test out the Simple Smooth Modifier.

Many Thanks,

John

1 Like