I have been trying to debug this for a while now but can’t figure out for the life of me why this error is occurring.
The error occurs at line 45 when trying to use the method EnemyTakeDamage which is in another script EnemyCombat. The error says:
NullReferenceException: Object reference not set to an instance of an object
Projectile.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Projectile.cs:45)
What’s weird about this is that I don’t have this problem for the script Player_Combat and accessing the PlayerTakeDamage method which are pretty identical to EnemyCombat and EnemyTakeDamage method. If anyone could point out any errors they see, that would be helpful as I cannot see anything wrong. Thank you in advance!
Projectile Script where the error occurs on line 45
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Projectile : MonoBehaviour
{
public float speed = 8f;
public int damage = 5;
// Start is called before the first frame update
//2 ways of handling public classes from other scripts
//plugging in the public game object and using get component to access the script
//public GameObject player;
//OR accessing the script and then accessing the classes inside that script
public Player_Combat PlayerCombat;
public EnemyCombat enemy_Combat;
public GameObject thisObject;
public bool Player;
void Update()
{
//moves the projectile forward
transform.position += (transform.forward) * speed * Time.deltaTime;
}
//triggers damage on hit
private void OnTriggerEnter(Collider other)
{
Debug.Log("HIT");
if (other.gameObject.tag == "Player")
{
//player.GetComponent<Player_Combat>().PlayerTakeDamage(2);
PlayerCombat.PlayerTakeDamage(damage);
thisObject.SetActive(false);
}
else if (other.gameObject.tag == "Enemy")
{
Debug.Log("enemy hit");
thisObject.SetActive(false);
enemy_Combat.EnemyTakeDamage(damage);
}
}
}
EnemyCombat script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyCombat : MonoBehaviour
{
public GameObject EmpathySphere;
public GameObject HateSphere;
public Transform EnemyPosition;
public bool canFire;
//maybe have an enemymanager script that handles this stuff later
//enemy stats
public int enemyMaxHealth = 20;
public int enemyCurrentHealth;
public int enemyStartingHealth = 20;
private int enemyMinHealth = 0;
public float shootSpeed = 2.5f; //how many seconds between shots
public HealthBarScript healthBar;
// Start is called before the first frame update
void Start()
{
enemyCurrentHealth = enemyStartingHealth;
healthBar.SetMaxHealth(enemyMaxHealth);//once ur health reaches 100 and your opponents reaches 100 u win
healthBar.SetHealth(enemyStartingHealth);
StartCoroutine(RandomFire());
}
// Update is called once per frame
void Update()
{
if (canFire == true && enemyCurrentHealth != enemyMaxHealth)
{
//choosing random ability
int randomNumber = Random.Range(1, 6);
Debug.Log("randomNumber: " + randomNumber);
Move(randomNumber);
if (randomNumber < 4)
{
ShootHateSphere();
}
else if (randomNumber >= 4)
{
//Debug.Log("empathy sphere");
ShootEmpathySphere();
}
}
}
//coroutine to fire bullets in random interval
IEnumerator RandomFire()
{
yield return new WaitForSeconds(Random.Range(0.5f, shootSpeed));
canFire = true;
}
public void EnemyTakeDamage(int damage)
{
if(enemyCurrentHealth != enemyMinHealth)
{
enemyCurrentHealth -= damage;
healthBar.SetHealth(enemyCurrentHealth);
}
}
public void ShootHateSphere()
{
//Instantiate(HateSphere, EnemyPosition.position, EnemyPosition.rotation);
//using singleton allows me to access objectpooler just through objectpooler.instance instead of having to establish the class in this script first
ObjectPooler.Instance.SpawnFromPool("EnemyHateSphere", EnemyPosition.position, EnemyPosition.rotation);
canFire = false;
StartCoroutine(RandomFire());
}
public void ShootEmpathySphere()
{
ObjectPooler.Instance.SpawnFromPool("EnemyEmpathySphere", EnemyPosition.position, EnemyPosition.rotation);
canFire = false;
StartCoroutine(RandomFire());
}
public void Move(int direction)
{
//maybe find another way to do this or move to another file as this will vary from enemy to enemy
switch (direction)
{
case 1:
this.transform.position = new Vector3(3, 1.5f, 9);
break;
case 2:
this.transform.position = new Vector3(0, 1.5f, 9);
break;
case 3:
this.transform.position = new Vector3(-3, 1.5f, 9);
break;
case 4:
this.transform.position = new Vector3(-6, 1.5f, 9);
break;
case 5:
this.transform.position = new Vector3(6, 1.5f, 9);
break;
}
}
}
Here’s the Player_Combat script that doesn’t have any errors when accessed by the Projectile Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Combat : MonoBehaviour
{
public int playerMaxHealth = 20;
public int playerCurrentHealth;
public int playerStartingHealth = 10;
private int playerMinHealth = 0;
public float ShootSpeed = 1.5f;
bool canFire = true;
public Transform PlayerPosition;
public HealthBarScript healthBar; //reference to the public class health bar script
// Start is called before the first frame update
void Start()
{
playerCurrentHealth = playerStartingHealth;
healthBar.SetMaxHealth(playerMaxHealth);//once ur health reaches 100 and your opponents reaches 100 u win
healthBar.SetHealth(playerStartingHealth);
StartCoroutine(SetFire());
}
// Update is called once per frame
void Update()
{
if (canFire == true)
{
//choosing random ability
PlayerEmpathySphere();
//Debug.Log("empathy sphere");
}
}
public void PlayerTakeDamage(int damage)
{
if(playerCurrentHealth != playerMinHealth)
{
playerCurrentHealth -= damage;
healthBar.SetHealth(playerCurrentHealth);
}
}
void PlayerEmpathySphere()
{
ObjectPooler.Instance.SpawnFromPool("PlayerEmpathySphere", PlayerPosition.position, PlayerPosition.rotation);
canFire = false;
StartCoroutine(SetFire());
}
IEnumerator SetFire()
{
yield return new WaitForSeconds(ShootSpeed);
canFire = true;
}
}