An Unity3D button appears to be null while trying to disable it - c#

What I'm trying to do is disable the button when the time is up. But I get an error while I set the button to be disable: it appears to be null.
The following script (RightButton.cs) includes a function called DisableButton that is invoked by the main script (TappingEngine.cs).
The statement that hangs inside the DisableButton function is btn.interactable = false;.
/* RightButton.cs */
using UnityEngine;
using UnityEngine.UI;
public class RightButton : MonoBehaviour {
Button btn;
// Use this for initialization
void Start () {
Debug.Log("Right button ready.");
}
public void Tap()
{
Debug.Log("Tap right! tot: " + TappingEngine.te.nTaps);
TappingEngine.te.Tap(TappingEngine.tapType_t.right);
}
public void DisableButton()
{
btn = this.GetComponent<Button>();
btn.interactable = false;
}
}
The following code is a part of the main script (which is quite long). However, someone advised me to post the full version for clarity.
(Focus on the two functions Update () and DisableButtons().)
/* TappingEngine.cs */
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class TappingEngine : MonoBehaviour {
public static TappingEngine te;
public int nTaps = 0;
public int GlobalTotal;
public int RightTaps;
public int LeftTaps;
public string FirstTap;
public int LastTap;
public int MaxChain;
public int FastestTwoTaps;
public int FastestTwoChainedTaps;
public GlobalTotalTaps GlobalTotalTaps_script;
public TotalRightTaps RightTotalTaps_script;
public TotalLeftTaps LeftTotalTaps_script;
public FirstTap FirstTap_script;
public RightButton RightButton_script;
const float TimeSpan = 5F;
public float Chrono;
public bool ChronoStart = false;
public bool ChronoFinished = false;
public float ElapsedPercent = 0F;
public enum tapType_t { right, left };
// Use this for initialization
void Start () {
GlobalTotal = 0;
te = this;
GlobalTotalTaps_script = FindObjectOfType(typeof(GlobalTotalTaps)) as GlobalTotalTaps;
RightTotalTaps_script = FindObjectOfType(typeof(TotalRightTaps)) as TotalRightTaps;
LeftTotalTaps_script = FindObjectOfType(typeof(TotalLeftTaps)) as TotalLeftTaps;
FirstTap_script = FindObjectOfType(typeof(FirstTap)) as FirstTap;
RightButton_script = FindObjectOfType(typeof(RightButton)) as RightButton;
}
// Update is called once per frame
void Update () {
if(ChronoStart) {
ElapsedPercent = (Time.time - Chrono) * 100 / TimeSpan;
if(ElapsedPercent >= 100F) {
DisableButtons();
//SceneManager.LoadScene("Conclusion", LoadSceneMode.Single);
}
}
Debug.Log("Elapsed time: " + (Time.time - Chrono));
}
private void DisableButtons()
{
RightButton_script.DisableButton();
}
public void OnTap() {
Debug.Log("Tap!");
}
public void Tap(tapType_t tapType) {
Manage_GlobalTotalTaps();
if(GlobalTotal == 1) {
Manage_FirstTap(tapType);
ChronoStart = true;
Chrono = Time.time;
}
Manage_LeftRight(tapType);
}
private void Manage_FirstTap(tapType_t tapType)
{
FirstTap = tapType.ToString();
FirstTap_script.FastUpdate();
}
private void Manage_LeftRight(tapType_t tapType)
{
if (tapType.Equals(tapType_t.left))
{
LeftTaps++;
LeftTotalTaps_script.FastUpdate();
}
else
{
RightTaps++;
RightTotalTaps_script.FastUpdate();
}
}
public void Manage_GlobalTotalTaps() {
GlobalTotal++;
GlobalTotalTaps_script.FastUpdate();
}
}
Below are a couple of screenshots that I hope will be useful.
Until now I have not yet figured out where the problem is. Moreover, the script of the button is very similar to that of the various Text objects that represent the statistics (the list on the right side of the screen).
With Text objects it works, with the Button object not.

