How to save in Unity the time obtained in the game timer? - c#

I have created a timer for my game and I need to save in a variable or a function, the time elapsed until the moment of finishing, and then show it on the screen as "Record".
I want to display on screen the shortest time achieved, when a shorter time is achieved, replace, (overwrite) the time that was until that moment.
So far I have managed to show the clock time and a text to show "Record" that only shows "00:00" since I don't know how to put my code together.
The stopwatch works and restarts every time a new game starts, but I don't know how to save the time achieved at the end of the game
How do I get the shortest time achieved to display?
My experience is sparse in C#, I have started with a simple template to experiment and make changes.
I have built the code of the clock, following an example.
On the other hand, looking for information, I see that with the PlayerPrefs method you can save and delete data.
I found another example and studied the logic to use that method on my watch, but I don't quite understand the logic and I can't get it to work.
How can I get to save the time to display it as text on the screen?
How to make it always rewrite with the shortest time obtained at the end of the game?
I show the code of my Reloj.cs which works and is displayed on the screen.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Reloj : MonoBehaviour
{
[Tooltip("Tiempo inicial")]
public int tiempoInicial;
[Tooltip("Escala de tiempo del relog")]
[Range(-10.0f, 10.0f)]
public float escalaDeTiempo = 1;
private Text myText;
private float tiempoDelFrameConTimeScale = 0f;
private float tiempoAMostrarEnSegundos = 0f;
private float escalaDeTiempoAlPausar, escalaDeTiempoInicial;
private bool estaPausado = false;
void Start()
{
// set the timeline
escalaDeTiempoInicial = escalaDeTiempo;
myText = GetComponent<Text>();
//we start the variable
tiempoAMostrarEnSegundos = tiempoInicial;
ActualizarRelog(tiempoInicial);
}
// Update is called once per frame
void Update()
{
if (!estaPausado)
{
// the following represents the time of each frame considered the time scale
tiempoDelFrameConTimeScale = Time.deltaTime * escalaDeTiempo;
// the following variable accumulates the elapsed time to show it in the Relog
tiempoAMostrarEnSegundos += tiempoDelFrameConTimeScale;
ActualizarRelog(tiempoAMostrarEnSegundos);
}
}
public void ActualizarRelog(float tiempoEnSegundos)
{
int minutos = 0;
int segundos = 0;
string textoDelReloj;
// ensure that the time is not negative
if (tiempoEnSegundos <= 0) tiempoEnSegundos = 0;
// calculate seconds and minutes
minutos = (int)tiempoEnSegundos / 60;
tiempoEnSegundos = (int)tiempoEnSegundos % 60;
// create the string of digital characters that form the relog
textoDelReloj = minutos.ToString("00") + ':' + tiempoEnSegundos.ToString("00");
// update UI text element with character string
myText.text = textoDelReloj;
}
public void Pausar()
{
if (!estaPausado)
{
estaPausado = true;
escalaDeTiempoAlPausar = escalaDeTiempo;
escalaDeTiempo = 0;
}
}
}
On the other hand, I have been doing tests to try to implement the following example in my Clock, but I can't. Before asking the question here, I have looked for a solution and I have tried to learn how to do it, I have seen videos, examples, and I do not get it.
The following example, I create it by watching a video, and I get it to save the data on the screen, and delete it from a button, but I don't know how to implement it in my Clock. I imagine it would be very simple, but I can't understand the logic.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LogicaPuntuaje : MonoBehaviour
{
public Text textoPuntaje;
public int numPuntaje;
// The start is called before the first table update
public Text textoRecord;
void Start()
{
numPuntaje = 0;
textoRecord.text = PlayerPrefs.GetInt("PuntajeRecord", 0).ToString();
}
// The update is called once per frame
void Update()
{
}
// button to create points by doing that I don't need
public void PuntajeAlAzaro()
{
numPuntaje = Random.Range(0, 11);
textoPuntaje.text = numPuntaje.ToString();
if (numPuntaje > PlayerPrefs.GetInt("PuntajeRecord", 0))
{
PlayerPrefs.SetInt("PuntajeRecord", numPuntaje);
textoRecord.text = numPuntaje.ToString();
}
}
// function to delete the record data
public void BorrarDatos()
{
PlayerPrefs.DeleteKey("PuntajeRecord");
textoRecord.text = "00:00";
}
}

