Death Delay?

Looking for some advice:

Currently, the “bullet” I am using is a magic spell, which is travelling slower than the bullet. The problem is that the death (and the Destroy(gameObject)) is occurring before the bullet makes it to the enemy.

I feel like this could be solved with a collider + trigger, like this:

     private void OnTriggerEnter(Collider other) 
     {
        if(other.tag == "Enemy")
        {
            Debug.Log("Hit Enemy");
            shootAction.bulletCollisionHasOccured = true;
            Destroy(other.gameObject);
        } 
        else
        {
            Debug.Log("Hit something else");
        }
     }

…but am getting “NullReferenceException: Object reference not set to an instance of an object.” The collision logic works properly, but I’m stuck on how to pass the information back to the ShootAction or HealthSystem script.

Any suggestions?

Well, technically you didn’t have to change anything except the moveSpeed of the ‘bullet’. The death and destroy happens when the ‘bullet’ determines that it reached the target. Slowing down the moveSpeed would mean the bullet will take longer to reach the target. I’m not 100% sure how the bullet could cause the death and destroy itself if it hasn’t reached the target yet.

If you click on the error in the console, it will tell you where the NRE occurred and then you could determine what it was. It will help to know so we can solve your problem

My question was worded badly - let me try this again :slight_smile:

This is my current code, base on the course:

    private void Update() 
    {
        if(!isActive)
        {
            return;
        }

        stateTimer -= Time.deltaTime;

        switch(state)
        {
            case State.Aiming:
                break;
            case State.Shooting:
                if(canShootBullet)
                {
                    Shoot();
                    canShootBullet = false;
                }
                break;
            case State.Cooloff:
                break;
        }

        if (stateTimer <= 0f)
            {
                NextState();
            }
    }

    private void Shoot()
    {
        OnShoot?.Invoke(this, new OnShootEventArgs
        {
            targetUnit = targetUnit,
            shootingUnit = unit
        });       
        
        targetUnit.Damage(40); 
    }

The problem with this method is that the damage is occurring immediately, yet the projectile takes time reach the target. I could solve it by adding a script like this to my projectile…

     private void OnTriggerEnter(Collider other) 
     {
        if(other.tag == "Enemy")
        {
            Debug.Log("Hit Enemy");
            Destroy(other.gameObject);
        } 
        else
        {
            Debug.Log("Hit something else");
        }
     }

…and this works, if I want the enemy to just die. However, I don’t know how to modify the script, so that it is sending back information to the unit about damage taken instead.

Thoughts?

It’s my bad. My code is quite different from the course because I don’t like switch statements, so I have an actual state machine, and I didn’t like the fact that the UnitAnimator was spawning projectiles. Wasn’t paying attention to the damage happening as soon as the shoot happens.

My own project uses a bow and arrow and the arrows are slower than the really-fast bullets from the course. What I did was to add a state between State.Shooting and State.CoolOff (call it State.Damage). The Shoot state waits long enough for the arrow to reach the target before transitioning to the Damage state. This does the damage and immediately moves to the CoolOff state

Here I have adapted the course’s code with the damage state. I’ve made comments about what is what

private enum State
{
    Aiming,
    Shooting,
    Damage, // I added this to do the damage
    Cooloff,
}

private void Update()
{
    if (!isActive)
    {
        return;
    }

    stateTimer -= Time.deltaTime;

    switch (state)
    {
        case State.Aiming:
            Vector3 aimDir = (targetUnit.GetWorldPosition() - unit.GetWorldPosition()).normalized;
            float rotateSpeed = 10f;
            transform.forward = Vector3.Lerp(transform.forward, aimDir, Time.deltaTime * rotateSpeed);
            break;
        case State.Shooting:
            if (canShootBullet)
            {
                Shoot();
                canShootBullet = false;
            }
            break;
        case State.Damage:
            targetUnit.Damage(40); // here we do the damage
            break;
        case State.Cooloff:
            break;
    }

    if (stateTimer <= 0f)
    {
        NextState();
    }
}

private void NextState()
{
    switch (state)
    {
        case State.Aiming:
            state = State.Shooting;
            float shootingStateTime = 0.1f; // <-- This is how long you will wait before the damage state
            stateTimer = shootingStateTime;
            break;
        case State.Shooting:
            state = State.Damage;
            float damageStateTime = 0f; // No need to linger. We'll do damage and move on
            stateTimer = damageStateTime;
            break;
        case State.Damage:
            state = State.Cooloff;
            float coolOffStateTime = 0.5f;
            stateTimer = coolOffStateTime;
            break;
        case State.Cooloff:
            ActionComplete();
            break;
    }
}

And if you’re still reading, I’ll answer your question:
You have the enemy. Just get its unit and do damage

private void OnTriggerEnter(Collider other) 
{
    if(other.tag == "Enemy")
    {
        Debug.Log("Hit Enemy");
        if (other.TryGetComponent<Unit>(out var unit))
        {
            unit.Damage(40);
        }
    } 
    else
    {
        Debug.Log("Hit something else");
    }
}
2 Likes

Your solution at the end worked perfectly - thank you so much!

Follow-up question, for my curiosity: since the time the arrow takes will be greater than zero, how can you use a float of zero between the “Shooting” and “Damage” state? Won’t it be a different time every time (based on the distance to the enemy)?

This is why I don’t like state machines using switches. That 0f is how long we will be in the damage state. Not the time between shooting and damage. I added a comment where the ‘flight duration’ goes. It’s set to 0.1f from the course, but you would either calculate a time to be there, or set it to some larger ‘time-to-live’ and trigger the next state in some other way. My own ShootAction spawns the bullet (instead of the UnitAnimator) so I can track the bullet and transition when it has been destroyed

1 Like

Thank you :slight_smile:

Privacy & Terms