I asked the same question on Unity3D Forum and I got the solution here.
One the game object where I attached the RightButton.cs there is a variable on line 24 Button btn; that needs to be set to public, so public Button btn;.
This makes appearing a new entry in the Inspector of the Right Button object (see the image below) and so in Unity3D drag and drop the Right Button GameObject into Right Button (Script)'s proper field (Btn in this case).

Related

Function not showing up in OnClick() for unity

I've been trying to get a function to return a number to change the text in a button. However, I can not use the functions I wrote with OnClick(). I won't show up.
Here is the script I've been working with.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class DiceRollerBehavior : MonoBehaviour
{
public int setRandom;
// Start is called before the first frame update
void Start()
{
setRandom = 0;
}
// Update is called once per frame
void Update()
{
}
public int roll()
{
setRandom = Random.Range(1, 10);
Debug.Log("Your new number is:" + setRandom.ToString());
return setRandom;
}
}
The OnClick() should put the roll function in this list but doesn't.
I just need to be able to trigger a function in this script using the OnClick() feature for unity.
To be able to set a callback here it must be public void, not public int.
Also, your code will not change any text. To be able to do this, you need to assign the text label you want to change to a class field. So, it will look like this:
public class DiceRollerBehavior : MonoBehaviour
{
[SerializeField]
private Text _text; // assign this field in the inspector
public int setRandom;
void Start()
{
setRandom = 0;
}
public void OnBtnClick()
{
int rollValue = roll();
_text.text = #"{rollValue}";
}
int roll()
{
setRandom = Random.Range(1, 10);
Debug.Log("Your new number is:" + setRandom.ToString());
return setRandom;
}
}

UNity3d Adding a value via button and getting random results

