Referencing a stopwatch time in another class

Greetings!

I’m currently working on a game that needs to keep time from the start of a scene and record time during specific actions. So what I need is code that starts keeping time when the scene starts and records that time when a separate class/script is called.

I’m using the Stopwatch function to keep time, and it works just fine when referenced in the same class:

public class GameController : MonoBehaviour {
Stopwatch stopWatch = new Stopwatch();
		stopWatch.Start();

using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true))
			{
				file.WriteLine( stopWatch.ElapsedMilliseconds);
			}
				}
}

However, what I really need to do is reference stopWatch in a different script. Here’s what I’ve tried:

public class RecordTime : MonoBehaviour {

GameController stopWatch = GetComponent<GameController>();
		using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true))
		{
			file.WriteLine( GameController.stopWatch.ElapsedMilliseconds);
		}

//trying to reference the GameController class to record time
}

Unfortunately, this doesn’t work. Does anyone have any ideas as to how to reference the stopwatch in another class?

GameController GameControllerRef = GetComponent<GameController>();
.....
file.WriteLine( GameControllerRef.stopWatch.ElapsedMilliseconds);

Hm, I tried pasting that code but it didn’t work.

I was getting this error :

Assets/Script/DestroyByContact.cs(30,74): error CS0122: `GameController.stopWatch’ is inaccessible due to its protection level

I made the stopWatch a public object and the script compiled but it still wouldn’t record my data.

public Stopwatch stopWatch = new Stopwatch();

Thoughts?

Can’t tell in what order any of this code is being called. In what functions are they sitting?

Does it write anything at all to file if you tell it to write this?

file.WriteLine( "Elapsed:" + GameController.stopWatch.ElapsedMilliseconds);

You might be trying to write the elapsed time before the stopwatch has started.

So the game controller script, which starts the stopwatch, starts running at the beginning of the scene, and continues running throughout. I have a streamwriter in that class that records time and otherwise works correctly.

The second script is only triggered when a specific action happens, in this case an object being destroyed. So it would always be triggered after the start of the gamecontroller script, thus after the stopwatch is started.

I just ran a version of the scene where the Gamecontroller records time and the Trigger records a word, and the file shows that these are run sequentially. Both items work independently, just not when I try to reference the stopwatch from another script.

spawned! 	3185
spawned! 	3701
spawned! 	4550
Destroyed! 	
spawned! 	4738
Destroyed! 	
spawned! 	5249

When I add the Gamecontroller stopwatch reference I get this error: Assets/Script/DestroyByContact.cs(30,73): error CS0120: An object reference is required to access non-static member `GameController.stopWatch’

The code that causes the error looks like this:

using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true))
		{
			GameController GameControllerRef = GetComponent<GameController>();
			file.WriteLine("Destroyed! \t" + GameController.stopWatch.ElapsedMilliseconds);
		}

Oh yeah, needs to be

file.WriteLine("Destroyed! \t" + GameControllerRef.stopWatch.ElapsedMilliseconds);

GameController is a class
GameControllerRef is the object reference.

I must have copied your code again.

Ah! I realized that mistake a few minutes ago and came to update the thread and saw that you had already mentioned it.

So, I put in the corrected line using GameControllerRef and I now get this error: NullReferenceException: Object reference not set to an instance of an object
DestroyByContact.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Script/DestroyByContact.cs:30)

What is also interesting, is that the trigger class no longer writes anything, not even the word “Destroyed!”

The streamwriter in Gamecontroller is still recording data correctly, while the other script is recording nothing.

Thanks for your continued help!

I see. The scripts are attached to different game objects.

You will need a reference to the object before you can get a reference to its script.

public GameObject GameControllerObject;[code]
Drag the Object with the GameController script attached, from the hierarchy into this field via the inspector.

then change to
[code]GameController GameControllerRef = GameControllerObject.GetComponent<GameController>();

Hm, I either don’t have my game set up correctly or I am misunderstanding your instructions.

The object with the Gamecontroller script, isn’t a prefab or anything and I can’t drag it into the GameControllerObject field. The only thing that object does is run the Gamecontroller script at the beginning (I’m not sure I’m explaining this right so I attached an image.)

The trigger script that I want to record data, is however attached to a prefab. I made the Gameobject variable like you said but can’t drag anything into that field.

Is there another way to reference the object? Maybe via its tag?

I didn’t think this would be so complicated! Thank you for taking the time to help.

Yes, you can find the GameObject by tag, or by name, they are quite slow operations so you don’t want to do them all the time, but they are fine for initialization.

I’d rename the object though, “GameObject” is a type.
Find by name:

private GameObject GameControllerObject;

void Start()
{
GameControllerObject = GameObject.Find("GameObject");
}

or

Find by Tag:

private GameObject GameControllerObject;

void Start()
{
GameControllerObject = GameObject.FindWithTag("GameController");
}

If you’re spawning things that need a reference to a persistent object, you should get the object that spawns them to hold a reference to that object, and pass the reference to the objects when it spawns them. That’s the most efficient way. That way it only needs to do a find operation once.

Is GameController spawning the asteroids? Because it can pass them a reference to the stopwatch when it spawns them.

GameObject Spawned = Instantiate(Asteroid, new Vector3(0, 0, 0), Quaternion.identity);
RecordTime RecScript = Spawned.GetComponent<RecordTime>();
RecScript.stopWatch = this.stopWatch;
public class RecordTime : MonoBehaviour {
public Stopwatch stopWatch;
...
file.WriteLine( stopWatch.ElapsedMilliseconds);

I’m still going through some of these early Unity tutorials and I realize these are some basic scripting mistakes I am making.

So I got the data collection to work by piggybacking off of a keeping score code, and like you said, passing the code to the object doing the spawning.

This is code that works:

public class GameController : MonoBehaviour

public void AddScore (int newScoreValue)
	{
		score += newScoreValue;
		UpdateScore ();
		using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true)) {
			file.WriteLine ("Destroyed! \t" + stopWatch.ElapsedMilliseconds);
		}
public class DestroyByContact : MonoBehaviour

private GameController gameController;
	
	void Start ()
	{
		GameObject gameControllerObject = GameObject.FindWithTag ("GameController");
		if (gameControllerObject != null)
		{
			gameController = gameControllerObject.GetComponent <GameController>();
		}
			}

//this is what calls the Addscore function in the GameController script which subsequently records the time
gameController.AddScore (scoreValue);

My question is if I instead set up my code like so, why doesn’t it work?

public class GameController : MonoBehaviour

public void recordTime()
	{
		
		using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true)) {
			file.WriteLine ("Destroyed! \t" + stopWatch.ElapsedMilliseconds);
		}

and

public class DestroyByContact : MonoBehaviour

private GameController gameController;
	
	void Start ()
	{
		GameObject gameControllerObject = GameObject.FindWithTag ("GameController");
		if (gameControllerObject != null)
		{
			gameController = gameControllerObject.GetComponent <GameController>();
		}
			}

//this no longer works
gameController.recordTime()

I realized my syntax was just wrong.

public void recordTime()

    {

               using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Test\WriteLines2.txt", true)) {

            file.WriteLine ("Destroyed! \t" + stopWatch.ElapsedMilliseconds);
}

        }

Everything works now!
Thanks!