simple score system in unity5 - c#

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class score : MonoBehaviour {
public int ballValue;
public Text scoretext;
// Use this for initialization
void Start () {
ballValue = 0;
}
// Update is called once per frame
void Update () {
scoretext.text = ballValue.ToString();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.tag == "bucket")
{
ballValue = ballValue + 1;
}
}
}
ok guys what am i doing wrong over here ,i am a beginner.what i am trying to achieve here is i want my ball to fall down to the bucket and get 1 point or score ,my ball has a actual circle collider and a rigidbody and my bucket has box collider which is a trigger and both of these are prefabs which is being used multiple times in the games just in case if anyone want to know.so can anyone tell me what i am doing wrong hereor can someone guide me to the right tutorial .thank you
(after playing with it for a whilei am able to get 1 point it does not increase and i am getting this error)
Object reference not set to an instance of an object.
and it refers to this line.
void Update () {
scoretext.text = ballValue.ToString();
}
ok guys i just found the real problem,as i said the bucket is a prefab which randomly generating like the pipes in flappy bird, so after creating my core system i drag and drop the text ui into the given place ,and i apply the changes and delete that prefab and when i go back to asset and check that prefab the given place for text says none.so how can i link the text ui directly to the script so it wont dlete it self.

A way to get around this, is having a static class that holds the score and then have your buckets invoke a method in the static class to increase the score.
All you have to do then, is have an empty game object with the static class attached.

Related

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();

How do I fix this null reference error on a text object?

Sorry for the newb question.
I am trying to make a panel display the players final score after the game ends, I copied some code from a brackeys video but it still doesn't work.
I've tried initializing the text variable as null, I've tried some different syntax as well.
Here is the script that displays the score while the player is playing the game. This part works just fine.
using UnityEngine;
using UnityEngine.UI;
public class Score : MonoBehaviour
{
private float timer;
public Text scoreText;
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
scoreText.text = timer.ToString("0.#");
}
}
This script is meant to pull the score from the first script and display it on a text object on the game over panel.
using UnityEngine;
using UnityEngine.UI;
public class DisplayScore : MonoBehaviour
{
public Text finalScore;
void OnEnable()
{
finalScore.text = GetComponent<Score>().scoreText.text.ToString();
}
}
The game is working quite well except for this null reference error.
error come from this line in the second script:
finalScore.text = GetComponent<Score>().scoreText.text.ToString();
Since in Unity the Text constructor is protected, you must access an existing Text object you have created in the editor. Something like this
finalScore = someGameObject.GetComponent<Text>();
finalScore.text = timer.ToString("0.#");
or create a Text object with .AddComponent<Text> as shown here: Text.text

Object Not Instantiating (C#)

I am coding a tower defense game in Unity, and I've ran into a snag while trying to figure out a way to place towers. My idea is to be able to click an art asset in the game when the player has a certain amount of points, and it replaces that art asset with a tower. Unfortunately, even when the player has the right amount of points, the object does not instantiate. I have made sure to link the prefab to the script, but it doesn't work. I'm stumped, the logic of the code seems right but maybe someone can help me figure out what's wrong here.
public class PointManager : MonoBehaviour
{
public int pointCount;
public Text pointDisplay;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
pointDisplay.text = "Points: " + pointCount;
}
}
public class PlaceTower: MonoBehaviour
{
public GameObject Tower;
private GameObject firstTower;
int placeCost = 25;
private PointManager pointsGained;
// Start is called before the first frame update
void Start()
{
pointsGained = GameObject.FindGameObjectWithTag("Point").GetComponent<PointManager>();
}
// Update is called once per frame
void Update()
{
}
private void OnMouseDown()
{
if (pointsGained.pointCount >= placeCost)
{
firstTower = Instantiate(Tower, transform.position, Quaternion.identity);
//Destroy(this.gameObject);
}
}
}
I got it. The problem was not with my code, but with my prefabs. In the documentation, I misread that OnMouseDown works on objects with colliders. While I had set up a circle collider on the object I was trying to instantiate, I had failed to put one on the object I was trying to instantiate from. Doing so fixed the problem immediately. A simple mistake that I would have completely glanced over had it not been for a second opinion. Thank you, Pac0!

Changing text programmatically to show score on game over screen in unity

I've been working on a simple 2D game in unity and it just has three scenes, the start scene, the game scene, and the game over scene. I want to display the score from the game in the game over screen. I created a score manager game object in the game scene that uses the DontDestroyOnLoad() function to carry it over into the game over screen and I gave it access to the score which is managed by the game manager. I've been debugging my code and the score is translated over into the score manager and is maintained when the game over screen loads, but for some reason it won't let me update the score text object. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour {
public static ScoreManager Instance;
private GameController gameController;
private int scoreInstance;
private Text scoreText;
// When scene is first loaded
void Awake() {
this.InstantiateController();
}
// Use this for initialization
void Start () {
GameObject gameControllerObject = GameObject.FindWithTag("GameController");
if (gameControllerObject != null)
{
gameController = gameControllerObject.GetComponent<GameController>();
}
GameObject scoreTextObject = GameObject.FindWithTag("ScoreText");
if (scoreTextObject != null)
{
scoreText = scoreTextObject.GetComponent<Text>();
}
scoreInstance = 0;
scoreText.text = "";
}
// Update is called once per frame
void Update () {
scoreInstance = gameController.score;
Debug.Log("Score: " + scoreInstance.ToString());
scoreText.text = scoreInstance.ToString();
}
private void InstantiateController ()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(this);
}
else if (this != Instance)
{
Destroy(this.gameObject);
}
}
}
So I tried to programmatically gather the "score text" ui component in the start function because I figured I can't just make it public and drag in the text component because the score manager is actually in a different scene than the score text object. I also tried adding this whole bit of code to gather the text component into the update function so that it can do that when the score manager is actually a part of game over screen. Nothing seems to work and I have no idea why. Can anybody please help me with this? Also I keep getting a "NullReferenceException: Object reference not set to an instance of an object" error. Thanks in advance for any help.
Unity Start function is only called the first time the script is enabled, i.e. not every time the scene changes for a DontDestroyOnLoad object.
So if you need to wire up some changes after a scene change, you need to either detect the scene change, or have an object that starts in that scene trigger the code you want to run.
Having another object on the new scene trigger things is easy and pretty fool-proof, but there's a builtin function you can add to your other objects:
void OnLevelWasLoaded(int currentLevel)
{
}
This will be called on level changes, and give you the level's number (not name sadly). However, the above is deprecated and they want you to use Unity's SceneManager, so the proper way to set this up is now:
Unity 5 OnLevelWasLoaded?
Start()
{
SceneManager.sceneLoaded += this.OnLoadCallback;
}
void OnLoadCallback(Scene scene, LoadSceneMode sceneMode)
{
// you can query the name of the loaded scene here
}

