Function not showing up in OnClick() for unity - c#

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;
}
}

Related

.GetComponent Function Makes my Variable = 0

StripeNum is on a button and the colour function is set to the same colour button and using Debug.Log it shows stripe1 = 20. But in the second script Debug.Log stripe1.stripe1 = 0. Im just referencing the game object the script is on (the same gameobject is used as the object for the button) Image of The Console Showing Debug.Logs
using UnityEngine;
public class StripeNum : MonoBehaviour
{
public void black()
{
stripe1 = 0;
}
public void brown()
{
stripe1 = 10;
}
public void red()
{
stripe1 = 20;
Debug.Log(stripe1);
}
public void orange()
{
stripe1 = 30;
}
public void yellow()
{
stripe1 = 40;
}
public void green()
{
stripe1 = 50;
}
public void blue()
{
stripe1 = 60;
}
public void purple()
{
stripe1 = 70;
}
public void grey()
{
stripe1 = 80;
}
public void white()
{
stripe1 = 90;
}
public float stripe1;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class FinalCalc : MonoBehaviour
{
Scene c_scene;
float TwoStripesAdded;
float FinalR;
public Text FinalNum;
void Start(){
c_scene = SceneManager.GetActiveScene();
GameObject gameobject = GameObject.Find("GameObject");
StripeNum stripe1 = gameobject.GetComponent<StripeNum>();
Stripe2Num stripe2 = gameobject.GetComponent<Stripe2Num>();
Stripe3Num stripe3 = gameobject.GetComponent<Stripe3Num>();
Stripe4Num stripe4 = gameobject.GetComponent<Stripe4Num>();
if (c_scene.buildIndex == 6){
TwoStripesAdded = stripe1.stripe1 + stripe2.stripe1;
Debug.Log($"Added {stripe1.stripe1} and {stripe2.stripe1} and got {TwoStripesAdded}");
FinalR = TwoStripesAdded * stripe3.stripe1;
FinalNum.text = FinalR.ToString() + "Ω " + "±" + stripe4.stripe1 + "%";
}
}
}
Why not just name the class Stripe and have multiple instances of it? You can have empty child GameObjects and you can plop each stripe MonoBehaviour on the empty child. Then you can name the GameObject Stripe1, Stripe2, etc.
In Start() you can find those GameObjects, get the component attached to each, and cache those references so you don't have to keep re-getting them.
Aaaand actually in looking at your code I was assuming you were running this in Update, but you're running the check in Start. I don't know when or how you're setting colors, but if you're doing it in Play mode it's already too late, because this script won't check the colors.
You can't activate the methods until play mode (which is why I was asking you how you set it), so the only way to get a reading is if you set the value in Editor mode, but again that's not going to call a method.
Maybe what you're doing is setting the value in Editor mode that corresponds to a color?
Whatever the case, I think your data is not initialized when you check it, which is only once, before the first frame is drawn. If you're getting other debug messages then I need to know how you're getting. The Sum should be printed before anyone gets to set a value in Play mode.
Also a thought - you're checking the scene for some reason? If you set values and change scenes, all your objects are destroyed. The resistor calculator in one scene is a different instance than the one in scene 6 and will not have any values set on any stripes.

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.

An Unity3D button appears to be null while trying to disable it

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).

Pass Value to One Script to Another in Unity3d

Currently, I'm trying to add / subtract value from one script to another. I wanted script one to add +125 health to script two but don't know how. There is no gameobject involved in this scenarios.
Script one is
using UnityEngine;
using System.Collections;
public class AddHealth : MonoBehaviour {
int health = 10;
public void ChokeAdd()
{
AddHealthNow();
}
public void AddHealthNow()
{
health += 125;
Debug.Log("Added +125 Health");
}
}
Script two is
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace CompleteProject
{
public class DataManager : MonoBehaviour
{
public static int depth;
public Text BOPPressureText;
int health = 20;
void Awake ()
{
depth = 0 ;
}
void Update ()
{
BOPPressureText.text = depth + 7 * (health) + " psi ";
}
}
}
If you're trying to add health to your second script, declare your health field as public. So that you can access its value in your first script.
public int health;
But I wouldn't do stuff like that. Expose this field by a property like:
public int Health
{
get
{
return this.health;
}
set
{
this.health = value;
}
}
by default the health will be declared as
private int health;
Other scripts can't access private fields.
Also you need a reference to your second script. You can access this via:
public DataManager data;
You've to assign your second object into this field in your Unity Editor. Then
This way, you can access the field healthby calling data.health += 125 in your first script.
I don't know the specific thing in Unity, but I think you can also call your script by:
DataManager data = GetComponent<DataManager>();
data.health += 125;
Other method to get your other script is call it like that in your first script:
var secondScript = GameObject.FindObjectOfType(typeof(DataManager)) as DataManager;
secondScript.health += 125;

Categories