Object reference to OnTriggerEnter object in C#

Hey guys, I’m new to C# and have a little problem with my code. I’m trying to use OnTriggerEnter to see when a bullet hits an object, but I have no idea about how to change the player’s health through a script attached to the bullet.

Here’s my code:

void OnTriggerEnter (Collider hit) {

		if (hit.tag == "Enemy") {

			Destroy (this.gameObject);
			Debug.Log ("Hit " + hit.name);

			//These lines are my attempt, but they won't work.
			enemy = hit.gameObject.GetComponent <EnemyController> ();
			enemy.health -= gun.damage;
 		}
	}

At the top, I have assigned a private EnemyController called enemy.
EnemyController is the name of the script attached to all enemy objects, which also has the health variable set inside of it. I also have a reference to both the player object and the current gun.

Hope that’s all the info that’s needed, but if someone can help me and needs some extra information, I’d be more than happy to provide that.

Hi @Toff1n ,
I think the error comes from this line:

EnemyController enemy = GameObject.FindGameObjectWithTag("Enemy").GetComponent();

So, lets a bullet hits and object, when this happens the bullet reads the object’s tag to check if it is an enemy. Then, if it is an enemy, you destroy the bullet (this is ok) and you create an enemy variable which will look on the entire scene trying to find an object with the tag you want (“Enemy” in this case). As you say, there are more than one enemy, so the script will find more than one enemy. Why would you do that? If you are hitting the right enemy you want to reduce health to, you should use this (as you did at the beginning of this question):

enemy = hit.gameObject.GetComponent ();

That would reduce health to those enemies who got hit by that bullet (one if the bullet is destroyed).

Now, the enemy script should have a public variable called health, otherwise you won’t be able to reduce its health.
NOTE: This is not the best way of reducing enemies health. I recommend you to create a public event (i.e. called ReduceHealth()) with an imput parameter that we will use to calculate the amount of health we have to reduce). This way, the one who calculate the amount of damage is the enemy and not each bullet. So in your EnemyController script you should have an event like this:

public void ReduceHealth(int damage)
{
	//This is a simple way of reducing an enemy's health. You could create a more complicated script to calculate this damage, based on armor for example.
	health -= damage;
}

Once you have this, your script should look like this:

public float speed;
private float timeAlive;
public GameObject player;

private GunController gun;

void Start () {
    player = GameObject.Find ("Player");
    gun = player.GetComponent <GunController> ();
}

void Update () {
    BulletHandler ();
}

void OnTriggerEnter (Collider hit) {
    if (hit.tag == "Enemy") {
        Debug.Log ("Hit " + hit.name);
        EnemyController enemy = hit.gameObject.GetComponent<EnemyController>();
        enemy.ReduceHealth(gun.damage);
        Destroy (this.gameObject);
    }
}

void BulletHandler () {
    transform.Translate (Vector2.right * speed * Time.deltaTime);
    timeAlive += Time.deltaTime;
    if (timeAlive > 2) {
        Destroy (this.gameObject);
    }
}

That should work. If it doesn’t, I suggest you to upload the exact console output of the error, that way I could further help you.

So this method is in your GunController I guess. And your code tries to change the enemy’s health instead of the player’s health, right?

You could tag your player as “Player” and do something like this:

void OnTriggerEnter (Collider hit) {
    if (hit.tag == "Enemy") {
        Debug.Log ("Hit " + hit.name);

        // You still need a reference to gun, but that depends on your other code etc.
        PlayerController player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
        player.health -= gun.damage;

        // Destroy your GameObject at the end, not at the beginning
        Destroy (this.gameObject);
    }
}

So in this case the player health would decrease when the bullet hits an enemy. That makes no sense :smiley: but I hope you can adapt from there.

…but I have no idea about how to change the player’s health through a script attached to the bullet

It seems to me that the OP wants the bullet to give damage to the Player in addition to Enemy.

I think that the bullet should not be responsible for reducing health, but the objects that could be damaged by the bullet, should be responsible for reducing their own health, when they get hit by a bullet.

So the OnTriggerEnter should not be in the BulletController but in the EnemyController and PlayerController:

    void OnTriggerEnter(Collider other)
    {

        if (other.tag == "Bullet")
        {

            Debug.Log(name + " got hit by a bullet");

            //When an enemy or the player get hit by a bullet, their health is decreased
            health -= other.GetComponent<BulletController>().damage;

            Destroy(other.gameObject); //destroys the bullet
        }
    }

Of course the necessary fields must exist in the relative scripts, e.g. health and damage.

Hmh. I might be doing something wrong here, but I still get the error “Object reference not set to an instance of an object” on the line where I had the problem before.

It’s the full code this time, and it’s attached to the bullet. So it’s separate from GunController.
public class BulletController : MonoBehaviour {

	public float speed;
	private float timeAlive;

	public GameObject player;

	private GunController gun;

	void Start () {
		
		player = GameObject.Find ("Player");
		gun = player.GetComponent <GunController> ();
	}

	void Update () {

		BulletHandler ();
	}

	void OnTriggerEnter (Collider hit) {

		if (hit.tag == "Enemy") {

			Debug.Log ("Hit " + hit.name);

			EnemyController enemy = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyController>();

            //Here's the error, not sure whether it's the enemy or the gun
			enemy.health -= gun.damage;

			Destroy (this.gameObject);
 		}
	}

	void BulletHandler () {

		transform.Translate (Vector2.right * speed * Time.deltaTime);

		timeAlive += Time.deltaTime;
		if (timeAlive > 2) {
			Destroy (this.gameObject);
		}
	}
}

@Vencarii any chance that you knew what’s going wrong?