- Home /
Multiple score counters instead of just one?
Hello! I am working on a color matching catch game where you need to match the color of the game object on the bottom of the screen with the color of the game object falling from the top of the screen. The issue I have run into is that instead of having one score counter...the game is acting as if each game object on the bottom of the screen has it's own score counter. For example, if I match three red blocks in a row, the score should and does display 30 points but as soon as I match a different color the score counter resets. And If it comes back to red the score picks up where it left off and goes to 40. Anyway, here is my code that I am using. I have this exact same code on each game object at the bottom of the screen. The only difference is which "other.tag" is called. Hoping another set of eyes may help out, thank you in advance!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Score : MonoBehaviour {
public Text scoreText;
public Text HighScoreText;
public int objectValue;
private int score;
private int highscore;
private SpawnBox spawnController;
// Use this for initialization
void Start () {
GameObject spawnObject = GameObject.FindWithTag("SpawnBox");
if (spawnObject != null)
{
spawnController = spawnObject.GetComponent<SpawnBox>();
}
if (spawnController == null)
{
Debug.Log("Cannot find 'SpawnBox' script");
}
highscore = PlayerPrefs.GetInt("High Score");
HighScoreText.text = "High Score: " + highscore;
score = 0;
UpdateScore();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Box0")
{
score += objectValue;
UpdateScore();
}
else
{
spawnController.GameOver();
}
}
// Update is called once per frame
void UpdateScore () {
scoreText.text = "Score: \n" + score;
if (score > highscore)
{
highscore = score;
PlayerPrefs.SetInt("High Score", highscore);
HighScoreText.text = "High Score: \n" + highscore;
}
}
}
Answer by GrayMatterTutorials · Jan 11, 2017 at 01:22 AM
You are individually tracking scores per object. The easiest solution is to throw the word "static" in front of "int score".
private static int score;
This will make it to where the score belongs to the class rather than to the instance of the class. If you have 5 instances of this class, so 5 objects have a Score component, then there will be 5 different versions of the score variable. Why? Because they belong to the instance and not the class. Makes sense, but why is only one text being displayed? Because there is only one text, not 5. This is a different situation than the instances of Score. This is like having 5 friends who can each have their own piece of cake, but they all choose to want the exact same one. So the 5 friends point to the same piece of cake much like the 5 instances of score points to the same text. So when you update the text, you are updating a single text object from 1 of the 5 instances. Making it static, on the other hand, says that that variable belongs to the class, which there is only one class, and not the instance. So when you change the score, you are changing the score for the one class and you can do this from any of the 5 instances. When you set the text, you are saying that the text equals the score of the class instead of the score of the individual instance of that class.
This should fix your problem. My advice for the future of this project is to separate the logic. I would have a ScoreManager and a Catcher class. The Catcher class goes to a single object catching the falling blocks, and when done right, updates the score of the ScoreManager. Then the ScoreManager will update the text. This way, it's much much cleaner code and you don't have any confusion like this. Either technique will work, so best of luck! As is always the case, if this doesn't work or another problem arises, please comment and I will help as much as I can!
I don't know if you got this to work yet, but it works perfectly fine for me. It may be something other than your score keeping things that is making it update like that?
ScoreManager Class:
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour
{
[SerializeField]
private Text _currentScoreText;
[SerializeField]
private Text _highScoreText;
private int _currentScore;
private int _highScore;
public int currentScore
{
get { return _currentScore; }
set
{
_currentScore = value;
_currentScoreText.text = _currentScore.ToString();
if (_currentScore > highScore)
highScore = _currentScore;
}
}
public int highScore
{
get { return _highScore; }
set
{
_highScore = value;
_highScoreText.text = _highScore.ToString();
}
}
private void Awake()
{
currentScore = 0;
Load();
}
private void OnEnable()
{
Load();
}
private void OnDisable()
{
Save();
}
private void Save()
{
PlayerPrefs.SetInt("HighScore", _highScore);
}
private void Load()
{
highScore = PlayerPrefs.GetInt("HighScore", 0);
}
}
Catcher Class:
using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
public class Catcher : MonoBehaviour
{
[SerializeField]
private ScoreManager _scoreManager;
//Note: This will cause me an error because I don't have this class.
//[SerializeField]
//private SpawnBox _spawnController;
//My own testing method
[SerializeField]
private KeyCode _scoreKey;
/// <summary>
/// This is just to test that individual catchers contibute to the whole.
/// </summary>
private void Update()
{
if (Input.GetKeyDown(_scoreKey))
_scoreManager.currentScore += 1;
}
private void OnTriggerEnter2D(Collider2D collision)
{
//Add your own values here.
if (collision.tag == "Box0")
_scoreManager.currentScore += 1;
//else
// _spawnController.GameOver();
}
}
I hope this new code helps you. I have 4 catchers set up with different scoreKey values: "A", "S", "D", "F". When any of these are pressed, it adds 1 value to the current score. I also have the current score and high score set up in a way similar to how you had it. When you end the game, the ScoreManager will save the high score by calling the OnDisable method. This just reduces the number of saves you have to do within the game. Let me know if you have anymore problems.
Thanks for the explanation, That makes sense! I modified just the one script as well as the others at the bottom of my screen with what you suggested with "Private static int score;" but I'm still getting the same result of the individual scores being kept :(
@Gray$$anonymous$$atterTutorials Is this still applicable since I'm doing a mobile game? One colored block falls from the top of the screen and the player scrolls through the blocks on the bottom until they match the color correctly, the blocks collide, and points are rewarded...There aren't any key presses or taps on the screen.
The key being pressed was just an example of a "condition". Yes, it is applicable. You will just need your condition code to call the "_score$$anonymous$$anager.currentScore += ;" where VARIABLE is whatever the score that needs to be added is. This is the relevant code, but you can make to condition whatever you want. I'm not sure what code you use to register that the blocks hit and matched up. If you have additional problems, provide that code and I will help you set it up!
Would you $$anonymous$$d emailing me? dkitch9@gmail.com
I have a few more questions but I feel like this one has been answered to the fullest extent. I appreciate you and @jakkuchan helping me out!!
Answer by jakkuchan · Jan 11, 2017 at 09:25 AM
For me, scoring is best tracked via a Game Manager and not in individual object scripts as you did here.
I'm not exactly sure how to compile this correctly into one script, that's why I split it up thinking it would work. What I'm trying to achieve is only add to the score when the correct color is matched ( red to red, green to green etc) and as soon as you match a color incorrectly, it's game over..
To Gray$$anonymous$$atterTutorials point, you would want to move the score, highscore and score related text into a singleton class you could call Score$$anonymous$$anager. The Score$$anonymous$$anager class can have a public function to add points, and on its update function (maybe?) perform the text updates based on the new value of score. Then you have another class that you attach to the blocks prefabs that checks for matching and calls the add points function. Also, you may want to move the saving of highscore to the Score$$anonymous$$anager class as a separate function called when the game is over.
Alright I'm not quite sure I'm getting a full grasp on this haha at least the checking for matching part. So essentially, could I just break this up into two scripts as is?
Did you see the Edit I made to my answer. I provided full code for both the Score$$anonymous$$anager and the Catcher class.
Your answer
Follow this Question
Related Questions
Call JS function from Unity Script,How to call a JS Function from a Unity Script? 0 Answers
How to make an enemy ragdoll on death? 1 Answer
How can I instantiate one shot over another? 1 Answer
How to setActive an Object form another scene? Help please. 2 Answers
Please Check the code and tell me why this isn't working?! 1 Answer