C# frames running twice?

This has me utterly confused. I am using unity3d and c# for the scripts and it seems as if the code is running twice per frame. However on button down I have a sprite change position and it only changes once at least I think it does.
I added the Debug in and I am getting results like this:
score 1 at 3.569991 at frame 168
score 2 at 3.57414 at frame 168
score 3 at 3.818392 at frame 183
score 4 at 3.820178 at frame 183
and so forth carrying on. I am not updating the score in any other scripts. There is more to this script but it is just printing the score out on screen.
Is there any reason why a script may run like this?
full script:
using UnityEngine;
using System.Collections;
public class Score : MonoBehaviour {
public static int highScore;
public static int myScore;
public static bool allowScore;
public GUIText myText;
public static bool WhichScene;
//only allows score to start when first object has passed player object
void OnTriggerEnter2D(Collider2D collisionObject) {
allowScore = true;
Debug.Log ("allowScore is true");
}
void Start () {
highScore = PlayerPrefs.GetInt("highScore");
int scale = Screen.height / 20;
myText.fontSize = scale;
}
//add 1 to score every switch
void Update () {
// need to stop score counting
if (DeathOnImpact.dead == true) {
allowScore = false;
} if (Input.GetMouseButtonDown (0) && allowScore == true && WhichScene == true) { // added SpawnerObjectMovement.WhichScene == true
//Input.GetMouseButtonDown (0)
//Input.GetKeyDown("space")
myScore = myScore + 1;
Debug.Log ("My score is " + myScore + " point(s)" + " at time:" + Time.realtimeSinceStartup + " at frame:" + Time.frameCount);
} if (myScore > highScore) {
highScore = myScore;
PlayerPrefs.SetInt("highScore", highScore);
}
myText.text = myScore.ToString ();
//myText.text = "Score: " + myScore.ToString ();
if (Score.WhichScene == false) {
int scale = Screen.height / 40;
myText.fontSize = scale;
myText.text = "practice mode";
}
}
}
The script is attached to a TriggerObject, a sprite, and a Gui Text
WhichScene referes to which button I pressed, 'play' for normal play or 'practice mode' for an easier version. Score is disabled for 'practice mode'.
UPDATE: I have just edited out everything that I have added since the problem arose and it has not been fixed. Im going to check all unity setting to see if anything has changed. It seems in build setting an old Scene which I deleted around when the problem arose is not selcted but just 'shadowed' so I cant select it. The Scene was an exact copy of the PlayScene. Is this a sign of the problem?
SOLUTION: It appears that separating the script into two smaller scripts has solved the issue. I am still unsure why it has only arisen now since it was working before as one, but oh well I guess. Thank you.
Based on your comments, where you have said that your script is attached to 3 GameObjects, that means that the Update() method is getting called 3 times per frame.
public class Score : MonoBehaviour {
public static int myScore;
You have declared myScore as a static int. This functionally means it will be shared by all instances of the Score script that run.
The Update() method of MonoBehaviour is called once per frame for every GameObject that has this script attached. You have 3 GameObjects with this script attached. Therefore, each will call Update() on their individual instance of the Score script.
I'm not sure what you exactly intend to happen, so it's hard for me to give any advice beyond pointing out the problem.
I think that you need to split this script into multiple scripts. This script is doing too much. It's violating the Single Responsibility Principal (SRP). This is one of the most important principles to follow in programming. I'd suggest splitting this into at least 3 scripts. I'd probably make the following scripts:
PlayerStatistics - Attach this script to your player object (I'm assuming that is the sprite you mentioned). It will simply hold the statistics, including score, for your player. There should only be one attached to each player.
ScoreBoard - Attach this script to your GUI component. It will take a reference to the PlayerStatistics. Notice this is a reference to the single instance that is on your Player. Your ScoreBoard script will only read the value of the score from the PlayerStatistics script.
ScoringTrigger - Attach this to your TriggerObject. It would also have a reference to the PlayerStatistics script. It would have the code that checks to see if scoring should be done, and updates the value of the PlayerStatistics script.
To avoid some events to run twice a frame use Events to get imput actions:
if(Event.current.type == EventType.MouseDown){
if(Event.current.button == 0 && allowScore && WhichScene) {
// do it once!
}
}

Categories

Resources