Hi guys, i’m trying to Write my first “game” on unity 2d and so far i managed to find a solution to my problems… .except for this one:
I Have a GameManager(Script) that have to call a function from a Script associated to a GameObject on the screen, but it just won’t do it. This is my GameManager:
public class GameManager : MonoBehaviour {
private GameManager instance = null;
public GameObject enemy;
private Enemy enemyScript;
// Use this for initialization
void Awake()
{
hasEnded = false;
if (instance == null)
instance = this;
else if (instance != null)
Destroy(gameObject);
SetUpScene();
enemyScript =GameObject.Find("Enemy").GetComponent<Enemy>();
playerHealth = playerHealthMax;
}
void Update () {
if (enemyScript.canShoot == true)
{
EnemyShoot();
}
if (hasEnded == true)
this.enabled = false;
}
//ENEMY
public void EnemyShoot()
{
print("EnemyShoot() Called| ");
int direzioneRandom = directions[UnityEngine.Random.Range(0, directions.Length)];
enemyScript.ShootTimered(direzioneRandom);
}
}
And this is the script i want to use from GameManager:
public class Enemy : MonoBehaviour {
private Animator animator;
public bool canShoot;
public GameObject fulmine;
private float shootingFrequency = 8f;
// Use this for initialization
void Start () {
animator = GetComponent<Animator>();
canShoot = true;
}
public IEnumerator ShootTimered(int dir)
{
print("ShootTimered Called| ");
canShoot = false;
yield return new WaitForSeconds(Mathf.Log(2, shootingFrequency));
Shoot(dir);
if (shootingFrequency >= 2f)
shootingFrequency -= 0.25f;
canShoot = true;
}
}
I can’t understand why but i get a NullReferenceException. Thank you for the help
Null again on Line : “enemyScript = GameObject.Find(“Enemy”).GetComponent();”
why should it be null? the enemy spawns on the scene… i don’t understand this
Order of objects initialization is not guaranteed (unless you manually set it up, but that’s only for special cases and in general should be last resort). When you’re running GameObject.Find from Awake, the object you’re trying to find may not yet be active and this function only finds active objects.
Try moving it the Find part to Start instead.
In general Awake should be used for self initialization, while Start for setting up references, unless you’re guaranteed to have the other object and you really need it in Awake (f.e. to have it in OnEnable).
As a sidenote, I’d change the Coroutine to be private and add a public void StartShooting() in the enemy, checking the canShoot there before starting it. Being able to start a coroutine on an object from outside without any checks is error prone - even if your GameManager does check before starting it right now, that’s still not safe in the long run.
public class Enemy : MonoBehaviour
{
private Animator animator;
private bool canShoot; // changed to private
public GameObject fulmine;
private float shootingFrequency = 8f;
// Use this for initialization
void Start()
{
animator = GetComponent<Animator>();
canShoot = true;
}
public void StartShooting(int dir)
{
if (canShoot)
{
canShoot = false;
StartCoroutine(ShootTimered(dir));
}
}
IEnumerator ShootTimered(int dir)
{
print("ShootTimered Called| ");
yield return new WaitForSeconds(Mathf.Log(2, shootingFrequency));
Shoot(dir);
if (shootingFrequency >= 2f)
shootingFrequency -= 0.25f;
canShoot = true;
}
}
One last thing you could also do is get rid of the Find completely and use [SerializeField] to set the connection in the inspector while keeping it private.