UI text not updating - c#

I know, so many of people have asked this question. I have gone to all of those posts, and none of the solutions have solved my problem. i am creating a level progress bar , here in this script i am trying to update text (levelNumber) and add +1 to levelNumber every time level is completed, here i am using playerprefs to save levelNumber so data can passes through next levels(scenes). but problem is levelNumber not even updating in Text field , as per script Text_1 should start from 0 and Text_2 from 1 when game starts its showing values which i have given in inspector 1 and 2. to confirm that i have changed values in inspector to 21 and 30 again when game starts its showing 21 and 30. that means UI Text not updating from script .
public class PrograssBar : MonoBehaviour
{
[SerializeField] private Text Text_1;
[SerializeField] private Text Text_2;
private int levelNumber = 0;
[SerializeField] Transform startTransform;
Transform finishTransform;
[SerializeField] Slider slider;
float maxDistance;
void OnEnable()
{
levelNumber = 0;
}
void Start()
{
finishTransform = GameObject.FindGameObjectWithTag("CloneGoal").GetComponent<Transform>();
maxDistance = getDistance();
levelNumber = PlayerPrefs.GetInt("LevelNumber");
}
void Update()
{
if (startTransform.position.z <= maxDistance)
{
float distance = 1 - (getDistance() / maxDistance);
setProgress(distance);
}
}
float getDistance()
{
return Vector3.Distance(startTransform.position, (finishTransform.position - new Vector3(0, 0, 22)));
}
void setProgress(float p)
{
slider.value = p;
}
private void LevelUp()
{
UpdateLevel(levelNumber + 1);
PlayerPrefs.SetInt("LevelNumber", levelNumber);
}
private void UpdateLevel(int levelNumber)
{
this.levelNumber = levelNumber;
Text_1.text = " " +this.levelNumber.ToString();
Text_2.text = " " +(this.levelNumber + 1).ToString();
}
}

The problem is that you never save your levelNumber to prefs during your execution, so your LevelUp function should look like:
private void LevelUp()
{
UpdateLevel(levelNumber + 1);
PlayerPrefs.SetInt("LevelNumber", levelNumber);
PlayerPrefs.Save();
}
See this doc

In the method private void UpdateLevel(int level) you're setting this.levelNumber = levelNumber.
And the attribute of a method is int level.
So you might want to do:
this.levelNumber = level;
And I'm not quite sure where you're calling the method private void LevelUp() since it's private and it's not called anywhere inside this class.

Related

Recycling a Button for individual object - Unity3D

