so i have this NPC, and if you talk to him the bool haveSoil becomes true. and i want one of the other npcs dialogue to change when this bool is true. ik how to change the dialogue, but the problem im facing is accessing the bool haveSoil from another script.
We may need more details to suggest a proper answer.
Let’s say NPC1 has a script named MyScript with the haveSoil bool.
NPC2 needs to read the value of NPC1’s haveSoil bool.
There are some quick and dirty ways to read the bool. For example, you can find NPC1 by name and then get the script on it:
if (GameObject.Find("NPC1").GetComponent<MyScript>().haveSoil) ...
In practice, you’d want to make sure Gameobject.Find and GetComponent don’t return null. But I won’t even bother detailing that because the whole approach is messy and error-prone.
Instead, you could give NPC2 an explicit reference to NPC1’s MyScript. For example, in a script on NPC2, define a public variable that you can assign in the Inspector:
public MyScript npc1Script;
Then you can check NPC1’s haveSoil like this:
if (npc1Script.haveSoil) ...
But even that’s not great because you have to manually hook up NPC1’s script to NPC2 in the Inspector. It would be better if NPC1 could register itself with some kind of registry. The NPC2 could then find NPC1 through the registry, without requiring a direct assignment to NPC1. For example, let’s say the global registry class looks like this:
public static class CharacterRegistry // Note: Not a MonoBehaviour
{
private static Dictionary<string, GameObject> dict = new Dictionary<string.GameObject>();
public static void RegisterCharacter(string characterName, GameObject characterGO)
{
dict[characterName] = characterGO;
}
public static void UnregisterCharacter(string characterName)
{
dict.Remove(characterName);
}
public static GameObject GetCharacter(string characterName)
{
GameObject characterGO;
return dict.TryGetValue(characterName, characterGO) ? characterGO : null;
}
}
Then each NPC could have a script like:
public class Character : MonoBehaviour
{
public string characterName;
void Awake()
{
CharacterRegistry.RegisterCharacter(characterName, this.gameObject);
}
void OnDestroy()
{
CharacterRegistry.RegisterCharacter(characterName);
}
}
It still uses strings, but they’re not tied to something delicate like GameObject names.
Now NPC2 can get NPC1’s haveSoil like this:
if (CharacterRegistry.GetCharacter("NPC1").GetComponent<MyScript>().haveSoil) ...
However, given that you’re talking about dialogue, some kind of global repository of information may be better than a character registry. You could do something similar to the CharacterRegistry script above, except you’d be setting information names and values:
public static class DialogueInfo
{
private HashSet<string> flags; // Holds a list of flags (like bools) that are true.
public static void IsFlagSet(string name) { return flags.Contains(name); }
public static void SetFlag(string name) { flags.Add(name); }
public static void ClearFlag(string name) { flags.Remove(name); }
}
Let’s say NPC1 sets a flag “npc1 has soil”:
DialogueInfo.SetFlag("npc1 has soil");
Then NPC2 can check it like this:
if (DialogueInfo.IsFlagSet("npc1 has soil")) ...
Another way to share this data is to define a ScriptableObject asset for each data point. Example:
[CreateAssetMenu]
public class BoolVariable : ScriptableObject
{
public bool value;
}
This defines a new type of asset that you can create in your project.
Then NPC1 and NPC2 can both have variables that point to the asset:
public BoolVariable npc1HasSoil;
NPC1 can set it like this:
npc1HasSoil.value = true;
and NPC2 can check it:
if (npc1HasValue.value) ...
It does not matter what you access. It’s ALWAYS the same process in Unity.
Referencing variables, fields, methods (anything non-static) in other script instances:
https://discussions.unity.com/t/833085/2
Get super-cozy familiar with it because you do it a LOT.