So I have three different 'bystanders' in my game world, each with an attached 'Bystander' script, and have a 'BystanderDialogue' element of my UI. The idea is that when the player comes in range of ANY of the bystanders, randomly selected text from a database is displayed, but for my script it only ever works for ONE of the bystanders.
I feel like I'm cross-referencing scripts too much or something, but I don't know. Here are the two sections of code:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Bystander : MonoBehaviour {
GameObject player;
public bool speak;
public bool isPlayerNear;
public int dialogueNumber;
GameObject bystanderDialogueObject;
BystanderDialogue bystanderDialogue;
// Use this for initialization
void Awake ()
{
player = GameObject.FindGameObjectWithTag ("Player");
bystanderDialogueObject = GameObject.Find ("BystanderDialogue");
bystanderDialogue = bystanderDialogueObject.GetComponent<BystanderDialogue> ();
}
// Update is called once per frame
void Update ()
{
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject == player)
{
dialogueNumber = Random.Range (0, bystanderDialogue.bystanderSpeech.Length);
speak = true;
isPlayerNear = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject == player)
{
speak = false;
isPlayerNear = false;
}
}
}
And the second one, attached to the UI object 'BystanderDialogue':
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class BystanderDialogue : MonoBehaviour {
Text text;
GameObject[] bystanderObjects;
Bystander bystander;
public string[] bystanderSpeech;
// Use this for initialization
void Awake ()
{
text = GetComponent<Text> ();
bystanderObjects = GameObject.FindGameObjectsWithTag ("NPC");
foreach (GameObject bystanderObject in bystanderObjects)
{
bystander = bystanderObject.GetComponent<Bystander> ();
}
}
// Update is called once per frame
void Update ()
{
BystanderSpeak (bystander);
if (bystander.isPlayerNear)
{
Debug.Log ("New bystander!");
}
}
void BystanderSpeak(Bystander bystander)
{
if (bystander.speak && bystander.isPlayerNear)
{
text.text = bystanderSpeech[bystander.dialogueNumber];
}
else if (!bystander.speak && !bystander.isPlayerNear)
{
text.text = "";
}
}
}
I'm very sure that I'm making some elementary mistakes, so apologies. Any help is much appreciated!
This code does not make sense:
void Awake ()
{
text = GetComponent<Text> ();
bystanderObjects = GameObject.FindGameObjectsWithTag ("NPC");
foreach (GameObject bystanderObject in bystanderObjects)
{
bystander = bystanderObject.GetComponent<Bystander> ();
}
}
If there are more than one bystanderObject, then you only kept the last object as reference into the bystander
member field. You should use a collection (list or array) instead to keep all of them:
Bystander[] bystanders;
void Awake()
{
bystanderObjects = GameObject.FindGameObjectsWithTag ("NPC");
bystanders = new Bystander[bystanderObjects.Length];
for (var i = 0; i < bystanderObjects.Length; ++i)
{
bystander[i] = bystanderObjects[i].GetComponent<Bystander>();
}
}
EDIT: it seams that you have a misconception of how everything works in Unity between two frames. I suggest you read Execution Order of Event Functions.
Your Update()
method will be completed before anything is drawn on the screen. So if you overwrite the value of Text
, only the last written value will be displayed. In fact, you need one Text
instance for each bystander
.