// here is the solution:
float currentTime; // your current timer (without logic)
float highscore = 99999; // set it to a really high value by default
void start()
{
highscore = PlayerPrefs.GetFloat("best"); // get your previous highscore
}
//on level completed:
{
if(currentTime <= highscore //your best time
{
highscore = currentTime;
PlayerPrefs.SetFloat("best", highscore); // save your score
}
}

Related

How I can make "Time" to be update constantly

I am beginner game dev in unity and i start new little project "alone", and in my game i have a little problem.
My problem is that the time, i.e. the clock in the game is not synchronized and does not synchronize and I have some suspicions.
I know maybe I'm doing another wrong step, maybe I put a wrong equation in the whole function and nothing works anymore, but to tell you more briefly, I want to make a game in which the game interface is a desktop and the clock on I coded it below, it doesn't work to be updated with time, I waited and tried many solutions that I applied and they didn't work, so I'll leave the code below
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class DateTime : MonoBehaviour
{
public Text timeLockScreenText;
public Text dateLockScreenText;
public Text timeTaskBarText;
string time = System.DateTime.UtcNow.ToLocalTime().ToString("HH:mm");
string date = System.DateTime.UtcNow.ToLocalTime().ToString("MM-dd-yyyy");
// Update is called once per frame
void Update()
{
InvokeRepeating("DateTimeV",0f,1f);
}
public void DateTimeV()
{
timeLockScreenText.text = time;
dateLockScreenText.text = date;
timeTaskBarText.text = timeLockScreenText.text;
}
}
Now I have some theories:
one is that in the game, just like in real life, it's like with any personal computer user when we open it there is a lockscreen with a clock and we press enter to enter all the time to access the internet and other files on the desktop, so I have the theory that the lockscreen being a GameObject which is like visibility opposite to the desktop, i.e. if the lockscreen is active the desktop is not visible and vice versa, the clock does not update because let's say if we are on the desktop the lockscreen is disabled and that's why the script doesn't really work and you have to to make two separate ones, one for the lockscreen and one for the desktop, actually for the clock on the desktop
or I don't know how to code well
I tried to put in Update() function, in InvokeRepeting, StartCourutine with IEnumerator function, and i dont have the solutions
I don't know anything about Unity, but it seems that you're never updating the values of time and date after they're initially assigned. Perhaps something like this would do the trick, where you just assign the correct values in the method:
public void DateTimeV()
{
DateTime utcNow = System.DateTime.UtcNow.ToLocalTime();
timeLockScreenText.text = utcNow.ToString("HH:mm");
dateLockScreenText.text = utcNow.ToString("MM-dd-yyyy");
timeTaskBarText.text = timeLockScreenText.text;
}
Use fixed update, and the code from Rufus L:
void FixedUpdate() => DateTimeV();
public void DateTimeV()
{
DateTime utcNow = System.DateTime.UtcNow.ToLocalTime();
timeLockScreenText.text = utcNow.ToString("HH:mm");
dateLockScreenText.text = utcNow.ToString("MM-dd-yyyy");
timeTaskBarText.text = timeLockScreenText.text;
}
What Rufus L said + you would use InvokeRepeating only once e.g. in
private void Start()
{
InvokeRepeating(nameof(DateTimeV), 0f, 1f);
}
or use a simple counter
private float timer;
private void Update ()
{
timer += Time.deltaTime;
if(timer > 1f)
{
timer -= 1f;
DateTimeV();
}
}
or a coroutine
private IEnumerator Start()
{
while(true)
{
DateTimeV();
yield return new WaitForSeconds(1f);
}
}

How to save and add a value obtained in the game?

I'm making a store for my game and I'm making a system where the score I get in the game is saved and every time you play it adds and saves too, but this last part isn't working I don't know why, I'm taking a variable from another script called score it receives the value I got and had to add it to the previous value but it doesn't happen.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CoinsManager : MonoBehaviour
{
public GameObject YellowSquare;
private int totalScore;
void Start()
{
YellowSquare.GetComponent<Text>().text = GameController.score.ToString();
totalScore = PlayerPrefs.GetInt("lastScore", GameController.score);
}
void Update()
{
SaveMoney();
}
void SaveMoney()
{
totalScore = GameController.score++;
PlayerPrefs.SetInt("lastScore", totalScore);
}
}
Why is the GameController.score completely detached from this? I would expect you rather do
// actually load the previous score into GameController.score
GameController.score = PlayerPrefs.GetInt("lastScore", GameController.score);
// then AFTER this update the text
YellowSquare.GetComponent<Text>().text = GameController.score.ToString();
.. and then in Update rather do
// Btw do you really want your score to be a counter of how many FRAMES you have played? o.O
GameController.score++;
PlayerPrefs.SetInt("lastScore", GameController.score);
// also update the text after changing the value
YellowSquare.GetComponent<Text>().text = GameController.score.ToString();

c#/Unity: Infinite Loop Issue... Am I going crazy?

So, c# noob here, with a bit of an issue:
I'm trying to script a boss battle for my Unity game, and I'm making it's A.I.
Every 10 seconds, I want the boss to check a random number. If it makes it, it will perform a teleport animation, and teleport. I haven't coded the teleportation itself, just trying to get the animation to trigger. I want this to be keep going throughout the boss fight, until the boss is defeated.
Unfortunately, it's an infinite loop that crashes my Unity every time I run it. I know having it in Update() is a dumb idea, but I've tried a lot of stuff and got nothing. I'm losing my mind here! Am I missing something obvious?!
Anyway, here's the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SmellseerAI : MonoBehaviour
{
public Animator animator;
public SmellseerHealth smellseerhealth;
public GameObject tele1;
public GameObject tele2;
public GameObject tele3;
public DateTime TimeOfLastTeleport;
private bool teleporting = false;
void Start()
{
TimeOfLastTeleport = System.DateTime.Now;
}
void Update()
{
Debug.Log("Starting teleportcheck!");
int TeleportMin = 1;
int TeleportMax = 10;
int RandomTeleport = UnityEngine.Random.Range(TeleportMin, TeleportMax);
var diffInSeconds = (System.DateTime.Now - TimeOfLastTeleport).TotalSeconds;
Debug.Log("diffInSeconds is " + diffInSeconds);
if ((RandomTeleport > 5) && (diffInSeconds > 3))
{
Debug.Log("Teleporting!");
teleporting = true;
animator.SetBool("teleporting", true);
while (animator.GetCurrentAnimatorStateInfo(0).normalizedTime <= 1)
{ //If normalizedTime is 0 to 1 means animation is playing, if greater than 1 means finished
Debug.Log("anim playing");
}
animator.SetBool("teleporting", false);
TimeOfLastTeleport = System.DateTime.Now;
}
else
{
Debug.Log("Failed to teleport");
}
Debug.Log("Gaming!");
}
}
You're running a while loop inside Update():
while (animator.GetCurrentAnimatorStateInfo(0).normalizedTime <= 1)
but the animator's time isn't changing because it updates each frame, and you're causing the main thread to hang with your while loop. You won't release Update() (and thus won't allow the next frame to be drawn) until your while loop breaks, but your while loop's condition requires more frames. So you just wait forever.
Try moving your teleport values to the class, initialize them in Start(), then re-set them again after you've done all your checks. Then you can return each frame your condition isn't met. Consider the following:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SmellseerAI : MonoBehaviour
{
public Animator animator;
public SmellseerHealth smellseerhealth;
public GameObject tele1;
public GameObject tele2;
public GameObject tele3;
public DateTime TimeOfLastTeleport;
private bool teleporting = false;
// NEW
int TeleportMin = 1;
int TeleportMax = 10;
int RandomTeleport;
void Start()
{
TimeOfLastTeleport = System.DateTime.Now;
//NEW
RandomTeleport = UnityEngine.Random.Range(TeleportMin, TeleportMax);
}
void Update()
{
var diffInSeconds = (System.DateTime.Now - TimeOfLastTeleport).TotalSeconds;
Debug.Log("diffInSeconds is " + diffInSeconds);
if ((RandomTeleport > 5) && (diffInSeconds > 3))
{
Debug.Log("Teleporting!");
teleporting = true;
animator.SetBool("teleporting", true);
// NEW
if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime <= 1)
{ //If normalizedTime is 0 to 1 means animation is playing, if greater than 1 means finished
Debug.Log("anim playing");
// NEW
return;
}
animator.SetBool("teleporting", false);
TimeOfLastTeleport = System.DateTime.Now;
}
else
{
Debug.Log("Failed to teleport");
}
Debug.Log("Gaming!");
// NEW
RandomTeleport = UnityEngine.Random.Range(TeleportMin, TeleportMax);
}
}
When you start the animation your code enters the while loop and never finishes, unity waits until all scripts are done before rendering the next frame, meaning the animation never finishes
Removing the while loop and just making it an if statement to check the animation state should work.

Trying to create an interruptible dialogue system, with subtitles, using coroutines

I am currently working on a game where to characters are having a conversation. There are a few dialogue options, but the conversation trees are quite simple. A key aspect is that the player is able to interrupt the other party mid-sentence and change the course of the conversation.
To preface, I have learned all I know from youtube and I've been getting by on increasingly complex if-statements, so I'm trying something new here.
So I did my first attempt using what I know: Invoke and if-statements.
public class SubtitleSystem : MonoBehaviour
{
public float subtitleTimeBuffer;
public string[] dialogue;
public string[] specialDialogue;
public float[] subTiming;
public float[] specialSubTiming;
public AudioClip[] diaClips;
public Text sub;
AudioSource player;
int subNum;
int specialSubNum;
// Start is called before the first frame update
void Start()
{
player = gameObject.GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
if (sub.enabled == false) {
SubSystem();
}
}
}
void SubSystem()
{
if(subNum < dialogue.Length)
{
if (subNum != 1)
{
player.clip = diaClips[subNum];
player.Play();
sub.text = dialogue[subNum];
sub.enabled = true;
Invoke("DisableText", subTiming[subNum] + subtitleTimeBuffer);
subNum++;
}
else if (subNum == 1)
{
player.clip = diaClips[subNum];
player.Play();
sub.text = specialDialogue[specialSubNum];
sub.enabled = true;
Invoke("DisableText", subTiming[subNum] + subtitleTimeBuffer);
Invoke("SpecialSub", specialSubTiming[specialSubNum]);
}
} else
{
Debug.Log("No more dialogue");
}
}
void DisableText()
{
sub.enabled = false;
}
void SpecialSub()
{
sub.text = dialogue[subNum];
subNum++;
}
This was functional, though clunky and very work intensive for the person that has to find the individual timing for each line of dialogue and manually break up a subtitle line if it was too long.
Another big problem was that it was impossible to fully interrupt dialogue, because Invoke was called and would run regardless of what I pressed. Maybe I could add some kind of bool condition to prevent that, but the project I'm working on will have a few hundred lines of dialogue, so I need to come up with something where I don't have to type in every line in the inspector and find the manual timing.
This is where it becomes murky for me as I am unfamiliar with a lot of these methods.
An obvious solution to the Invoke problem would be to use Coroutines. These can be interrupted and I could even have a check for input inside a loop to let a player interrupt.
IEnumerator SubtitleRoutine()
{
while (DialogueIsPlaying)
{
//Display Subtitles
if(Input.GetButton("Interrupt button"){
//interrupt
}
yield return null;
}
//Wait for next piece of dialogue
}
Something like that is what I'm imagining.
The next problem is tying dialogue to some kind of system so I can pull the correct piece of audio and display the correct subtitles. In my first attempt this was simple enough because the four pieces of test audio I created were short sentences, but if a character speaks for longer it would be tedious to break up the dialogue manually.
Alternatively I thought about breaking the audio files up into "subtitle-length" so every audio file had a subtitle string directly associated with it, but this seems inefficient and troublesome if dialogue needs to change down the line.
So I thought if I could somehow create a class, that contained all the information needed, then my coroutine could pull in the correct dialogue using it's id (perhaps an integer) and plug in all the information from the object into my coroutine.
So something like this:
public class dialogue
{
//Int ID number
//Audiofile
//Who is speaking
//Length
//Subtitle String 1
//Subtitle String 2
//Subtitle String 3
// etc
}
IEnumerator SubtitleRoutine(dialogue)
{
while (DialogueIsPlaying)
{
//Display Subtitles - divide number of subtitle string by Length and display each for result.
if (Input.GetButton("Interrupt button"){
//interrupt audio and subtitles - stop the coroutine
//set correct dialogue Int ID for next correct piece of dialogue and start coroutine with new dialogue playing.
}
yield return null;
}
//Wait for next piece of dialogue
}
Though this is all outside of what I know, from what I've been able to read and understand, this seems like it might work.
So my question is:
Is this approach going to work?
If so, where should I look for ressources and help to teach me how?
If not, what methods should I look at instead?
Thank you so much for your help!
So what I understand is that you want to make an interruptable dialog system. You chose the coroutine approach which is a great choice, but you're not using it to its full potential. When you use StartCoroutine(IEnumerator _enumerator); you'll get a coroutine class back. If you store it, you can later use StopCoroutine(Coroutine _routine); to stop it. So you won't have to use a while loop or if statements to check interrupting.
Hope this will help you. If it doesn't I'll send some code.
After receiving some help from a coding mentor I found a system that works using a custom class as a datatype and coroutines to display subtitles with correct timing.
The names of the variables are in Danish but the code works in Unity without issues.
using System.Collections.Generic;
using UnityEngine;
public class Undertekster
{
public int id;
public AudioClip audioFile;
public float length;
public string[] subtitles;
public bool isMonk;
public SubSystem subsys;
public Undertekster(int id, int dialogClipNummer, float length, string[] subtitles, bool isMonk, SubSystem subsys)
{
this.subsys = subsys;
this.id = id;
this.audioFile = subsys.dialogClip[dialogClipNummer];
this.length = length;
this.subtitles = subtitles;
this.isMonk = isMonk;
}
}
Notice that use another script when constructing the class to make use of Monobehavior. That way I can assign the correct audiofile to each line of dialogue using an array created in the inspector. The proper way would probably be to look for the file somehow, but that's beyond me.
Next is the subtitle system. For demonstration you hit space in-game to start dialogue and hit F to interrupt. The "subtitles" are Debug.log in the console, but you can easily tie them to a Text object in the UI.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SubSystem : MonoBehaviour
{
[Header("DialogClip")]
public AudioClip[] dialogClip;
[Header("Indstillinger")]
public float subtitleBuffer;
public AudioSource munk;
public AudioSource salamander;
List<Undertekster> alleUndertekster = new List<Undertekster>();
int currentDialogueNumber;
Undertekster currentDia;
float timeDivided;
void Start()
{
currentDialogueNumber = 1;
LoadDialog();
}
public void LoadDialog()
{
alleUndertekster.Add(new Undertekster(1, 0, dialogClip[0].length, new string[] { "Kan du huske mig?" }, true, this));
alleUndertekster.Add(new Undertekster(2, 1, dialogClip[1].length, new string[] { "Øh...", "Lidt..." }, false, this));
alleUndertekster.Add(new Undertekster(3, 2, dialogClip[2].length, new string[] { "Jeg er din nabo din idiot!" }, true, this));
alleUndertekster.Add(new Undertekster(4, 3, dialogClip[3].length, new string[] { "Shit!" }, false, this));
}
IEnumerator PlayNextDialogue()
{
int count = 0;
while (munk.isPlaying || salamander.isPlaying)
{
ShowSubtitle(count);
yield return new WaitForSeconds(timeDivided + subtitleBuffer);
count++;
yield return null;
}
//yield return new WaitForSeconds(subtitleBuffer);
currentDialogueNumber++;
Debug.Log("Coroutine is stopped and the current dialogue num is " + currentDialogueNumber);
StopCoroutine(PlayNextDialogue());
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
InterruptDialogue();
}
if (Input.GetKeyDown(KeyCode.Space))
{
StartDialogue();
}
}
public void StartDialogue()
{
currentDia = alleUndertekster.Find(x => x.id == currentDialogueNumber);
timeDivided = currentDia.length / currentDia.subtitles.Length;
if (currentDia.isMonk)
{
munk.clip = currentDia.audioFile;
munk.Play();
} else if (!currentDia.isMonk)
{
salamander.clip = currentDia.audioFile;
salamander.Play();
}
StartCoroutine(PlayNextDialogue());
}
public void InterruptDialogue() {
StopCoroutine(PlayNextDialogue());
munk.Stop();
salamander.Stop();
currentDialogueNumber++;
StartDialogue();
}
public void ShowSubtitle(int i)
{
if(i <= currentDia.subtitles.Length - 1)
{
Debug.Log(currentDia.subtitles[i]);
} else
{
return;
}
}
}
I chose to put all the dialogue classes into a list so it was easily searchable for the id-numbers. It might have been better to use a Dictionary, but this worked for me and that was good it enough for this project.
With this system, my manuscript writer can put in every line of dialogue with its associated audioclip in the LoadDialog() function and determine who is speaking and in how many pieces the subtitles should be broken into to fit on the screen. They are then displayed one after the other while the audio is playing.
This probably isn't the best solution in the world, but I hope it works for whoever might need it - plus I learned a ton.

Unity PlayerPrefs is not updating my 'high score'

I'm making a 2D game where you're in the middle of the screen and you move round an endless green (screen) world and white cubes spawn randomly around you, and I have finished the game mechanics and a main menu and game over screens. The one thing I'm trying to add now is a high score. I did a bit of research and found PlayerPrefs is probably the way to do it. I have a seperate scene for my main menu and my gameplay level (which includes the game over screen). I have no error messages. I have created a HSSetter (High Score Setter) script on the high score text in the main menu screen:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HSSetter : MonoBehaviour
{
public Text highScoreText;
// Start is called before the first frame update
void Start()
{
highScoreText.text = "High Score: " + PlayerPrefs.GetInt("HighScore").ToString();
}
// Update is called once per frame
void Update()
{
highScoreText.text = "High Score: " + PlayerPrefs.GetInt("HighScore").ToString();
}
}
and in my score script which is in my actual game level, here's the bit where I try to create the high score:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class score : MonoBehaviour
{
public int scoreCount = 0;
public int highScoreIFA;
void Start()
{
highScoreIFA = PlayerPrefs.GetInt("HighScore");
}
void Update()
{
if (scoreCount >= highScoreIFA)
{
PlayerPrefs.SetInt("HighScore", scoreCount);
}
}
public void AddToScore()
{
if (isHit == true) // i know this if loop works
{
scoreCount += 1; // and this, I use it to change the score text in-game.
isHit = false;
}
}
}
In AddToScore(), I increment scoreCount.
Through some debugging, I have found that everything in the HSSetter script works - when I change the highScoreText.text, the text on screen changes, which led me to believe the issue might be with the change of scenes? Thanks!
Multiple things you should do here
The first you already updated in your question afterwards: You had the condition wrong and always updated only
if(highScoreIFA > scoreCount)
which would almost always be the case.
Now you have changed it to
if(scoreCount >= highScoreIFA)
which still is not good since if the score is equal there is no reason to update it, yet.
I would rather use
if(scoreCount > highScoreIFA)
so only really update it when needed.
Secondly in both scripts do not use Update at all! That is extremely inefficient.
I would rather use event driven approach and only change and set stuff in the one single moment it actually happens.
You should only one single class (e.g. the score) be responsible and allowed to read and write the PlayerPrefs for this. I know lot of people tent to use the PlayerPrefs for quick and dirty cross access to variables. But it is exactly this: Quick but very dirty and error prone.
If you change the keyname in the future you'll have to do it in multiple scripts.
Instead rather let only the score do it but then let other scripts reference it and retrieve the values directly from that script instead
And finally you should use
PlayerPrefs.Save();
to create checkpoints. It is automatically done in OnApplicationQuit, bit in case your app is force closed or crashes the User would lose progress ;)
Might look like
public class score : MonoBehaviour
{
public int scoreCount = 0;
// Use an event so every other script that is interested
// can just register callbacks to this
public event Action<int> onHighScoreChanged;
// Use a property that simply always invoked the event whenever
// the value of the backing field is changed
public int highScoreIFA
{
get => _highScoreIFA;
set
{
_highScoreIFA = value;
onHighScoreChanged?.Invoke(value);
}
}
// backing field for the public property
private int _highScoreIFA;
private void Start()
{
highScoreIFA = PlayerPrefs.GetInt("HighScore");
}
public void AddToScore()
{
if (isHit == true) // i know this if loop works
{
scoreCount += 1; // and this, I use it to change the score text in-game.
isHit = false;
// Only update the Highscore if it is greater
// not greater or equal
if (scoreCount > highScoreIFA)
{
PlayerPrefs.SetInt("HighScore", scoreCount);
// Save is called automatically in OnApplicationQuit
// On certain checkpoints you should call it anyway to avoid data loss
// in case the app is force closed or crashes for some reason
PlayerPrefs.Save();
}
}
}
}
Then your other script only listens to the event and updates its display accordingly. It is even questionable if both scripts should not rather simply be one ;)
public class HSSetter : MonoBehaviour
{
public Text highScoreText;
// Reference your Score script here
[SerializeField] private score _score;
private void Awake ()
{
// Find it on runtime as fallback
if(!_score) _score = FindObjectOfType<score>();
// Register a callback to be invoked everytime there is a new Highscore
// Including the loaded one from Start
_score.onHighScoreChanged += OnHighScoreChanged;
}
private void OnDestroy()
{
_score.onHighScoreChanged += OnHighScoreChanged;
}
private void OnHighScoreChanged(int newHighScore)
{
highScoreText.text = $"High Score: {newHighScore}";
}
}

Categories

Resources