i found my next tier 1 problem and hoping for some help here in the so called internet.
first of all here are my atm not to hard to understanding codes.
please tell me if im doing something wrong here on stackoverflow im an absolute newbie and dont know how to explain my problem in this case without post a bunch of code :(
i know there are much ways to improve mystuff but im in the learning process and for now its maybe enough to tell my why the behavior of my code didnt match my expectations.
This is my PlayerClass:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Values : MonoBehaviour
{
public float MaxNrg;
public float Nrg;
public float NrgDrain;
public float NrgDrainCoef;
public float NrgInPercent;
// Start is called before the first frame update
public void Start()
{
MaxNrg = 7950.0f;
Nrg = 7950.0f;
NrgDrain = 0.09201389f;
NrgDrainCoef = 1.0f;
}
// Update is called once per frame
public void Update()
{
}
public void FixedUpdate()
{
NrgInPercent = (GETnrg() / GETmaxnrg()) * 100;
}
public void SETmaxnrg(float tmpfloat)
{
MaxNrg = tmpfloat;
}
public void SETnrg(float tmpfloat)
{
Nrg = tmpfloat;
}
public void SETnrgdrain(float tmpfloat)
{
NrgDrain = tmpfloat;
}
public void SETnrgdraincoef(float tmpfloat)
{
NrgDrainCoef = tmpfloat;
}
public void ADDmaxnrg(float tmpfloat)
{
MaxNrg += tmpfloat;
}
public void ADDnrg(float tmpfloat)
{
Nrg += tmpfloat;
}
public void ADDnrgdrain(float tmpfloat)
{
NrgDrain += tmpfloat;
}
public void ADDnrgdraincoef(float tmpfloat)
{
NrgDrainCoef += tmpfloat;
}
public float GETmaxnrg()
{
return MaxNrg;
}
public float GETnrg()
{
return Nrg;
}
public float GETnrgdrain()
{
return NrgDrain;
}
public float GETnrgdraincoef()
{
return NrgDrainCoef;
}
public float GETnrginpercent()
{
return NrgInPercent;
}
}
End Here are the "Drain_mechanics":
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Drain_Mechanics : MonoBehaviour
{
public bool drainstate = false;
public double NrgLeftInSeconds;
public GameObject Scriptcontainer_Player;
// Start is called before the first frame update
public void Start()
{
Scriptcontainer_Player = GameObject.Find("Scriptcontainer_Player");
}
// Update is called once per frame
public void Update()
{
}
public void FixedUpdate()
{
if(drainstate == true)
{
Scriptcontainer_Player.GetComponent<Player_Values>().Nrg -= Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdrain() * Time.deltaTime * Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdraincoef();
}
else if(drainstate == false)
{
}
NrgLeftInSeconds = Scriptcontainer_Player.GetComponent<Player_Values>().GETnrg() / (Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdrain() * Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdraincoef());
}
public void SETdrainstate(bool tmpdrainstate)
{
drainstate = tmpdrainstate;
}
public double GETnrgleftinseconds()
{
return NrgLeftInSeconds;
}
}
Class for initializing the input fields in the game:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text.RegularExpressions;
public class Initialize_InputFields : MonoBehaviour
{
public GameObject Input_Energy;
public GameObject Input_Drainrate;
public GameObject Input_DrainCoef;
public float InputNrg;
public float InputNrgDrainrate;
public float InputNrgDrainCoef;
// Start is called before the first frame update
public void Start()
{
Input_Energy = GameObject.Find("Input_Energy");
Input_Drainrate = GameObject.Find("Input_Drainrate");
Input_DrainCoef = GameObject.Find("Input_DrainCoef");
}
// Update is called once per frame
void FixedUpdate()
{
InputNrg = float.Parse(Input_Energy.GetComponent<InputField>().text);
InputNrgDrainrate = float.Parse(Input_Drainrate.GetComponent<InputField>().text);
InputNrgDrainCoef = float.Parse(Input_DrainCoef.GetComponent<InputField>().text);
}
public float GETinputnrg()
{
return InputNrg;
}
public float GETinputnrgdrainrate()
{
return InputNrgDrainrate;
}
public float GETinputnrgdraincoef()
{
return InputNrgDrainCoef;
}
}
a class to manipulate the textfields while the game is running
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Display_LabelsCalculated : MonoBehaviour
{
public GameObject Scriptcontainer_Player;
public GameObject Scriptcontainer_GameMechanics;
public GameObject Display_Energy;
public GameObject Display_EnergyDrain;
public GameObject Display_EnergyDrainCoef;
public GameObject Display_EnergyTimeleft;
public GameObject Display_EnergyPercentleft;
public Text Display_Energy_Text;
public Text Display_EnergyDrain_Text;
public Text Display_EnergyDrainCoef_Text;
public Text Display_EnergyTimeleft_Text;
public Text Display_EnergyPercentleft_Text;
// Start is called before the first frame update
void Start()
{
Scriptcontainer_Player = GameObject.Find("Scriptcontainer_Player");
Scriptcontainer_GameMechanics = GameObject.Find("Scriptcontainer_GameMechanics");
Display_Energy = GameObject.Find("Display_Energy");
Display_EnergyDrain = GameObject.Find("Display_EnergyDrain");
Display_EnergyDrainCoef = GameObject.Find("Display_EnergyDrainCoef");
Display_EnergyTimeleft = GameObject.Find("Display_EnergyTimeleft");
Display_EnergyPercentleft = GameObject.Find("Display_EnergyPercentleft");
Display_Energy_Text = Display_Energy.GetComponent<Text>();
Display_EnergyDrain_Text = Display_EnergyDrain.GetComponent<Text>();
Display_EnergyDrainCoef_Text = Display_EnergyDrainCoef.GetComponent<Text>();
Display_EnergyTimeleft_Text = Display_EnergyTimeleft.GetComponent<Text>();
Display_EnergyPercentleft_Text = Display_EnergyPercentleft.GetComponent<Text>();
}
// Update is called once per frame
public void Update()
{
}
public void FixedUpdate()
{
int hours = (int)(Scriptcontainer_GameMechanics.GetComponent<Drain_Mechanics>().GETnrgleftinseconds() / 60) / 60;
int minutes = (int)(Scriptcontainer_GameMechanics.GetComponent<Drain_Mechanics>().GETnrgleftinseconds() / 60) % 60;
int seconds = (int)Scriptcontainer_GameMechanics.GetComponent<Drain_Mechanics>().GETnrgleftinseconds() % 60;
Display_EnergyTimeleft_Text.text = hours.ToString() + ":" + ((minutes < 10) ? ("0") : ("")) + minutes.ToString() + ":" + ((seconds < 10) ? ("0") : ("")) + seconds.ToString();
Display_Energy_Text.text = Scriptcontainer_Player.GetComponent<Player_Values>().GETnrg().ToString();
Display_EnergyDrain_Text.text = Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdrain().ToString();
Display_EnergyDrainCoef_Text.text = Scriptcontainer_Player.GetComponent<Player_Values>().GETnrgdraincoef().ToString();
Display_EnergyPercentleft_Text.text = Scriptcontainer_Player.GetComponent<Player_Values>().GETnrginpercent().ToString();
}
}
followed by some button mechanics
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Button_Mechanics : MonoBehaviour
{
public GameObject Scriptcontainer_Player;
public GameObject Scriptcontainer_InputFields;
public GameObject Scriptcontainer_GameMechanics;
public Button Button_SetEnergy;
public Button Button_SetDrainCoef;
public Button Button_SetDrainrate;
public Button Button_AddEnergy;
public Button Button_AddDrainCoef;
public Button Button_AddDrainrate;
public Button Button_ActivateMechanics;
public Button Button_DeactivateMechanics;
public Button Button_ResetValues;
// Start is called before the first frame update
public void Start()
{
Scriptcontainer_Player = GameObject.Find("Scriptcontainer_Player");
Scriptcontainer_InputFields = GameObject.Find("Scriptcontainer_InputFields");
Scriptcontainer_GameMechanics = GameObject.Find("Scriptcontainer_GameMechanics");
Button_SetEnergy = GameObject.Find("Button_SetEnergy").GetComponent<Button>();
Button_SetDrainCoef = GameObject.Find("Button_SetDrainCoef").GetComponent<Button>();
Button_SetDrainrate = GameObject.Find("Button_SetDrainrate").GetComponent<Button>();
Button_AddEnergy = GameObject.Find("Button_AddEnergy").GetComponent<Button>();
Button_AddDrainCoef = GameObject.Find("Button_AddDrainCoef").GetComponent<Button>();
Button_AddDrainrate = GameObject.Find("Button_AddDrainrate").GetComponent<Button>();
Button_ActivateMechanics = GameObject.Find("Button_ActivateMechanics").GetComponent<Button>();
Button_DeactivateMechanics = GameObject.Find("Button_DeactivateMechanics").GetComponent<Button>();
Button_ResetValues = GameObject.Find("Button_ResetValues").GetComponent<Button>();
}
public void Update()
{
}
// Update is called once per frame
public void FixedUpdate()
{
Button_SetEnergy.onClick.AddListener(SETnrgbtnclk);
Button_SetDrainCoef.onClick.AddListener(SETnrgdraincoefbtnclk);
Button_SetDrainrate.onClick.AddListener(SETnrgdrainbtnclk);
Button_AddEnergy.onClick.AddListener(ADDnrgbtnclk);
Button_AddDrainCoef.onClick.AddListener(ADDnrgdraincoefbtnclk);
Button_AddDrainrate.onClick.AddListener(ADDnrgdrainbtnclk);
Button_ActivateMechanics.onClick.AddListener(SETactivatemechanicsbtnclk);
Button_DeactivateMechanics.onClick.AddListener(SETdeactivatemechanicsbtnclk);
Button_ResetValues.onClick.AddListener(SETresetbtnclk);
}
public void SETnrgbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrg(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrg());
}
public void SETnrgdrainbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrgdrain(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrgdrainrate());
}
public void SETnrgdraincoefbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrgdraincoef(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrgdraincoef());
}
public void ADDnrgbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().ADDnrg(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrg());
}
public void ADDnrgdrainbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().ADDnrgdrain(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrgdrainrate());
}
public void ADDnrgdraincoefbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().ADDnrgdraincoef(Scriptcontainer_InputFields.GetComponent<Initialize_InputFields>().GETinputnrgdraincoef());
}
public void SETactivatemechanicsbtnclk()
{
Scriptcontainer_GameMechanics.GetComponent<Drain_Mechanics>().SETdrainstate(true);
}
public void SETdeactivatemechanicsbtnclk()
{
Scriptcontainer_GameMechanics.GetComponent<Drain_Mechanics>().SETdrainstate(false);
}
public void SETresetbtnclk()
{
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrg(7950);
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrgdrain(0.09201389f);
Scriptcontainer_Player.GetComponent<Player_Values>().SETnrgdraincoef(1.0f);
}
}
at this point i apollogize one more time the amount of text im posting here but otherwise i cant even explain whats going on. and im not able to pick the exact codesnippets which are needed here. it will be better in future.
basically the main mechnisms work fine and im absolutely proud of what i did here...
my problems are the following.
Major problem 1. when i enter a value in the input fields and perform the button SET actions, i HAVE to do it in a specific order. NRG->DRAIN->COEF
otherwise the calculated textboxes are doing random stuff.
Major problem 2. when i try to perform the button add actions, the game also do random stuff. even when i set all variable to fixed values.
minor problem 3. in the Initialize_InputFields.cs im using the float.parse functionality. and my game constantly create warnings about a formatexception. is there a smarter way to solve this.
minor problem 4. last but not leat i want to work with realtime values. is there a way in unity to accerlate the globale timescale for the whole game?

