Null Reference in script after having called other class without a null reference
Hello,
I'm in the process of creating the backbone for a training system for a tactic driven game. I've set up two means of increasing stats/attributes: doing jobs when the turn ends, and being actively trained. I have an "End Turn" button that is attached to a UIManager script (see below) that sets the doJobs bool to true and does the jobs as I'd expect. This is accomplished by clicking a button with the OnPointerDown() function that holds a value, and then clicking on a character in the roster to assign the job.
I've set up the training ID the same as the job ID, with buttons having an OnPointerDown() call to pass the ID to a global variable, and a pairing for that to the character ID in the update function of the roster. When trying to do training however, I'm getting a NullRef.
In the past I've solved this by just making sure everything is assigned properly in the inspector, but I'm calling Roster more than once in this script and it's only throwing it for training.
the jobs/training is done here:
public class JobDoer:Monobehavior
{
bool doJobs = false;
bool doTraining = false;
public Roster charRost;
public void JobsOnTurnEnd()
{
if (doJobs == true)
foreach (BaseCharacter b in charRost.characterRoster)
{
if (b.jobID == 0)
{
JobRest(b);
}
}
}
public void Training()
{
if (doTraining == true)
foreach (BaseCharacter b in charRost.characterRoster) //null reference gets thrown here
{
if (b.trainID == 1)
{
TrainStrength(b);
}
}
}
}
I genuinely have no idea why this is happening and have spent the bulk of the last 2 days tracing back through my code over and over again, with no results. I'm able to get the training ID set to the student ID (checked it through debugging), but when I do a training trigger it throws the above error. If anyone could help I would greatly appreciate it.
[EDIT]: I tried using the doJobs bool and the end turn button to do the training, and it works that way; so it seems the issue is related to the trigger.
The above may not be enough information to go on, so below are trimmed versions of scripts that have some sort of interaction with the above.
public class CharacterData
{
public int characterID;
//attributes
public int strength = 0;
//job/training stuff
public int trainID = 0;
public int jobID = 0;
public bool isStudent = false;
}
which is used as the data for:
public class BaseCharacter: CharacterData
{
}
I then use the BaseCharacter class to create an array of characters:
public class Roster :MonoBehaviour
{
public void CreateRoster() //creates character data
{
characterRoster = new BaseCharacter[characters];
for (int i = 0; i < characters; i++)
{
characterRoster[i] = new BaseCharacter();
characterRoster[i].characterID = i; //generates ID
//then I generate the rest of the attributes by a random number generator adding to each and decrementing from a pool
}
public void PopulateRosterPanel(int start, int last)
{
//here I set up a roster of prefab panels between some bounds
}
public int SelectStudent() //allows for selecting a character
{
foreach (BaseCharacter b in characterRoster)
{
bool der = //is the mouse over the character's panel?
bool canSelect = true;
if (der && canSelect)
{
if (Input.GetMouseButtonDown(0)) //on left click, select one
{
selectedID =b.characterID;
jobCharacterID.IDPair(b); //pairs the job id with the character
}
}
}
return selectedID;
}
void Update()
{
studentTrain.TrainID(characterRoster[SelectedVar.StudentID]);
}
}
The job assignment stuff:
public class Jobs : MonoBehaviour, IPointerDownHandler{
public int jobID;
public void OnPointerDown(PointerEventData eventData) //default ID = 0
{
if (this.gameObject.name == "RestButton")
{
jobID = 0;
}
}
public int JobAssign(int JID) //character or characterID and JobID
{
JobVar.JobID = JID;
return JobVar.JobID;
}
public void IDPair(BaseCharacter b)
{
b.jobID = JobVar.JobID;
if (b.jobID == 5)
{
SelectedVar.StudentID = b.characterID;
b.isStudent = true;
}
}
The end turn job triggers:
public class UIManager : MonoBehaviour
{
public JobDoer turnJobs;
public void EndTurn()
{
turnJobs.doJobs = true;
turnJobs.JobsOnTurnEnd();
}
Training stuff:
public class StudentTraining : MonoBehaviour , IPointerDownHandler
{
public void OnPointerDown(PointerEventData eventData)
{
if (this.gameObject.name == "TrainStrengthButton")
{
trainID = 1;
}
TrainAssign(trainID);
}
public int TrainAssign(int TID)
{
JobVar.TrainID = TID;
return JobVar.TrainID;
}
public void TrainID(BaseCharacter b)
{
b.trainID = JobVar.TrainID;
}
}
and my training trigger (which I've tried attached both to the instantiated student prefab and to a non-instantiated button in the student panel) is :
public class ToggleTraining : MonoBehaviour
{
public JobDoer jobDo;
public void Toggle()
{
jobDo.doTraining = true;
jobDo.Training();
}
}
where I've got 3 global variables for student, job, and training id:
public static class JobVar
{
static int _jobID;
public static int JobID
{
get { return _jobID; }
set { _jobID = value; }
}
static int _trainID;
public static int TrainID
{
get { return _trainID; }
set { _trainID = value; }
}
}
public static class SelectedVar
{
static int _studentID;
public static int StudentID
{
get { return _studentID; }
set { _studentID = value; }
}
}
You really should use some Debug.Log()'ing to deter$$anonymous$$e where the scope of your issue is. Posting your entire code base is usually a bad idea, especially since it discourages other Unity developers from reading your entire post and helping you.
Anyways, do Debug.Log(charRost.gameObject.Name);
before your foreach statement on line 20 in your JobDoer object. What happens when you run that code?
Your answer
Follow this Question
Related Questions
Null Reference Exception Error 1 Answer
Bugs on my C# Scripts? 0 Answers
Null Reference Exception when changing material shader 0 Answers
NullReferenceException, Script Error 1 Answer