I am a beginner in Unity and I am currently making a simple game. I have a problem where the button should reappear on the object I am getting contact with. It only shows on the first object that I put the script on.
What I wanted to do is to have a recyclable button that will appear whenever I have contact with objects like the "view" button in most of the games. What keeps happening in my project is that the collision is triggered but the position of the object is in the first object where I put the script to set it active and set the position. I put it in another object because I want the button to show in that object but it keeps appearing in the first object.
This is the script I used:
using UnityEngine;
using UnityEngine.UI;
public class InteractNPC : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse, nameBtn, dialogBox;
[SerializeField] TextAsset characterData;
// [SerializeField] UnityEngine.UI.Text dialogMessage;
private Transform head;
private Vector3 offset = new Vector3(0, 1.0f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
head = this.transform.GetChild(0);
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.GetComponent<Button>().onClick.AddListener(onNameClick);
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
//Character characterJson = JsonUtility.FromJson<Character>(characterData.text);
nameBtn.gameObject.SetActive(true);
// Text lbl = nameBtn.gameObject.GetComponentInChildren(typeof(Text), true) as Text;
// lbl.text = "BOBO";
// nameBtn.GetComponent<Button>().GetComponentInChildren<Text>().text = characterJson.name;
}
}
private void OnTriggerExit(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.gameObject.SetActive(false);
}
}
// DIALOGUE SYSTEM
public void onNameClick()
{
Text dialogMessage, dialogName;
if (dialogBox.gameObject.activeInHierarchy)
{
dialogName = GameObject.Find("Canvas/DialogBox/DialogueName").GetComponent<Text>();
dialogMessage = GameObject.Find("Canvas/DialogBox/Dialogue").GetComponent<Text>();
if (dialogMessage != null && dialogName != null)
{
loadCharacterData(dialogMessage, dialogName);
Debug.Log("not null dialog message");
}
else
{
Debug.Log("null dialog message");
}
}
}
public void loadCharacterData(Text dialogMessage, Text dialogName)
{
Character characterJson = JsonUtility.FromJson<Character>(characterData.text);
dialogName.text = characterJson.name;
dialogMessage.text = characterJson.dialogs[0].choices[1];
}
}
Well your issue is that each and every instnce of your scrip will all the time overwrite
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
every frame.
What you want is set it only once in
[SerializeField] private Button nameBtn;
pivate Character character;
private void Start()
{
...
// do this only once!
character = JsonUtility.FromJson<Character>(characterData.text);
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.gameObject.SetActive(true);
var lbl = nameBtn.gameObject.GetComponentInChildren<Text>(true);
lbl.text = characterJson.name;
var position = Camera.main.WorldToScreenPoint(head.position + offset);
uiUse.transform.position = position;
nameBtn.transform.position = position;
}
}
Further you will have another issue: Each and every instance of your script attaches a callback
nameBtn.GetComponent<Button>().onClick.AddListener(onNameClick);
that is not good! Now whenever you click the button once, the allback is fired for each and every instance of your script.
You would rather do this only if the click was actually invoked for the current object.
For this you could attach the listener only add-hoc when needed like e.g.
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player"))
{
...
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.onClick.AddListener(onNameClick);
}
}
private void OnTriggerExit(Collider other)
{
if (collisionInfo.CompareTag("Player"))
{
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.gameObject.SetActive(false);
}
}
ok we didn't know before your objects move
so well you will need to go back to what you had before and update the position continuously, BUT only while you are the current active object so e.g.
private static InteractNPC buttonOwner;
private Camera mainCamera;
void Update()
{
if(buttonOwner != this) return;
if(!mainCamera) mainCamera = Camera.main;
var position = mainCamera.WorldToScreenPoint(head.position + offset);
uiUse.transform.position = position;
nameBtn.transform.position = position;
}
private void OnTriggerEnter(Collider collisionInfo)
{
if (collisionInfo.CompareTag("Player") && !buttonOwner)
{
...
buttonOwner = this;
}
}
private void OnTriggerExit(Collider other)
{
if (collisionInfo.CompareTag("Player") && buttonOwner == this)
{
nameBtn.onClick.RemoveListener(onNameClick);
nameBtn.gameObject.SetActive(false);
buttonOwner = null;
}
}
As far as I see you never create a new Button, I guess that Unity may think, you want the same Button on all NPCs.
Maybe try to call the constructor for a new Button in the Start Method and see if it then generates a new Button per NPC.

Unity Input.GetKeyDown(KeyCode.Space) not detecting key Press