decrease variable by button click C#

I want to decrease a value by clicking a button, but it does not stay at and turns back to the value at the beginning,
here is my code, what should I add or change can somebody help me?
Thanks a lot
public class LifeShow : MonoBehaviour
{
public GameObject Life; //where the variable will be decreased from
public int Lifevalue;
public string text;
public Button returns;
// Start is called before the first frame update
void Start()
{
Lifevalue = 1;
Life.GetComponent<Text>().text = "Life : " + Lifevalue;
}
// Update is called once per frame
// clicking the button and the lifevalue variable decreases
void Update()
{
Button btn = returns.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
void TaskOnClick()
{
Lifevalue-- ;
Life.GetComponent<Text>().text = "Life : " + Lifevalue;
}
}
}
What you can do is change the local method void TaskOnClick() to a public method by putting it outside update and using public keyword and you can add OnClick in unity
now hit the '+' button and drag and drop your object that script attached to. You can then find as this
choose your function and you are ready. You don't need to do this by script.
If you want to restrict it to not go below 0 you can add a If condition in script
if(LifeValue > 0)
{
LifeValue--;
// showing text
}
It will prevent to go below 0.
OnClick + to add listener
Drag listener object to slot (Life)
Choice function from Life script (Modify)
Set argument value 1 / -1 / -99
[DisallowMultipleComponent]
public class Life : MonoBehaviour {
public event System.Action<int> Changed; // event with INT attribute
private int _amouth;
public int Amouth { // this in property
get => _amouth;
// when you set Amouth, then change _amouth and invoke "Changed" event
set {
if (_amouth != value) {
_amouth = value;
Changed?.Invoke(_amouth);
}
}
}
private void Start () {
Amouth = 1;
}
public void Modify (int number) {
Amouth += number;
}
}
[DisallowMultipleComponent]
[RequireComponent(typeof(Text))]
public class LifeView : MonoBehaviour { // Add Component to text object
[SerializeField] private Life _life; // set on inspector window
private Text _text;
public int LineAmouth { get; private set; }
private void OnEnable () {
_text = GetComponent<Text>();
UpdateText(_life.Amouth);
_life.Changed += UpdateText; // subscribes to Life event
}
private void OnDisable () {
_life.Changed -= UpdateText;
}
private void UpdateText (int amouth) {
_text.text = "Life : "+amouth;
}
}
Not really an expert of Mono but, first of all it seems that you are attaching an event handler on every frame, which is not good. The code should be:
public class LifeShow : MonoBehaviour
{
public GameObject Life; //where the variable will be decreased from
public int Lifevalue;
public string text;
public Button returns;
// Start is called before the first frame update
void Start()
{
Lifevalue = 1;
Life.GetComponent<Text>().text = "Life : " + Lifevalue;
Button btn = returns.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
}
// Update is called once per frame
void Update()
{
}
void TaskOnClick()
{
Lifevalue-- ;
Life.GetComponent<Text>().text = "Life : " + Lifevalue;
}
}
Second, it is pretty unclear what's the difference between Lifevalue and the Life GameObject, can you tell?
EDIT: As someone stated in the comments this code is not really enough to give good hints, could you show the Life object's code? That would be pretty helpful.

