- Home /
Making a variable work in two separate objects?
To set the scene:
I have a small game where you shoot coconuts at targets, you hit them, you fall down, you get something. Now, my question is, I have two scripts set up:
This one is used to knock the targets down when hit with the coconut, and then knocks the variable 'washit' up by one.
using UnityEngine;
using System.Collections;
public class targetCollisions : MonoBehaviour {
bool beenhit = false;
Animation targetroot;
public AudioClip hitsound;
public AudioClip resetsound;
public float resetTime = 3.0f;
public int washit;
// Use this for initialization
void Start () {
targetroot = transform.parent.transform.parent.GetComponent<Animation> ();
washit = 0;
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter (Collision col) {
if (beenhit == false && col.gameObject.name == "coconut") {
StartCoroutine("targetHit");
}
}
IEnumerator targetHit () {
AudioSource hitAudio = GetComponent<AudioSource> ();
hitAudio.clip = hitsound;
hitAudio.Play ();
targetroot.GetComponent <Animation> ().Play ("down");
beenhit = true;
yield return new WaitForSeconds(3);
targetroot.GetComponent <Animation> ().Play ("up");
AudioSource resetAudio = GetComponent<AudioSource> ();
resetAudio.clip = resetsound;
resetAudio.Play ();
beenhit = false;
washit ++;
}
}
Now, this next script also uses 'washit', and when washit equals three, it's supposed to translate the object the script is attached to.
using UnityEngine;
using System.Collections;
public class victorycell : MonoBehaviour {
public int washit;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (washit >= 3) {
transform.position = new Vector3(20f, 10f, 15f);
}
}
}
The problem is, of course, that washit isn't increasing in value despite me hitting the target. What have I done wrong?
Answer by pekalicious · Nov 11, 2015 at 04:50 AM
Those are two different components with their own washit data. Not only that, but the data is also unique on a per-instance basis. In other words, if you have 5 game objects with targetCollisions, they each have their own value for washit. So doing the check in the first component would have the same issue.
What you really want is a variable that is stored somewhere that both components have access to read and write from.
The simplest solution (and probably not a good long-term solution) would be to make one of the two a static variable. Later on you can clean up the code using a singleton/manager/whathaveyou
I'm assuming that you expect to have multiple targetCollisions but only one victorycell that does the game over condition checking. So, remove the washit from targetCollisions and then add the word "static" in victorycell. Then move "washit = 0" to victorycell's Start method. Finally, instead of "washit ++;" you need to do "victorycell.washit ++;".
In general know that static fields store data across instances and the lifecycle of your application. You should generally avoid it because they stay in memory and forces your code to get highly tangled (which is a hell to change).
(I would have made pasted the changed code here, but I'm on mobile. Hopefully my instructions are clear enough)
plus 1 for simplest solution.
I forgot to mention this, actually.
I've had a situation where I couldn't use a static variable but I can't remember the details. I think I was trying to access a variable on a script that was on a prefab that was only being instantiated once. $$anonymous$$aybe Unity considered there to be two instances of the script or maybe it had something to do with execution order. I have no idea.
Thank you very much for the information! I'm still learning a lot about C# so I'm not too familiar with the way it works.
Answer by ijidau · Nov 11, 2015 at 01:22 PM
I think you have misunderstood what public means. Public makes a variable accessible to other scripts and the unity editor, if you reference it through it's parent gameObject and then script component, but it doesn't make it a global variable (like some other scripting/programming paradigms).
To make the variable accessible you need a way to talk from one script to the other, see: https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/communicating-between-components-gameobjects
Answer by bpierpont89 · Nov 11, 2015 at 01:22 PM
You define washit as an int, but never set washit as a specific number. Therefore, you can't add points to washit, as the system does not know what to add the points to. You would want to simply define washit with the inclusion of "=0." That should be it.
public int washit = 0;
Answer by Fragmental · Nov 11, 2015 at 04:56 AM
It's best practice to declare your classes with capitals like "TargetCollisions" and "VictoryCell". And then declare your variables with camel casing like "washIt" or "targetRoot". It's helpful, for reasons, and makes your code easier to read.
victorycell.washit and targetCollisions.washit are two different variables that have no relation except for the name. There are a couple ways to gain access to the variable on one script with another. Honestly, I'm not sure what the best way is.
One example: in the targetCollisions class add the declaration,
public static targetCollisions instance = null;
Then add to void Start()
instance = this;
Then you should be able to access targetCollisions.washit with
targetCollisions.instance.washit
I'm not sure, but this might be called a Singleton Pattern. If you have multiple instances of the targetCollisions script, or if the GameObject that holds one of those scripts is instantiated at runtime, this may not work very well.
If both of your scripts are on the same GameObject, then you might be able to get the script by using something like
targetCollisions instance = GetComponent<targetCollisions>();
and then you can access the variable with
instance.washit
(note, this is one occassion where capitalizing the class TargetCollisions allows you to us targetCollisions as a variable here for better readability)
If your scripts are on different objects, you can still use the same method but you would first have to access the other GameObject and then use GetComponent.
http://docs.unity3d.com/410/Documentation/ScriptReference/index.Accessing_Other_Game_Objects.html will tell you more about how to go about doing that, though I've found that script reference to be a little confusing at times.
In this example, there is an object named "SomeGuy"
GameObject go = GameObject.Find("SomeGuy");
go.GetComponent<targetCollisions>().washit = 3;
There are probably quite a few questions like this on Unity Answers.
Your answer
Follow this Question
Related Questions
Cannot assign Public GameObject variable in Inspector... 2 Answers
public script variable in inspector 2 Answers
How to make variable accessible by other scripts but not visible in editor? 1 Answer
Why can't I to declare public the variable "Clave"? 1 Answer
Can I make variables visible to other scripts without making them visible in the Inspector? 1 Answer