I'm learning Unity but my key press isn't being detected
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Rigidbody myBody;
private float time = 0.0f;
private bool isMoving = false;
private bool isJumpPressed = false;
void Start(){
myBody = GetComponent<Rigidbody>();
}
void Update()
{
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
Debug.Log(isJumpPressed);
}
void FixedUpdate(){
if(isJumpPressed){
myBody.velocity = new Vector3(0,10,0);
isMoving = true;
Debug.Log("jump");
}
if(isMoving){
time = time + Time.fixedDeltaTime;
if(time>10.0f)
{
//Debug.Log( Debug.Log(gameObject.transform.position.y + " : " + time));
time = 0.0f;
}
}
}
}
why isJumpPressed always false. What am I doing wrong? From what I understand this should work but I'm obviously missing something
UPDATE:
Thanks to everyone who proposed ideas. I got the isJumpPressed to return true when I stopped trying to detect the space bar.
isJumpPressed = Input.GetKeyDown("a");
anyone got any ideas why this would work and not
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
or
isJumpPressed = Input.GetKeyDown("space");
UPDATE 2:
Apparently this is a bug in Linux. I've read it won't happen when the game is built just in the editor. I've found a workaround at
https://forum.unity.com/threads/space-not-working.946974/?_ga=2.25366461.1247665695.1598713842-86850982.1598713842#post-6188199
If any Googler's Stumble upon this issue reference the following code because this is working for me.
public class Player : MonoBehaviour
{
public Rigidbody myBody;
private float time = 0.0f;
private bool isMoving = false;
private bool isJumpPressed = false;
void Start(){
myBody = GetComponent<Rigidbody>();
}
void Update()
{
isJumpPressed = Input.GetKeyDown(SpacebarKey());
if(isJumpPressed)
{
Debug.Log(isJumpPressed);
}
}
void FixedUpdate(){
if(isJumpPressed){
myBody.velocity = new Vector3(0,10,0);
isMoving = true;
Debug.Log("jump");
}
if(isMoving){
time = time + Time.fixedDeltaTime;
if(time>10.0f)
{
//Debug.Log( Debug.Log(gameObject.transform.position.y + " : " + time));
time = 0.0f;
}
}
}
public static KeyCode SpacebarKey() {
if (Application.isEditor) return KeyCode.O;
else return KeyCode.Space;
}
}
The problem is that FixedUpdate and Update are not called one after the other. Update is called once per frame and FixedUpdate is called once per physics update (default is 50 updates per second).
So the following could happen:
Update is called -> GetKeyDown is true (this frame only) -> isJumpPressed = true
Update is called -> GetKeyDown is false -> isJumpPressed = false
FixedUpdate is called -> isJumpPressed is false
Here is an example that prints "Update Jump" every time you press space, and "FixedUpdate Jump" only sometimes when you press space. Do not do this:
bool isJumpPressed;
void Update()
{
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
if (isJumpPressed)
{
Debug.Log("Update Jump");
}
}
private void FixedUpdate()
{
if (isJumpPressed)
{
Debug.Log("FixedUpdate Jump");
}
}
Do this instead:
bool isJumpPressed;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
isJumpPressed = true;
Debug.Log("Update Jump");
}
}
private void FixedUpdate()
{
if (isJumpPressed)
{
Debug.Log("FixedUpdate Jump");
isJumpPressed = false;
}
}
One possible problem is that your project might be using the new Input System package. If you are using this package, the old Input Manager functions will not work. To check this, go to Edit > Project Settings... > Player > Other Settings and Active Input Handling should be set to Input Manager (Old) (or Both might also work).
If you actually want to use the Input System package, you have to install it if you don't already have it, and you would check if the spacebar is pressed like so:
using UnityEngine.InputSystem;
...
jumpPressed = Keyboard.current.space.wasPressedThisFrame;
I had the same issue. Spend some hours trying to figure out.
Maybe all was good from the beginning until I figured out.
When you I executed the play to see the result and test the movement, by mistake I chose the scene tab. If I want to see the result (to play) I must click the "Game Tab". In Game Tab the keys were detected.enter image description here

How can I successfully store and load data from a game character?