Unity C#; Why Is My Game Loading The Default State After I Save It In A Different State?

I am making my first game in unity. It is a clicker game, and am working on saving and loading. There is a saving button and a loading button, all linked up to the scripts as they are supposed to, but for some reason, after I press the save button and load button, it loads the default state of the game. Can anyone help me with this? Here are the codes for both scripts, aswell as the script for GlobalTamanduas:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Load : MonoBehaviour {
public int SaveTamanduas;
public int SaveCash;
public int SaveBargainCost;
public int SaveBargainLevel;
public int SaveCloneCost;
public int SaveCloneLevel;
public GameObject LoadButton;
public void Start() {
SaveTamanduas = PlayerPrefs.GetInt("SaveTamanduas");
GlobalTamanduas.TamanduaCount = SaveTamanduas;
SaveCash = PlayerPrefs.GetInt("SaveCash");
GlobalCash.CashCount = SaveCash;
SaveBargainCost = PlayerPrefs.GetInt("SaveBargainCost");
BargainButton.Cost = SaveBargainCost;
SaveCloneCost = PlayerPrefs.GetInt("SaveCloneCost");
CloneButton.Cost = SaveCloneCost;
SaveCloneLevel = PlayerPrefs.GetInt("SaveCloneLevel");
CloneButton.Level = SaveCloneLevel;
SaveBargainLevel = PlayerPrefs.GetInt("SaveBargainLevel");
BargainButton.Level = SaveBargainLevel;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
public class Save : MonoBehaviour {
public static int TamanduaCount = Convert.ToInt32(GlobalTamanduas.TamanduaCount);
public static int CashCount = Convert.ToInt32(GlobalCash.CashCount);
public static int BargainCostCount = Convert.ToInt32(BargainButton.Cost);
public static int BargainLevelCount = Convert.ToInt32(BargainButton.Level);
public static int CloneCostCount = Convert.ToInt32(CloneButton.Cost);
public static int CloneLevelCount = Convert.ToInt32(CloneButton.Level);
public GameObject SaveButton;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void SaveTheGame()
{
PlayerPrefs.SetInt("SaveTamanduas", TamanduaCount);
PlayerPrefs.SetInt("SaveCash", CashCount);
PlayerPrefs.SetInt("SaveBargainCost", BargainCostCount);
PlayerPrefs.SetInt("SaveBargainLevel", BargainLevelCount);
PlayerPrefs.SetInt("SaveCloneCost", CloneCostCount);
PlayerPrefs.SetInt("SaveCloneLevel", CloneLevelCount);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GlobalTamanduas : MonoBehaviour {
public static double TamanduaCount = 0;
public GameObject TamanduaDisplay;
public double InternalTamandua;
// Update is called once per frame
void Update () {
InternalTamandua = TamanduaCount;
TamanduaDisplay.GetComponent<Text>().text = "Tamanduas: " + InternalTamandua;
if (TamanduaCount == 0)
{
if (GlobalCash.CashCount == 0)
{
TamanduaCount += 1;
}
}
}
}
Problem 1
By default PlayerPrefs are only saved in OnApplicationQuit!
In order to "manually" force a saving of the PlayerPrefs you need to call PlayerPrefs.Save after editing the values.
By default Unity writes preferences to disk during OnApplicationQuit(). In cases when the game crashes or otherwise prematuraly exits, you might want to write the PlayerPrefs at sensible 'checkpoints' in your game.
public void SaveTheGame()
{
PlayerPrefs.SetInt("SaveTamanduas", TamanduaCount);
PlayerPrefs.SetInt("SaveCash", CashCount);
PlayerPrefs.SetInt("SaveBargainCost", BargainCostCount);
PlayerPrefs.SetInt("SaveBargainLevel", BargainLevelCount);
PlayerPrefs.SetInt("SaveCloneCost", CloneCostCount);
PlayerPrefs.SetInt("SaveCloneLevel", CloneLevelCount);
PlayerPrefs.Save();
}
Problem 2
int, float, double etc are structs and thereby value types!
You are however only assigning them once in
public static int TamanduaCount = Convert.ToInt32(GlobalTamanduas.TamanduaCount);
public static int CashCount = Convert.ToInt32(GlobalCash.CashCount);
public static int BargainCostCount = Convert.ToInt32(BargainButton.Cost);
public static int BargainLevelCount = Convert.ToInt32(BargainButton.Level);
public static int CloneCostCount = Convert.ToInt32(CloneButton.Cost);
public static int CloneLevelCount = Convert.ToInt32(CloneButton.Level);
This does NOT mean they are automatically updated whenever e.g. GlobalTamanduas.TamanduaCount changes! Since you never assign them again they will keep forever their default values (or the once that were set in these static fields in the moment the static constructor was executed).
So what you rather want to do would be get rid of these static fields in the Save class and rather use
public void SaveTheGame()
{
PlayerPrefs.SetInt("SaveTamanduas", Convert.ToInt32(GlobalTamanduas.TamanduaCount));
PlayerPrefs.SetInt("SaveCash", Convert.ToInt32(GlobalCash.CashCount));
PlayerPrefs.SetInt("SaveBargainCost", Convert.ToInt32(BargainButton.Cost));
PlayerPrefs.SetInt("SaveBargainLevel", Convert.ToInt32(BargainButton.Level));
PlayerPrefs.SetInt("SaveCloneCost", Convert.ToInt32(CloneButton.Cost));
PlayerPrefs.SetInt("SaveCloneLevel", Convert.ToInt32(CloneButton.Level));
PlayerPrefs.Save();
}
In a similar manner there is no need / complete redundancy to keep the values all in local fields when loading. Simply apply them to their according classes and do not additionally store them in the Load class.
Further Notes
You know btw that there is also PlayerPrefs.SetFloat and PlayerPrefs.GetFloat so why not simply using float instead of double and use them without the need of any conversation/parsing?
Especially when you increase them in full steps like in
TamanduaCount += 1;
why is it not simply an int?
And finally I would not all the time poll a value in Update but rather make the whole thing event driven by using a property like e.g.
public class GlobalTamanduas : MonoBehaviour
{
private static double _tamanduaCount;
public static double TamanduaCount
{
get => _tamanduaCount;
set
{
_tamanduaCount = value;
// Inform anyone who is interested in (listening to) this event
OnTamanduaChanged?.Invoke(_tamanduaCount);
}
}
public GameObject TamanduaDisplay;
public static Action<double> OnTamanduaChanged;
void Awake()
{
// Start listening to the event
OnTamanduaChanged += HandleTamandueChanged;
// Handle it once right now
HandleTamanduaChanged(TamanduaCount);
}
private void OnDestroy ()
{
// Important: always clean up listeners to avoid errors
OnTamanduaChanged -= HandleTamandueChanged;
}
void HandleTamandueChanged(double count)
{
TamanduaDisplay.GetComponent<Text>().text = "Tamanduas: " + count;
if (count == 0 && GlobalCash.CashCount == 0)
{
TamanduaCount = 1;
}
}
}

Unity Quiz Game Score in C#

I am making a quiz game in the unity from the unity live session quiz game tutorials everything is working fine except somehow the score isn't working when i Click the button it should add 10 score to the Score. Here are the tutorials : https://unity3d.com/learn/tutorials/topics/scripting/intro-and-setup?playlist=17117 and the code for my Game Controller :
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
public class GameController : MonoBehaviour {
public Text questionDisplayText;
public Text scoreDisplayText;
public Text timeRemainingDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionDisplay;
public GameObject roundEndDisplay;
private DataController dataController;
private RoundData currentRoundData;
private QuestionData[] questionPool;
private bool isRoundActive;
private float timeRemaining;
private int questionIndex;
private int playerScore;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
// Use this for initialization
void Start ()
{
dataController = FindObjectOfType<DataController> ();
currentRoundData = dataController.GetCurrentRoundData ();
questionPool = currentRoundData.questions;
timeRemaining = currentRoundData.timeLimitInSeconds;
UpdateTimeRemainingDisplay();
playerScore = 0;
questionIndex = 0;
ShowQuestion ();
isRoundActive = true;
}
private void ShowQuestion()
{
RemoveAnswerButtons ();
QuestionData questionData = questionPool [questionIndex];
questionDisplayText.text = questionData.questionText;
for (int i = 0; i < questionData.answers.Length; i++)
{
GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();
answerButtonGameObjects.Add(answerButtonGameObject);
answerButtonGameObject.transform.SetParent(answerButtonParent);
AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
answerButton.Setup(questionData.answers[i]);
}
}
private void RemoveAnswerButtons()
{
while (answerButtonGameObjects.Count > 0)
{
answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
answerButtonGameObjects.RemoveAt(0);
}
}
public void AnswerButtonClicked(bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointsAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
}
if (questionPool.Length > questionIndex + 1) {
questionIndex++;
ShowQuestion ();
} else
{
EndRound();
}
}
public void EndRound()
{
isRoundActive = false;
questionDisplay.SetActive (false);
roundEndDisplay.SetActive (true);
}
public void ReturnToMenu()
{
SceneManager.LoadScene ("MenuScreen");
}
private void UpdateTimeRemainingDisplay()
{
timeRemainingDisplayText.text = "Time: " + Mathf.Round (timeRemaining).ToString ();
}
// Update is called once per frame
void Update ()
{
if (isRoundActive)
{
timeRemaining -= Time.deltaTime;
UpdateTimeRemainingDisplay();
if (timeRemaining <= 0f)
{
EndRound();
}
}
}
}
and my answer Button Code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AnswerButton : MonoBehaviour {
public Text answerText;
private AnswerData answerData;
private GameController GameController;
// Use this for initialization
void Start ()
{
GameController = FindObjectOfType<GameController> ();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
GameController.AnswerButtonClicked (answerData.isCorrect);
}
}
and Answer Data :
using UnityEngine;
using System.Collections;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
If everything is working fine (the whole code gets executed correctly, which I presume at this point), you probably did not set the data correctly. In your Game Controller, you have the line
playerScore += currentRoundData.pointsAddedForCorrectAnswer;
in your AnswerButtonClicked method which should add an amount you defined to the score if the answer is correct. Since I presume that your whole code is running fine (I can't see your in-engine setup, only the code here, which looks like the one in the tutorial), this is probably the first location where to look at the error. This value is probably set in the Unity Inspector or via another script, so you may want to go check in other files or the Editor.
The next thing to check is, if the buttons are correctly linked via their event handler. This can be checked by looking at the inspector. In the tutorial series this step is done in part Click to answer at the end of the video.

Categories