Trying to record level time data and print to screen at the end Unity 2D - unity3d

So I have a 2D platformer parkour game which holds a timer when player starts level. I have 5 levels and at the end of each level, I want to keep the last time value and display them at the end of the game.
So far, I tried to hold the last time value when player triggers the End portal and store them in an array in the code below. Here are the scripts:
Time Data Manager Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
void Start(){
}
void Update(){
Debug.Log(timeDataArr[SceneManager.GetActiveScene().buildIndex-1]);
}
public void AddTimeData(string timeData, int levelBuildIndex){
timeDataArr[levelBuildIndex-1] = timeData.ToString();
}
}
End Portal Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class EndPortal : MonoBehaviour
{
public AudioSource aSrc;
private int sceneNumber;
public GameObject bgAudio;
public Text scoreText;
string textData;
public timeDataManager tDManager;
void Start(){
sceneNumber = SceneManager.GetActiveScene().buildIndex;
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
}
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
aSrc.Play();
Destroy(bgAudio);
textData = scoreText.text;
Debug.Log(textData);
Debug.Log(sceneNumber);
tDManager.AddTimeData(textData,sceneNumber);
SceneManager.LoadScene(sceneBuildIndex:sceneNumber+1);
}
}
}
As I said before, I tried to keep all timer values at the end of each level and store them in an array in my timeDataManager script. But it's not working.
Any ideas on how to fix? Or do you have any other ideas? Thanks a lot for your time.

Issylin's answer is a better solution for your needs but i want to mention couple of things about your code.
One thing about your timeDataArr. If you don't touch it in inspector, you need to initialize it first. So let's say, if you want to hold 5 levels of time data, you need to do something like;
public string[] timeDataArr = new string[5];
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_TO_HoldTimeData = 5;
void Start()
{
timeDataArr = new string[sceneAmount_TO_HoldTimeData];
}
}
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_NOT_ToHoldTimeData = 1;
void Start()
{
timeDataArr = new string[SceneManager.sceneCountInBuildSettings - sceneAmount_NOT_ToHoldTimeData];
}
}
Another thing is you need to be careful about levelBuildIndex-1. If you call that in first scene,
SceneManager.GetActiveScene().buildIndex
will be 0 and levelBuildIndex-1 will be -1 or in Debug part it will be timeDataArr[-1] but array indexes must start with 0. So it will throw an error.
One more thing, this is not an error or problem. Instead of this part
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
you can do
tDManager = FindObjectOfType<timeDataManager>();

There are several way to achieve what you're trying to do.
The easier would be to use a static class for such a simple data like the one you're carrying through your game.
using System.Collections.Generic;
public class Time_Data
{
/// TODO
/// Add the members
/// e.g. your time format as string or whatever,
/// the scene index, etc
}
public static class Time_Manager
{
private static List<Time_Data> _times;
public static void Add_Time(in Time_Data new_time)
{
_times.Add(new_time);
}
public static List<Time_Data> Get_Times()
{
return _times;
}
public static void Clear_Data()
{
_times.Clear();
}
}
Use it like any other static methods within your OnTriggerEnter2D call.
Time_Manager.Add( /* your new data here */ );
The other way, if you intend to stay with a game object within your scenes, would be to use the DontDestroyOnLoad method from Unity so your game object which has your script timeDataManager would remain.
Note that in your code, using string[] might be unsafe. For your use of it, consider using a List<string>.

Related

error CS0117: 'ScoreSystem' does not contain a definition for 'HighscoreKey'

i was just writing my script and this appeared while trying to test the game. heres my script
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;
public class MainMenu : MonoBehaviour
{
[SerializeField] private TMP_Text HighscoreText;
private void Start()
{
int Highscore = PlayerPrefs.GetInt(ScoreSystem.HighscoreKey, 0);
HighscoreText.text = $"High Score: {Highscore}";
}
public void Play()
{
SceneManager.LoadScene(1);
}
}
please help me, tq
The error is very clear: it says that inside the Score System class, it did not find the HighscoreKey variable.
To make this work, if you created the ScoreSystem class yourself, you should add a static string variable called HighscoreKey.
Like this:
public static string HighscoreKey = “…”;
Good Work!

Not able to change text from another script

How it should work - when i click on the UI button, the score increases and is displayed using text.
How it's working - An error that says 'NullReferenceException: Object reference not set to an instance of an object'
There are two scripts on two different game objects.
Player Script
using UnityEngine;
public class Player : MonoBehaviour
{
ScoreManager scoreManager;
private void Start()
{
scoreManager = new ScoreManager();
}
public void UpdateScore()
{
scoreManager.IncrementScore();
}
}
ScoreManager Script
using UnityEngine;
using TMPro;
public class ScoreManager : MonoBehaviour
{
private int score = 0;
public TextMeshProUGUI scoreText;
public void IncrementScore()
{
score++;
scoreText.text = score.ToString();
}
}
When I use Debug.Log(score.ToString()), it displays the score in the console. But when I use textmeshprougui, it gives an error.
Also, I've dragged the text into the inspector, so that cannot be a problem for the null referrance. I've checked it multiple times.
Why am I not able to update the text from another script?
Null reference exception is in your Player.cs script and caused because of the code in your Start() method
ScoreManager scoreManager;
private void Start()
{
scoreManager = new ScoreManager();
}
Remove the code in your Start() method. Because there is a field ScoreManager scoreManager;, you drag the gameobject which has the script ScoreManager.cs into its slot in the Player.cs script. Now you have the reference of the ScoreManager.cs script in your Player.cs script.
Now, you are resetting its reference in your Start() method. This caused the null reference exception.

