How to stop attacking if the unit is dead?

Hi,

Multiplayer course

This is my unit.cs on method ServerHandleDie I put some animation on line 51 and made a coroutine so the unit would play the animation before it gets destroyed the animation plays and the unit gets destroyed after but now my problem is while the animation is playing the opposing side (Build side) is still able to target my unit even the health is 0

public class Unit : NetworkBehaviour
{
    [SerializeField] UnitMovement unitMovement;
    [SerializeField] private Targeter targeter = null;
    [SerializeField] private UnityEvent onSelected = null;
    [SerializeField] private UnityEvent onDeSelected = null;
    [SerializeField] private Health health = null;
    [SerializeField] private Animator animator = null;

    public static event Action<Unit> ServerOnUnitSpawned;
    public static event Action<Unit> ServerOnUnitDeSpawned;

    public static event Action<Unit> AuthorityOnUnitSpawned;
    public static event Action<Unit> AuthorityOnUnitDeSpawned;


    public UnitMovement GetUnitMovement() 
    { 
        return unitMovement; 
    }

    public Targeter GetTargeter()
    {
        return targeter;
    }

    #region Server

    public override void OnStartServer()
    {
        ServerOnUnitSpawned?.Invoke(this);
        health.ServerOnDie += ServerHandleDie;
    }

    public override void OnStopServer()
    {
        health.ServerOnDie -= ServerHandleDie;
        ServerOnUnitDeSpawned?.Invoke(this);
    }

    [Server]
    private void ServerHandleDie() //Handles Destroy For Unit
    {
        animator.SetBool("isDead", true);
        StartCoroutine(OnsDieServerHandle());
    }

    IEnumerator OnsDieServerHandle()
    {
        yield return new WaitForSeconds(2);
        NetworkServer.Destroy(gameObject);
    }

    #endregion


    #region Client

    public override void OnStartAuthority()
    {
        AuthorityOnUnitSpawned?.Invoke(this);
    }

    public override void OnStopClient()
    {
        if (!isOwned) { return; }
        AuthorityOnUnitDeSpawned?.Invoke(this);
    }

    [Client]
    public void Select()
    {
        if(!isOwned) return;
        onSelected?.Invoke();
    }

    [Client]
    public void DeSelect()
    {
        if (!isOwned) return;
        onDeSelected?.Invoke();
    }
    #endregion
}

I tried to clear my target on my targeter Script on but it still attacks my unit

Targeter.cs

public class Targeter : NetworkBehaviour
{
    private Targetable target;
    [SerializeField]private Health health;

    public Targetable GetTarget()
    {
        return target;
    }

    public override void OnStartServer()
    {
        GameOverHandler.ServerOnGameOver += ServerHandleGameOver;
        health.ServerOnDie += ServerStopAttacking;
        
    }

    public override void OnStopServer()
    {
        GameOverHandler.ServerOnGameOver -= ServerHandleGameOver;
        health.ServerOnDie -= ServerStopAttacking;
    }


    [Command]
    public void CmdSetTarget(GameObject targetGameobject)
    {
        if (!targetGameobject.TryGetComponent<Targetable>(out Targetable newTarget)) return;

        target = newTarget;
    }

    [Server]
    public void ClearTarget()
    {
        target = null;
    }

    [Server]
    private void ServerHandleGameOver()
    {
        ClearTarget();
    }

    [Server]
    private void ServerStopAttacking()
    {
        ClearTarget();
        Debug.Log("cleared");
    }
}

Anyone have any idea how to stop the attacking once my unit’s health turn to 0?

Thanks in advance

Hi there,

Unit attacking is handled in the UnitFiring script. This is checking for a null state of the target. In the course when the unit dies, it is destroyed, so the target becomes null and the attacking stops.

Since you are maintaining the game object a little longer to play your animation you need to add another check in the CanFireAtTarget() method in the UnitFiring script. You’ll need to get a hold of the target’s health and see if it is still alive.

Hope that helps!

Ok I will try that Thank you for the advice :slight_smile:

Hello again,

So I tried my best to do it but seems I am still doing something wrong or I am missing something

I tried to use the event ServerOnDie
and set the bool isAlive to false
when it triggers

but seems like the isAlive bool is not getting updated

some other methods I tried is doing a getter method on the health script getting the current health

then currentHealth == 0 then isAlive = false but I still get the same outcome this line here is my last attempt

can you please give me more advice
Thank you

public class UnitFiring : NetworkBehaviour
{
    [SerializeField] private Targeter targeter = null;
    [SerializeField] private GameObject projectilePrefab = null;
    [SerializeField] private Transform projectileSpawnPoint = null;
    [SerializeField] private float fireRange = 5f;
    [SerializeField] private float fireRate = 1f;
    [SerializeField] private float rotationSpeed = 20f;
    [SerializeField] private Animator animator;
    [SerializeField] private Health health;

    private float lastFireTime;
    private bool isAlive = true; //<--

    public override void OnStartServer()
    {
        health.ServerOnDie += ServerHandleDie; //<--
    }

    public override void OnStopServer()
    {
        health.ServerOnDie -= ServerHandleDie; // <--
    }

    [ServerCallback]
    private void Update()
    {
        Targetable target = targeter.GetTarget();

        if (target == null)
        {
            animator.SetBool("isAttacking", false);
            return;
        }

        if (!CanFireAtTarget())
        {
            animator.SetBool("isAttacking", false);
            animator.SetBool("isRunning", true);
            return;
        }

        if (!isAlive) // <--
        {
            return;
        }
        

        RotationToTarget();

        if (Time.time > (1 / fireRate) + lastFireTime)
        {
            Quaternion projectileRotation = Quaternion.LookRotation(target.GetAimAtPoint().position - projectileSpawnPoint.position);

            GameObject projectileInstance = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileRotation);

            NetworkServer.Spawn(projectileInstance, connectionToClient);

            lastFireTime = Time.time;
        }
    }

    private void RotationToTarget()
    {
        Quaternion targetRotation = Quaternion.LookRotation(targeter.GetTarget().transform.position - transform.position);

        transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    }

    [Server]
    private bool CanFireAtTarget()
    {
        animator.SetBool("isRunning", false);
        animator.SetBool("isAttacking", true);
        return (targeter.GetTarget().transform.position - transform.position).sqrMagnitude <= fireRange * fireRange;

    }


    [Server]
    private void ServerHandleDie() // <--
    {
        isAlive = false;
    }
}

OnStopServer is only being triggered when the gameObject is destroyed. This is after you want to play the animation. So you would need to trigger something earlier.

I like the idea of unit firing checking the health before firing. How were you implementing this? You need to make sure you are getting the health from the target specifically. So like targeter.GetTarget() then get the health of that object.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms