hi
there is a ui text in each scene called gamescore.
i have a scoremanager gameobject in each scene too.
i attached scoremanager to scoremanager gameobject and made it as singleton.
what i try to implement is to save scores from each game session and write it to score int
and keep it permanent between game run sessions. and also show it to user via gamescore text.
this code does not work properly , though there are no errors in console. any idea would be welcomed.
public class ScoreManager : MonoBehaviour
{
public static ScoreManager instance;
public float minEventTime = 2;
public float maxEventTime = 3;
public int score;
public Text scoreText;
public int lives = 3;
public Text livesText;
public Image livesimage;
public GameObject GameOver;
void Awake()
{
if (instance == null)
instance = this;
else if (instance != null)
Destroy (gameObject);
}
void Start()
{
score = PlayerPrefs.GetInt ("Gamescores");
if (score == 0)
score = 0;
scoreText.text = score.ToString ();
}
void Update()
{
scoreText.text = score.ToString ();
if (ScoreManager.instance.lives <= 0)
{
GameOver.SetActive (true);
}
}
}
and here count will increament by 1 unit as game score :
void RandomItem()
{
bool isValid = false;
InteractableObj ObjToChangeState;
int count = 0;
do
{
ObjToChangeState = AllObjs[Random.Range(0, AllObjs.Length)];
if(!ObjToChangeState.isUsed)
{
ObjToChangeState.isUsed = true;
ObjToChangeState.ChangeState(true);
isValid = true;
}
count++;
PlayerPrefs.SetInt ("Gamescores" , count);
}
while(!isValid);
RandomTimer ();
}
In the second code snippet your setting the integer in player prefs to count, which overwrites whatever was there before, and since count starts at 0, and it doesn’t look like it ever gets set to what “Gamescores” is actually set to, that means the number is getting changed in the player prefs, probably in a way that makes this problem.
I’d try and have just one script that handles all the persistent data in the game, maybe call it “SaveGame.cs” and have it act as a singleton, perhaps a static class. Then you call “SaveScore(someInteger);” whenever you want to save, and always make sure your sending it the newest updated score, and never use player prefs calls in other scripts, to help avoid situations where you aren’t sure why things aren’t saving like this.
1 Like
as you can see there are Public ui int and Text there in these classes.
now if i use one class instead , this class will work fine in gameplay scenes , but back to main menu scene , actually some of those public properties dont exist like player lives .
to create one class will make no conflicts in that main menu scene?
P.S : i also need ui score text in gameplay scenes act like a counter . that mean after end of each game session , they become 0 . and count new for new game trying.
but there in main menu scene that score ui text shows the total score from all times .
could you please do some snippets?
I may be misunderstanding the problem, so let me ask some questions to see what you are trying to do.
You want to have the score save only if the player doesn’t start a new game - is that right? Like, for instance, the player could quit the game, and later return to the game, and still pick up where they left off? But reset the score to 0 if the player runs out of lives, or starts a new game?
And you want your score UI to persist between scene changes (or at least to show the same score after scene changes) - is that right?
1 Like
i need when player return back to game , they pick up from where they left off . yes.
if also they run out of lives , or at any time they reset the current game , they pik up all they have already sammelt, gathered i mean .
and ui score in gameplay scenes start from 0 to whatever player pick ups . but ui score in main menu scene shows overal scores.
P.S:
i made all codes in one class as below. my question is this class is attached to gameobject in gameplay scenes and in inspector , are assigned public fields… but the same class is attached to a gameobject in main menu scene too , there i did not need use of player lives . and some fields in that scene will empty remain. what should i do in this case?
public class GameController : MonoBehaviour
{
public static GameController instance;
public InteractableObj[] AllObjs;
public float minEventTime = 2;
public float maxEventTime = 3;
public int score;
public Text scoreText;
public int lives = 3;
public Text livesText;
public Image livesimage;
public GameObject GameOver;
void Awake()
{
if (instance == null)
instance = this;
else if (instance != null)
Destroy (gameObject);
}
public void Start()
{
AllObjs = FindObjectsOfType<InteractableObj> ();
RandomTimer ();
Time.timeScale = 1.0f;
score = PlayerPrefs.GetInt ("Gamescores");
if (score == 0)
score = 0;
scoreText.text = score.ToString ();
}
void Update()
{
scoreText.text = score.ToString ();
if (lives <= 0)
{
GameOver.SetActive (true);
}
}
void RandomTimer()
{
float rnd = Random.Range (minEventTime, maxEventTime);
Invoke ("RandomItem", rnd);
}
void RandomItem()
{
bool isValid = false;
InteractableObj ObjToChangeState;
int count = 0;
do
{
ObjToChangeState = AllObjs[Random.Range(0, AllObjs.Length)];
if(!ObjToChangeState.isUsed)
{
ObjToChangeState.isUsed = true;
ObjToChangeState.ChangeState(true);
isValid = true;
}
count++;
PlayerPrefs.SetInt ("Gamescores" , count);
}
while(!isValid);
RandomTimer ();
}
}
Okay if the object with this “master” script on it is going to be used from the main menu throughout the rest of the game scenes, then you should only include it in the main scene (assuming the main scene loads first when the game starts) and then call DontDestroyOnLoad to make sure the game object with this script in that first scene does not get destroyed when you change scenes.
You will need to make sure if you return to the main scene again later after playing and going back, that you don’t create another duplicate of the object, but it seems you already do this type of check in the Start method, so that part should be fine.
If you need to “load up” the game from some saved state (and load the score amount) then when your user selects to resume the game from the main menu, that is when you look up the score from player prefs, then assign the values to the actual variables. If the player instead hits new game you just assign the latest score to 0.
If you want to keep a memory of past scores, you will need to use a more complex system, perhaps by doing “CurrentGamescore” and “BestGamescore” or something like that in the player prefs.
1 Like
all right. this script i use with singleton as you said above in first paragraph. its ok until i go to new scene. there my singleton will miss score text field.
how should i say to this script to find in each scene the correspondent ui text for game score?
Perhaps you could also keep the same canvas from the main menu scene, and don’t destroy it when changing scenes (maybe just a simple script that just calls DontDestroyOnLoad for the canvas, and checks for duplicate instance during start method like the other script does).
Once the canvas stays alive through scenes, you don’t have to worry about breaking reference when you change scenes, and you don’t need the score canvas in each game scene, just the main scene like the “master” object.
1 Like
yes! but you know , i would like , only in each new scene except main menu scene , to reference to ui score text rather than move all the canvas. all of my game ui is a Game score.
may you please help me to understand how to refer to ui text with singleton in other scenes too?
in first scene its only drag and drop . but i have no idea how in run time singleton will fetch a ui text?
Well it would be possible to just use a quick check in the Update method of the master script, which looks for the text to become null. This check should only be performed in the game scenes, at least if the main menu scene does not show the score canvas. Then each score canvas gameobject would need to be either named exactly the same name (like “ScoreCanvas” it would say in the inspector in each scene the canvas appears in) or it could be tagged with a special tag to identify it as the canvas that has the score text on it.
You could also find the actual text object (the child under the canvas, which displays the score) instead.
Once you have decided if your going to use the name of the objects or the tags, you can search for objects using GameObject.Find to search for an object with a specific name, or you could use GameObject.FindWithTag to find them by the tag.
So your Update method might end up having something like this to check for the text being null before searching for the new one:
void Update()
{
if(scoreText == null)
{
// WARNING: you need to make sure your not in the main menu also!
scoreText = GameObject.Find("ScoreText").GetComponent<Text>(); // the actual text objects name as it appears in the inspector
// alternatively you could use tags, and tag the canvas or the text object itself
}
scoreText.text = score.ToString();
if (lives <= 0)
{
GameOver.SetActive(true);
}
}
EDIT: Fixed a mistake, had to use GetComponent to get the actual text component of the gameobject. Updated the script above.
1 Like
sometimes a simple thing is hard to do . this is my master script . in main menu it is ok but still in other scenes i cannot on run time to fetch the score text. i dont know if the should happen in one script ? or referencing ui text in new scene should be done with another script in that scene.?
public class ScoreManager : MonoBehaviour
{
public static ScoreManager instance;
private int score;
public Text scoreText;
private GameObject scoreTexts;
void Awake()
{
if (instance == null)
{
DontDestroyOnLoad (gameObject);
instance = this;
}
else if (instance != null)
{
Destroy (gameObject);
}
}
void Start()
{
scoreTexts = GameObject.FindGameObjectWithTag("Gamescores");
}
}
this ui text is a child of a ui image gameobject inside canvas. can this be the reason i cannot find it on run time?
scoreText = GameObject.FindGameObjectWithTag ("Gamescores").GetComponent<Text> ();
any idea?
i searched alot!
how will you fetch a ui text which is inside a canvas and is the child of ui image on runtime via a singleton class?
Canvas…
…UI image
…UI text
i taged it . find… no clue !
Use a ScriptableObject and save when you need to from there. Otherwise it will reset to whatever the defaults are on load. Super simple.
still no answer .
if someone can with a little snippet reference a ui text inside canvas and post it here , i would be happy . its hours i am searching. i got no correct clue.i have a singleton in main menu . i need in other scenes , it reference score ui text .
Perhaps you can add a script onto the score text object that subscribes to an event on the singleton. When your score changes, you can call the event with the new score. Remember to unsubscribe from the event when the object is disabled.
bro , that is high programming language , please slow and slow 
in every new scene except main menu , my score text has no script …has no thing connected to .
what i need is to connect it to singleton and feed it text int from saved score from playerpref.set int
any idea maybe?
thanks in advanced .
Doesn’t matter if there is no script on the text object right now, you can add one. 
Of course you could use GameObject Find / FindWithTag if you want, that’s just not what I would normally suggest. It was mentioned earlier in the thread, I believe.
I can offer you a slightly different variation of what I wrote before. Imagine when the scene loads, you have a script on the UI Text. This script, say in Start(), does something like :
void Start() {
ScoreManager.Instance.ScoreText = GetComponent<Text>();
}
Now, of course that’s not an event, but setting up a connection at the beginning of the scene is correct, and the object itself tells the singleton what it needs to know. 
1 Like
i will follow your suggestion 
how public score text field of singleton , will be referenced correctly to score ui text in other scenes?
Well, I just explained that in my last example.
Put a script on the UI Text game object. In Start(), assign its Text component to the singleton’s score text field.

1 Like