Photon, RPC not working, how can I fix my code?

I'm trying to synchronize text in a unit between players, but I'm getting an error.
I just need to sync the text
[1]: https://i.stack.imgur.com/0l98U.png
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using UnityEngine.UIElements;
public class Sync : MonoBehaviourPunCallbacks
{
private PhotonView view;
public Text textGame;
public Text copied;
void Start()
{
view = GetComponent<PhotonView>();
}
public void sync()
{
if(view.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
[PunRPC]
public void ViewAll(string tG)
{
tG = copied.text;
Debug.Log(tG);
}
}```
пппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп
The error is telling you that the "view" variable has not been assigned and is therefore null.
To assign it you can make that field public, and in the inspector you
assign the photonView you want, I guess that of the player.
Alternatively you can assign "view" not from the inspector but in a
Start() or Awake() method. If the photonView you want to associate is
on the same GameObject as the script, you can write like this:
void Awake()
{
view = GetComponent();
}
However, the easiest answer is to replace "view" with "photonView".
It will have the same result as the solutions described above, but it will be very simple.
enter code here
public void sync()
{
if(photonView.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
I have not directly given you the simple slogan to make you fully understand the problem and to help you solve it.

NullReferenceException: OnDestroy() function error

In my game I have coins, in my coin script I have an OnDestroy() function but I get this error "NullReferenceException: Object reference not set to an instance of an object
coinscript.OnDestroy () (at Assets/Scrips/coinscript.cs:9)"
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class coinscript : MonoBehaviour
{ public gamemanager GameManager;
void OnDestroy()
{
GameManager.plusScore(10);// FindObjectOfType<gamemanager>().pluseScore(10); gets the same error
}
}
fixed it thanks to help from KiynL
using System.Collections.Generic;
using UnityEngine;
public class coinscript : MonoBehaviour
{ public gamemanager GameManager;
bool destroyed = false;
void OnDestroy()
{
if (destroyed = false)
{
GameManager.plusScore(10);
destroyed = true;
}
}
}
This is because the object may be destroyed multiple times in one frame. Fix it.
void OnDestroy()
{
if (gameObject) GameManager.plusScore(10);
}
You need to go into the properties of whatever object you attached that script to, and assign Game Manager an object that has a gamemanager script attached to it.
As ted said its probably because you haven't set GameManager from inspector. you need to drag a gameObject that has gamemanager component on it.
but I recommand making plusScore function static and calling it without an object, if you make it statis you also have to make varible that stores score static as well, some thing like this:
public class gamemanager : MonoBehaviour
{
static int Score = 0;
public static void plusScore(int score)
{
Score += score;
}
}
then calling it like this:
gamemanager.plusScore(10);

Accessing struct list on Start() gives NullReferenceError

What in the name of god am I doing wrong here? Every time I run the game I get this: "NullReferenceException: Object reference not set to an instance of an object". I know what that means I just don't get why it is saying that?
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class Inventory : MonoBehaviour {
public static Inventory instance;
public List<InventoryItems> INVENTORY_ITEMS = new List<InventoryItems>();
void Awake(){
instance = this;
}
void Start(){
Debug.Log(instance.INVENTORY_ITEMS); // ERROR
Debug.Log(INVENTORY_ITEMS); // ERROR
}
}
[Serializable]
public struct InventoryItems
{
public string name;
}
This is how you should write this code:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class Inventory : MonoBehaviour {
public static Inventory instance;
public List<InventoryItems> INVENTORY_ITEMS;//do not initialize here
void Awake(){
instance = this;
INVENTORY_ITEMS = new List<InventoryItems>();//init here instead
}
void Start(){
Debug.Log(instance.INVENTORY_ITEMS); //no ERROR
Debug.Log(INVENTORY_ITEMS); //no ERROR
}
}
[Serializable]
public struct InventoryItems
{
public string name;
}
Added note:
The reason for this error is that the value of a public serializable member in monobehaviour is being read from the editor (inspector) overwriting any value being assigned to it prior to Awake.
I suggest either change the list accessor to internal, or make it a property, or keep it public but let inspector handle the initialization and adding the initial elements.
Added another note:
According to Programmer and Uri Popov, your original code most certainly will work on unity 5.4 and later.