After finishing the Aggro Group lecture my HasNext is now getting a null error message:
NullReferenceException: Object reference not set to an instance of an object
RPG.Dialogue.PlayerConversant.HasNext () (at Assets/Scripts/Dialogue/PlayerConversant.cs:91)
RPG.UI.DialogueUI.UpdateUI () (at Assets/Scripts/UI/DialogueUI.cs:55)
RPG.UI.DialogueUI.Start () (at Assets/Scripts/UI/DialogueUI.cs:30)
Dialogue currentDialogue is not set to null at the beginning but even setting it to null does not change the error. The script project now does not like the message and I am not sure why.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace RPG.Dialogue
{
public class PlayerConversant : MonoBehaviour
{
Dialogue currentDialogue;
DialogueNode currentNode = null;
AIConversant currentConversant = null;
bool isChoosing = false;
public event Action onConversationUpdated;
public void StartDialogue(AIConversant newConversant, Dialogue newDialogue)
{
currentConversant = newConversant;
currentDialogue = newDialogue;
currentNode = currentDialogue.GetRootNode();
TriggerEnterAction();
onConversationUpdated();
}
public void Quit()
{
currentDialogue = null;
TriggerExitAction();
currentNode = null;
isChoosing = false;
currentConversant = null;
onConversationUpdated();
}
public bool IsActive()
{
return currentDialogue != null;
}
public bool IsChoosing()
{
return isChoosing;
}
public string GetText()
{
if (currentDialogue == null)
{
return "";
}
return currentNode.GetText();
}
public IEnumerable<DialogueNode> GetChoices()
{
return currentDialogue.GetPlayerChildren(currentNode);
}
public void SelectChoice(DialogueNode chosenNode)
{
currentNode = chosenNode;
TriggerEnterAction();
isChoosing = false;
// onConversationUpdated(); // Only call onConversationUpdated() here if not calling Next().
Next(); // Moves directly to the next node in dialogue rather than display button response text.
}
public void Next()
{
int numPlayerResponses = currentDialogue.GetPlayerChildren(currentNode).Count();
if (numPlayerResponses > 0)
{
isChoosing = true;
TriggerExitAction();
onConversationUpdated();
return;
}
DialogueNode[] children = currentDialogue.GetAIChildren(currentNode).ToArray();
int randomIndex = UnityEngine.Random.Range(0, children.Count());
TriggerExitAction();
currentNode = children[randomIndex];
TriggerEnterAction();
onConversationUpdated();
}
public bool HasNext()
{
return currentDialogue.GetAllChildren(currentNode).Count() > 0;
}
private void TriggerEnterAction()
{
if (currentNode != null)
{
TriggerAction(currentNode.GetOnEnterAction());
}
}
private void TriggerExitAction()
{
if (currentNode != null)
{
TriggerAction(currentNode.GetOnExitAction());
}
}
private void TriggerAction(string action)
{
if (action == "")
{
return;
}
foreach (DialogueTrigger trigger in currentConversant.GetComponents<DialogueTrigger>())
{
trigger.Trigger(action);
}
}
}
}
Then here is the code that is for the rest of the error when the rest of the error:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Dialogue;
using TMPro;
using UnityEngine.UI;
using System;
namespace RPG.UI
{
public class DialogueUI : MonoBehaviour
{
PlayerConversant playerConversant;
[SerializeField] TextMeshProUGUI AIText;
[SerializeField] Button nextButton;
[SerializeField] GameObject AIResponse;
[SerializeField] Transform choiceRoot;
[SerializeField] GameObject choicePrefab;
[SerializeField] Button quitButton;
[SerializeField] TextMeshProUGUI conversantName;
// Start is called before the first frame update
void Start()
{
playerConversant = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerConversant>();
playerConversant.onConversationUpdated += UpdateUI;
nextButton.onClick.AddListener(() => playerConversant.Next());
quitButton.onClick.AddListener(() => playerConversant.Quit());
UpdateUI();
}
// Update is called once per frame
void Update()
{
}
void UpdateUI()
{
gameObject.SetActive(playerConversant.IsActive());
if (playerConversant.IsActive())
{
return;
}
AIResponse.SetActive(!playerConversant.IsChoosing());
choiceRoot.gameObject.SetActive(playerConversant.IsChoosing());
if (playerConversant.IsChoosing())
{
BuildChoiceList();
}
else
{
AIText.text = playerConversant.GetText();
nextButton.gameObject.SetActive(playerConversant.HasNext());
}
}
private void BuildChoiceList()
{
foreach (Transform item in choiceRoot)
{
Destroy(item.gameObject);
}
foreach (DialogueNode choice in playerConversant.GetChoices())
{
GameObject choiceInstance = Instantiate(choicePrefab, choiceRoot);
var textComponent = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
textComponent.text = choice.GetText();
Button button = choiceInstance.GetComponentInChildren<Button>();
button.onClick.AddListener(() =>
{
playerConversant.SelectChoice(choice);
});
}
}
}
}