I was wrote a script that combines whale characters to create a new character. However, it is difficult to save and load data from a list of names, levels and locations of the newly created characters.
Whale data does not seem to be stored and loaded when the game is played.
I'd really thanks it if you could tell me where's wrong.
using system;
using System.Collections;
using System.Collections.General;
using system.IO;
using LitJson;
using UnityEngine;
using Random = UnityEngine.Random;
[System.Serializable]
Public class WhaleData
{
Public in dataLevel{get; set;// whale level
public Vector3 dataMousePosition{get; set;//the whale location
public string dataName{get; set;} //whale name
}
Public class Whale: MonoBehaviour
{
public int level;
Private pool isDrag;
Public GameObject NextPrepab;
Private Vector3 mousePosition;
Public WhaleData whaleData;
Private List[WhaleData] WhaleDatas = new List[WhaleData]();
private pool IsSave; //bool value to check for stored data
void start()
{
IsSave = PlayerPrefs.HasKey ("0_name"); //saved_level Check if a key value named //saved_level exists
//initialize all data values if no save data exists
If (!IsSave)
{
Debug.Log ("No data stored).");
PlayerPrefs.DeleteAll();
}
//recall value if save data exists
else
{
Debug.Log ("Stored Data").");
LoadData();
}
}
Private void Update ()
{
SaveData();
LoadData();
}
private void onMouseDown()
{
isDrag = true;
}
private void OnMouseDrag()
{
if (isDrag)
{
mousePosition.x = Input.mousePosition.x;
mousePosition.y = input.mousePositionY;
mousePosition.z = 10;
//change the mouse coordinates to the screen to world and set the position of this object
gameObject.transform.position = Camera.main.ScreenToWorldPoint(mousePosition);
// store the location of the whale in the whalData.dataMousePosition= gameObject.transform.position; //
}
}
private void onMouseUp()
{
//OverlapSphere : Return from the specified location to the collider array in contact within range
var colliders = Physics.OverlapSphere (transform.position, 0.1f);
foreach (var col in colliders) // arrangement of surrounding contacts
{
If (name!= col. gameObject.name) //if the name is different, go
{
If (level==col.gameObject.GetComponent[Whale>().level) //If the level of contact with the level stored in me is the same,
{
whatData.dataLevel = col.gameObject.GetComponent[Whale>().level; // store the level of the whale in the whalData class
var newWhale = Instantiate(NextPrepab, transform.position, quaternion.identity);
newWhale.name = Random.Range (0f, 200f).ToString(); //name is random.
dateData.dataName = name;// store the name of the whale in the whalData class
SaveData();
print(col.gameObject.name);
print(gameObject.name);
whatDatas.Add(whaleData);
Destroy (col.gameObject);
Destroy (gameObject);
// delete if there is any whale information with the same name as Whale's name that will disappear from the dateDatas list (use a simple calculation expression of the unknown method)
if (whaleDatas.Find(whaleData=>whaleData.dataName=colgameObject.GetComponent[Whale>(.name).dataName==colgameObject.GetComponent[Whale>(.name)
{
whaleDatasRemove (col.gameObject.GetComponent[Whale>(whaleData));
Destroy (col.gameObject);
Destroy (gameObject);
}
else
{
break;
}
break;
}
}
}
isDrag = false;
}
Public static void setVector3 (string key, Vector3 value)
{
PlayerPrefs.SetFloat (key + "X", value.x);
PlayerPrefs.SetFloat (key + "Y", value.y);
PlayerPrefs.SetFloat (key + "Z", value.z);
}
Public static Vector3 GetVector3 (string key)
{
Vector3 v3 = Vector3.zero;
v3.x = PlayerPrefs.GetFloat (key + "X");
v3.y = PlayerPrefs.GetFloat (key + "Y");
v3.z = PlayerPrefs.GetFloat (key + "Z");
return v3;
}
private void saveData()
{
for (int i=0; i <whaleDatas.Count; i++)
{
PlayerPrefs.SetString(i+"_name",whaleDatas[i‐dataName));
PlayerPrefs.SetInt(i+"_level",whaleDatas[i‐dataLevel));
Vector3 value = whatDatas[i].dataMousePosition;
string key = i + "_position";
SetVector3 (key,value);
PlayerPrefs.Save();
Debug.Log ("Saved");
}
}
private void LoadData()
{
for(int i=0; i <whaleDatas.Count; i++)
{
whaleDatas[i].dataName = PlayerPrefs.GetString(i+"_name");
whaleDatas[i].dataLevel = PlayerPrefs.GetInt(i+"_level");
string key = i + "_position";
whaleDatas[i].dataMousePosition = GetVector3(key);
}
}
}
Your code is actually broken in term of design.
First PlayerPref doesnt support boolean save by default.
IsSave = PlayerPrefs.HasKey //this will always return false.
thats why everytime you start the game all your saved data is deleted.
You can try this work around to save and load a boolean type How to save bool to PlayerPrefs Unity
Now, How on earth you decided to save and load data at update function?! , this is terrible and has huge performance cost if your data is huge. you just cant do it this way.
Instead, try to make events that store the data and load it instead, like once player enter a trigger box , the data is saved, and ofcourse you dont need to reload it if its saved , bec why you would have to load the data after its being saved?!!
Once again, dont read and write at Update Function like this all the time, this is bad design .

"AudioClip " does not take a constructor that takes 0 arguments

on this line, which is line 10 it says "AudioClip" does not take a constructor that takes 0 arguments. How to fix it? I know that AudioClip is a default class in Unity. What parameters shall I pass there or how to solve this issue?
AudioClip _clipRecord = new AudioClip()
int _sampleWindow = 128;
How to solve it?
public class MicInput : MonoBehaviour {
public static float MicLoudness;
private string _device;
//mic initialization
void InitMic(){
if(_device == null) _device = Microphone.devices[0];
_clipRecord = Microphone.Start(_device, true, 999, 44100);
}
void StopMicrophone()
{
Microphone.End(_device);
}
AudioClip _clipRecord = new AudioClip();
int _sampleWindow = 128;
//get data from microphone into audioclip
float LevelMax()
{
float levelMax = 0;
float[] waveData = new float[_sampleWindow];
int micPosition = Microphone.GetPosition(null)-(_sampleWindow+1); // null means the first microphone
if (micPosition < 0) return 0;
_clipRecord.GetData(waveData, micPosition);
// Getting a peak on the last 128 samples
for (int i = 0; i < _sampleWindow; i++) {
float wavePeak = waveData[i] * waveData[i];
if (levelMax < wavePeak) {
levelMax = wavePeak;
}
}
return levelMax;
}
void Update()
{
// levelMax equals to the highest normalized value power 2, a small number because < 1
// pass the value to a static var so we can access it from anywhere
MicLoudness = LevelMax ();
}
bool _isInitialized;
// start mic when scene starts
void OnEnable()
{
InitMic();
_isInitialized=true;
}
//stop mic when loading a new level or quit application
void OnDisable()
{
StopMicrophone();
}
void OnDestroy()
{
StopMicrophone();
}
// make sure the mic gets started & stopped when application gets focused
void OnApplicationFocus(bool focus) {
if (focus)
{
//Debug.Log("Focus");
if(!_isInitialized){
//Debug.Log("Init Mic");
InitMic();
_isInitialized=true;
}
}
if (!focus)
{
//Debug.Log("Pause");
StopMicrophone();
//Debug.Log("Stop Mic");
_isInitialized=false;
}
}
}
on this line, which is line 10 it says "AudioClip " does not take a constructor that takes 0 arguments. How to fix it?
----AudioClip _clipRecord = new AudioClip()----
---int _sampleWindow = 128;----
How to solve it?
In the AudioClip class add the following:
public AudioClip(){}
This issue arises because although you do initially get an empty ctor when you create a class, you lose that once you create a non-empty ctor so you MUST add the empty one if you wish to use it.
In the new unity version just change new AudioClip();
with
AudioClip _clipRecord = null;
Hope it helps

Error CS0029: Cannot implicitly convert type `UnityEngine.GameObject[]' to `UnityEngine.GameObject'

I get the error on:
lad = GameObject.FindGameObjectsWithTag ("Ladder");
I'm just trying to disable all the ladders in the scene while the alarm is on and then enable them again once the alarm goes away. I'm not sure what the error means but need it fixed as soon as possible. I'm using C# and Unity 5. Thanks for any help you guys can provide!
using UnityEngine;
using System.Collections;
public class LevelAlarm : MonoBehaviour {
public bool alarmOn = false;
public bool bPlayerHidden = false;
// How long an alarm lasts for
[SerializeField]
private float alarmTimer = 5.0f;
private float alarmCurrentTimer = 0.0f;
public GameObject lad;
// Use this for initialization
void Start ()
{
lad = GameObject.FindGameObjectsWithTag ("Ladder");
}
// Update is called once per frame
void Update ()
{
// While alarm is on, run a timer
if (alarmOn)
{
alarmCurrentTimer += Time.deltaTime;
lad.SetActive(false);
// Timer is complete, alarm resets
if(alarmCurrentTimer >= alarmTimer)
{
alarmOn = false;
alarmCurrentTimer = 0.0f;
lad.SetActive(true);
}
}
}
}
GameObject.FindGameObjectsWithTag() returns an array of GameObjects, if you want first object of this array, use this:
void Start ()
{
var objects = GameObject.FindGameObjectsWithTag ("Ladder");
if(objects != null && objects.Length > 0)
{
lad = objects[0];
}
}
It's GameObject.FindGameObjectWithTag, not GameObject.FindGameObjectsWithTag, don't has character "s" after "Object".
Error CS0029: Cannot implicitly convert type UnityEngine.GameObject[]' toUnityEngine.GameObject'
This error simply means that you try to stop alarm whose tag are "Ladder".It creates an array and the function you use accept only one element of utilityEngine.GameObject. So you may use foreach loop to access all elements in the array by using :
public bool alarmOn = false;
public bool bPlayerHidden = false;
// How long an alarm lasts for
[SerializeField]
private float alarmTimer = 5.0f;
private float alarmCurrentTimer = 0.0f;
**public GameObject[] lad;**
// Use this for initialization
void Start ()
{
lad = GameObject.FindGameObjectsWithTag ("Ladder");
}
// Update is called once per frame
void Update ()
{
// While alarm is on, run a timer
if (alarmOn)
{
alarmCurrentTimer += Time.deltaTime;
**foreach(var eachLad in lad)
{
eachLad.SetActive(false);
}**
// Timer is complete, alarm resets
if(alarmCurrentTimer >= alarmTimer)
{
alarmOn = false;
alarmCurrentTimer = 0.0f;
**foreach(var eachLad in lad)
{
eachLad.SetActive(true);
}**
}
}
}

Categories