Class array initialization on Start() gives -> Object reference not set to an instance of an object
Hi everyone,
I'm creating a very simple local multiplayer game. In my case, I have a lobby screen, where I get the amount of players who are going to play. Then, I save this to a GameData class to load the info into the game scene. Here's the GameData class: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class GameData : MonoBehaviour {
public static GameData gameData;
private Player[] playerList;
// Use this for initialization
void Awake () {
if (gameData == null)
{
DontDestroyOnLoad(gameData);
gameData = this;
} else if(gameData != this)
{
Destroy(gameObject);
}
}
public void SavePlayersToPlay(Player[] players)
{
playerList = new Player[players.Length];
for (int i=0; i<playerList.Length; ++i)
{
playerList[i] = new Player
{
name = players[i].name,
num = players[i].num,
color = players[i].color
};
}
}
public Player GetPlayer(int i)
{
return playerList[i];
}
public int GetTotalPlayers()
{
return playerList.Length;
}
public string GetPlayerName(int i)
{
return playerList[i].name;
}
}
After all the number of players are saved, I load the match scene, which has a Matchmanager class. This class is responsible of spawning the players with the info of GameData (number of players, color, name, etc), generate the match scenario, set the camera, etc. Also the MatchManager has an PlayerManager array, which controls all the player stuff like set player active, disable player control, etc.
This is the PlayerManager class:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager
{
[HideInInspector] public Color playerColor;
[HideInInspector] public Transform spawnPoint;
[HideInInspector] public string playerName;
[HideInInspector] public int playerNumber;
[HideInInspector] public GameObject Instance;
[HideInInspector] public int playerWins;
//private PlayerMotor _playerMotor;
private PlayerMotor _playerMotor;
public void Setup(float jetpackTime, float dizzyTime)
{
//_playerMotor = Instance.GetComponent<PlayerMotor>();
_playerMotor = Instance.GetComponent<PlayerMotor>();
//inicializamos los tiempos de los powerups
Instance.GetComponent<PlayerState>().SetPowerUpsTime(jetpackTime, dizzyTime);
_playerMotor.playerNumber = playerNumber;
MeshRenderer[] renderers = Instance.GetComponentsInChildren<MeshRenderer>();
for (int i=0; i<renderers.Length; ++i)
{
renderers[i].material.color = playerColor;
}
}
public State CurrentState()
{
return Instance.GetComponent<PlayerState>().healthState;
}
public void SetControl(bool control)
{
_playerMotor.enabled = control;
}
public bool IsActive()
{
return _playerMotor.enabled;
}
public void ActivateDizzyMode()
{
Instance.GetComponent<PlayerState>().SetDizzy();
}
public bool WantToEnableDizzy()
{
bool value = Instance.GetComponent<PlayerState>().GetMyPowerup() == Powerups.DizzyControls && Instance.GetComponent<PlayerState>().IsPowerUpEnabled();
if (value)
{
//he gastado el dizzy
Instance.GetComponent<PlayerState>().DisablePowerUp();
}
return value;
}
public void Reset()
{
Instance.transform.position = spawnPoint.position;
Instance.transform.rotation = spawnPoint.rotation;
Instance.SetActive(false);
Instance.SetActive(true);
}
}
In the Start() method of the MatchManager, I fulfill the PlayerManager array, with all the data loaded from GameData, and then, I started the Gameloop coroutine, who manages all the gameloop. When the Gameloop is started, more concretely in the RoundStarting() method, the Editor gives me the error :
NullReferenceException: Object reference not set to an instance of an object
MatchManager.SetCameraTargets () (at Assets/Scripts/MatchManager.cs:87)
MatchManager+<RoundStarting>c__Iterator1.MoveNext () (at Assets/Scripts/MatchManager.cs:151)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
MatchManager:Start() (at Assets/Scripts/MatchManager.cs:67)
So, Its like the PlayerManager array is not being initialized correctly and I don't know what I'm doing wrong.
Here is the MatchManager class:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MatchManager : MonoBehaviour {
public float
roundTime, startRoundDelay, losetaFallTime, powerupSpawnTime, endRoundDelay;
public float
jetpackTime, dizzyTime;
public GameObject playerPrefab;
public PowerUp[] powerUps;
public MapGenerator map;
private WaitForSeconds
startWait, endWait;
private float throwLoseta = 0f;
private float instantiatePowerup = 0f;
private float elapsedRoundTime;
public CameraControl camControl;
private Vector2 _mapSize;
private PlayerManager[] players;
public void SetupMatch()
{
Debug.Log("Number of loaded Players: " + GameData.gameData.GetTotalPlayers());
//Get Map size and Setup map Generator.
map = GetComponent<MapGenerator>();
_mapSize = map.GetMapSize();
}
// Use this for initialization
void Start ()
{
elapsedRoundTime = roundTime;
startWait = new WaitForSeconds(startRoundDelay);
endWait = new WaitForSeconds(endRoundDelay);
PlayerManager[] players = new PlayerManager[GameData.gameData.GetTotalPlayers()];
for (int i = 0; i < players.Length; ++i)
{
players[i] = new PlayerManager();
Player tmpPlayer = GameData.gameData.GetPlayer(i);
Debug.Log(tmpPlayer.color);
players[i].playerColor = tmpPlayer.color;
players[i].playerNumber = tmpPlayer.num;
Debug.Log("Setting Player: " + players[i].playerNumber);
players[i].playerName = tmpPlayer.name;
players[i].spawnPoint = GameObject.Find("spawnPoint_" + (i + 1)).transform;
players[i].Instance = Instantiate(playerPrefab, players[i].spawnPoint.position, players[i].spawnPoint.rotation) as GameObject;
players[i].Setup(jetpackTime, dizzyTime);
}
SetupMatch();
StartCoroutine(GameLoop());
}
private void SpawnPlayers()
{
/*
for (int i=0; i<players.Length; ++i)
{
players[i].Instance = Instantiate(playerPrefab, players[i].spawnPoint.position, players[i].spawnPoint.rotation) as GameObject;
players[i].Instance.name = "Jugador_" + (i + 1);
players[i].playerNumber = i + 1;
players[i].Setup(jetpackTime, dizzyTime);
}*/
}
private void SetCameraTargets()
{
// Create a collection of transforms the same size as the number of tanks.
Debug.Log("Target num: " + players.Length);
Transform[] targets = new Transform[players.Length];
// For each of these transforms...
for (int i = 0; i<targets.Length; ++i)
{
// ... set it to the appropriate tank transform.
targets[i] = players[i].Instance.transform;
}
// These are the targets the camera should follow.
camControl.m_Targets = targets;
}
private void ResetAllPlayers()
{
for (int i = 0; i < players.Length; ++i)
{
players[i].Reset();
}
}
private void DisableAllPlayerControls()
{
for (int i = 0; i < players.Length; ++i)
{
players[i].SetControl(false);
}
}
private void EnableAllPlayerControls()
{
for (int i = 0; i < players.Length; ++i)
{
players[i].SetControl(true);
}
}
private bool OnePlayerLeft()
{
int numPlayersAlive = 0;
Debug.Log("> OnePlayerLeft() < -| Total Players: " + players.Length);
for (int i = 0; i < players.Length; ++i)
if (players[i].Instance.activeSelf)
++numPlayersAlive;
return numPlayersAlive < 1;
}
public IEnumerator GameLoop()
{
Debug.Log("Gameloop Starts");
yield return RoundStarting();
yield return RoundPlaying();
yield return RoundEnding();
Debug.Log("Loading new match...");
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
public IEnumerator RoundStarting()
{
Debug.Log("Preparing match...");
map.GenerateMap((int)_mapSize.x, (int)_mapSize.y);
SpawnPlayers();
SetCameraTargets();
ResetAllPlayers();
DisableAllPlayerControls();
yield return startWait;
}
public IEnumerator RoundPlaying()
{
Debug.Log("Match Started!!!");
EnableAllPlayerControls();
while (IsRoundRunning())
{
throwLoseta += Time.deltaTime;
if (throwLoseta >= losetaFallTime)
{
if (map.ActiveLosetas() > 0)
{
map.FallLoseta(map.GetRandomCoord());
throwLoseta = 0f;
}
else elapsedRoundTime = 0f;
}
instantiatePowerup += Time.deltaTime;
if (instantiatePowerup >= powerupSpawnTime)
{
if (map.ActiveLosetas() > 0)
{
instantiatePowerup = 0f;
//Instancio un powerup random en funcion de su probabilidad en la posicion random de una de las losetas aun activas.
Instantiate(powerUps[GetPowerUpToSpawn()].prefab, map.GetActiveLoseta().position, Quaternion.identity);
}
else elapsedRoundTime = 0f;
}
elapsedRoundTime -= Time.deltaTime;
//Debug.Log("Tiempo Restante: " + elapsedRoundTime.ToString("f0"));
yield return null;
}
}
public IEnumerator RoundEnding()
{
DisableAllPlayerControls();
Debug.Log("Match Ended!!!");
yield return endWait;
}
public void EnableDizzy(int player)
{
//dizzyEnabled = true;
Debug.Log("Dizzy Mode enabled");
for (int i = 0; i < players.Length; ++i)
{
if (players[i].playerNumber != i-1)
{
players[i].ActivateDizzyMode();
}
}
}
public bool IsRoundRunning()
{
return elapsedRoundTime > 0f && !OnePlayerLeft();
}
//devuelve el powerup que se va a instanciar, en función de la probabilidad asignada
public int GetPowerUpToSpawn()
{
float total = 0f;
for (int i = 0; i < powerUps.Length; ++i){
total += powerUps[i].probability + 0.0f;
}
float randomPoint = UnityEngine.Random.value * total;
for (int i = 0; i < powerUps.Length; i++){
if (randomPoint < powerUps[i].probability)
return i;
else
randomPoint -= powerUps[i].probability;
}
return powerUps.Length - 1;
}
// Update is called once per frame
void Update ()
{
//dizzy enabled?
if (IsRoundRunning())
{
for (int i=0; i<players.Length; ++i)
{
if (players[i].WantToEnableDizzy()/* && !dizzyEnabled*/)
{
EnableDizzy(i+1);
}
}
}
}
}
Anybody knows what is happening here? How I should initialize my PlayerManager array?
Thanks in Advance!! (and sorry for my bad english) Rodri
Answer by rodrybest · May 08, 2018 at 09:09 PM
Well... finally I got the solution.
The PlayerManager array must be initialized in the same declaration line :
private PlayerManager[] players = new PlayerManager[GameData.gameData.GetTotalPlayers()];
instead of:
void Start ()
{
PlayerManager[] players = new PlayerManager[GameData.gameData.GetTotalPlayers()];
}
Doing it on Start() method initializes the array locally on Start() and after exiting this method the values of PlayerManager[] no longer exists.
Noob mistake!!!!