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?

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

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)

@replay55 ,

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;

@replay55

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.

Unity Script Reference – Overview: Accessing Other Game Objects 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.