0

I have a script for attacking, and it checks to see if the object has the "Enemy script" like so:

// Damage them
foreach (Collider2D enemy in hitEnemies)
{
    // Debug log showing the attack connected
    Debug.Log("We hit " + enemy.name);`

    // the enemy takes damage from the player, could be rewritten
    enemy.GetComponent<Enemy>().TakeDamage(attackDamage);
}

Now the issue is, it only checks to see if they object has that script. I need to also make it check for a boss script that has the load area method in it.

I can have it be only a Enemy script or the EnemyLoadArea script. The idea is, that only bosses have the EnemyLoadArea script. If I change it from "enemy.GetComponent" to "enemy.GetComponent", Unity no longer recognizes the damage, and the enemy doesn't die.

There may be a better way to have a scene load on a boss death, but I don't know if there is.

I can't leave fields blank in Unity, so I can't have the load area code in the enemy script. How can I get it to check for two different gameobjects? Or even, how can I rewrite the code to check for a tag in Unity? So instead of finding the Enemy script, it checks to see if the NPC is tagged as an Enemy, and then take damage?

I've tried using

enemy.GetComponent<Enemy || EnemyLoadArea>().TakeDamage(attackDamage);

and

enemy.GetComponent<Enemy>().TakeDamage(attackDamage);
enemy.GetComponent<EnemyLoadArea>().TakeDamage(attackDamage);

and also tried reusing the same foreach method with the component being changed from "" to <"EnemyLoadArea"> but it doesn't work either.

Every different fix I've tried return in errors like "|| cannot be used", or just

NullReferenceException: Object reference not set to an instance of an object PlayerAttack.Attack () (at Assets/Scripts/Player/PlayerAttack.cs:53) PlayerAttack.Update () (at Assets/Scripts/Player/PlayerAttack.cs:30)

  • 1
    Pretend for a moment that we don't know why you "can't have the load area code in the enemy script". You want to rephrase that whole paragraph? My initial thought is that you could use an interface such as *IDamagable* on both `Enemy` and `EnemyLoadArea`, and then do a `TryGetCompoent (out var d)`. Once you've got `d` you would then call `d.TakeDamage(attackDamage)` – Milan Egon Votrubec Mar 11 '23 at 06:46
  • @MilanEgonVotrubec I have no idea what you mean tbh :( However, the EnemyLoadArea script does work if I change the code from enemy.GetComponent to enemy.GetComponent, but then the normal enemies don't register as taking a damage. – Moonlit Buns Mar 11 '23 at 09:55

1 Answers1

1

If you want to retrieve a component from an object, but you're not sure if the object really has that component, you can use TryGetComponent(). It return true if the object has the component you're looking for, and if it does, the component is assigned to the out parameter. The code could look something like this:

if (enemy.TryGetComponent<Enemy>(out Enemy _) ||
    enemy.TryGetComponent<EnemyLoadArea>(out EnemyLoadArea _))
{
    enemy.TakeDamage(attackDamage);
}

But the better way to solve this is to restructure your class hierarchy using interface. interface's prime purpose is to group classes that have related functionalities together. Because both of Enemy and EnemyLoadArea can be attacked, this is the perfect case to implement a common interface for them. You could define something like this:

public interface IAttackable
{
    public void TakeDamage(float amount);
}

You can then have both Enemy and EnemyLoadArea implement the interface.

public class Enemy : MonoBehaviour, IAttackable
{
    // ...
    
    public void TakeDamage(float amount)
    {
        // Do something
    }
}


public class EnemyLoadArea : MonoBehaviour, IAttackable
{
    // ...
    
    public void TakeDamage(float amount)
    {
        // Do something
    }
}

Later, to deal damage to an attackable object, you don't need to care whether it is an Enemy or an EnemyLoadArea, you can just do this:

if (enemy.TryGetComponent<IAttackable>(out IAttackable attackable))
{
    attackable.TakeDamage(attackDamage);
}

You can google to find out more about interface, or have a quick read on this answer on another question.