so i created a score that counts the player movment
using UnityEngine;
using UnityEngine.UI;
public class score : MonoBehaviour
{
public Transform player;
public Text scoreText;
void Update()
{
scoreText.text = player.position.z.ToString("0");
}
}
which works fine but when i tried to create a highscore system that save score and display it it just shows zero and doesnot get updated
enter using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HighScore : MonoBehaviour
{
public Text Score;
public Text highscore;
float highScore=0f;
public Transform player;
void Update()
{
Score.text = highScore.ToString();
if(PlayerPrefs.GetFloat("Score",0)<=highScore)
{
PlayerPrefs.GetFloat("score", highScore);
highscore.text = PlayerPrefs.GetFloat("score").ToString();
}
}
public void highnumber()
{
highscore.text = PlayerPrefs.GetFloat("score").ToString();
}
public static class HighScore
{
public Text Score;
public Text highscore;
float highScore=0f;
public Transform player;
void Update()
{
Score.text = highScore.ToString();
//care here, "score" and "Score" it's not the same
if(PlayerPrefs.GetFloat("score",0)<=highScore)
{
//HERE YOU DONT WANT TO GetFloat, YOU WANT TO SET FLOAT
//PlayerPrefs.GetFloat("score", highScore); we remove this lane
PlayerPrefs.SetFloat("score", highScore); //we add this instead
highscore.text = PlayerPrefs.GetFloat("score").ToString();
}
}
public void highnumber()
{
highscore.text = PlayerPrefs.GetFloat("score").ToString();
}
}
Think about set a var with PlayerPrefs.GetFloat("score"), instead of call GetFloat each time. It's more efficient.
Also I doubt, or at least i think you shouln't to have this Script attached to a gameObject... so remove the MonoBehaviour inheritance from HighScore class, and make it static. Cause u only want a highScore instance true? If you have any doubts about how to do it, and you're interested, just tell me.
EDIT:
Well as you said you need a script monobehaviour to control the text, okay. Lets imagine this 2 classes so:
public static class Stats
{
private static float _highScore; //your highscore it's here
private static int _maxHp, _hp; //some example values
//...someMoreValues
private static float _savedScore //this data gets the last score from PlayerPrefs
private static bool _initialized; //this var is used to know if playerPref data is loaded
//Calling this you always update your highscore
public static void GetHighScore()
{
_InitializeScores();
return _highScore;
}
//this calls playerprefs to save the highscore
public static void SaveHighScore(){
if(_savedScore < _highScore) //only if it's bigger than previuos one
{
_savedScore = _highScore; //we also update the savedscore we had from PlayerPrefs initialization
PlayerPrefs.SetFloat("score", _highScore);
}
}
//this loads your playerprefs values the 1st time it's called
private static void _InitializeScores()
{
if (!_initialized) //if not initialized
{
_initialized = true;
_savedScore= PlayerPrefs.GetFloat("score", 0f);
_highScore = _savedScore
//here you can add all the vars in a future you could recover from PlayerPrefs;
}
}
}
this 1st class manages your highscore, and after at the text you have this other one:
public class HighScoreTextController : MonoBehaviour
{
//here you drag'n'drop your text script as always
public Text score;
// Start is called before the first frame update
// Update is called once per frame
void Update()
{
score.text = Stats.GetHighScore().ToString();
}
}
As you see, at update you call Stats.highScore.ToString(). You don't need to create a var with an instance of it like
Stats stats = new Stats();
Because Stats is static (no instances, only one for all the game). GetHighScore takes care of call PlayerPrefs the 1st time you need to show the highScore and gives you it all the time you need.
When you want to save your highScore, for example when the game ends, you just call
Stats.SaveHighScore();
And only if the score is bigger, it is saved... Calling PlayerPrefs, only one time to get the data, and only one time to save it if necesary.
And why we want to use 2 scripts instead of 1?
Well, because you don't know yet, but maybe in a future you will need to get your highScore from other site... And elsewhere, you only need to call to Stats.GetHighScore(), because it's static. And maybe in a future you would need to use PlayerPrefs for other values... well you can initialize all at same time at your stats and use them whenever u wish.
Best Wishes
Related
I am recently new to c# and I need some help.
Essentially I have two scripts, one for spawning objects and one for moving an object along a path. I need a way to combine these two mechanics so that when a new object is instantiated it automatically joins the path and follows it.
The path is made using iTween.
![The objects the scripts are attached to] (https://i.stack.imgur.com/QPQn2.png)
I've tried changing the variable m_PlayerObj to the cube prefab and I've tried adding the Path script to the instantiation script but nothing seems to work.
The scripts attached do nkt include these attempts I made as I wanted to make the code very clear.
Spawner script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnerScript : MonoBehaviour
{
public GameObject cubeprefab;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(cubeprefab, transform.position, Quaternion.identity);
}
}
}
Path script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Path : MonoBehaviour
{
public GameObject m_PlayerObj;
public Transform[] positionPoint;
[Range(0, 1)]
public float value;
// Start is called before the first frame update
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
float tempTime;
// Update is called once per frame
void Update()
{
if (value < 1)
{
value += Time.deltaTime / 10;
}
iTween.PutOnPath(m_PlayerObj, positionPoint, value);
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
As stated above, any help would be greatly appreciated as I am really stuck on this conceot and since I am new to Unity I really can’t see a way around it // how to fix it.
Instead of only storing the player object in the Path script, store a collection of objects. That way, the path can keep track of more than one object.
//public GameObject m_PlayerObj; // Get rid of this
public List<GameObject> followers; // Add this
Then, in your Update loop, you can loop through all of them.
void Update()
{
for (var i = 0; i < followers.Length; ++i)
{
if (value < 1)
{
value += Time.deltaTime / 10;
}
iTween.PutOnPath(m_PlayerObj, positionPoint, value);
}
}
Of course, now, you need to make sure you pass your cube instance to the Path GameObject when you spawn it, so the path knows about the cube follower. That means your spawner also needs to know about the path.
public class SpawnerScript : MonoBehaviour
{
public GameObject cubeprefab;
public Path path; // Need to populate this in the Editor, or fetch it during Awake()
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
var cubeInst = Instantiate(cubeprefab, transform.position, Quaternion.identity);
path.followers.Add(cubeInst);
}
}
}
Now a new problem is going to be that each object is going to be at the same position on the path, because the path only stores one value - a better term might be progress. So if they're all the same, like the cube, you won't be able to tell because they'd overlap.
So you have to decide what you want to do instead. Evenly space them? You could do that with some math. Or have them all start from the beginning and keep track of their progress separately? Then you'd need to store progress for each of them. A better place to do that is probably on the cube object, which means you need to add a new script to your cube prefab:
public class PathFollower : MonoBehaviour
{
[Range(0, 1)]
public float pathProgress;
}
And, you need to start referring to the prefab by this script, instead of just GameObject:
public class SpawnerScript : MonoBehaviour
{
public PathFollower pathFollower;
public Path path; // Need to populate this in the Editor, or fetch it during Awake()
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
var followerInst = Instantiate(pathFollower, transform.position, Quaternion.identity);
path.followers.Add(followerInst);
}
}
}
public class Path : MonoBehaviour
{
//public GameObject m_PlayerObj; // Get rid of this
public List<PathFollower> followers; // Add this
//...
Finally, you need to make sure to use the individual progress for each path follower, rather than a single progress value like your old Path script did:
for (var i = 0; i < followers.Count; ++i)
{
if (followers[i].pathProgress < 1)
{
followers[i].pathProgress += Time.deltaTime / 10;
}
iTween.PutOnPath(followers[i].gameObject, positionPoint, followers[i].pathProgress);
}
Putting it all together (separate files of course, with their own includes!):
public class SpawnerScript : MonoBehaviour
{
public PathFollower pathFollower;
public Path path; // Need to populate this in the Editor, or fetch it during Awake()
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
var followerInst = Instantiate(pathFollower, transform.position, Quaternion.identity);
path.followers.Add(followerInst);
}
}
}
public class Path : MonoBehaviour
{
//public GameObject m_PlayerObj; // Get rid of this
public List<PathFollower> followers; // Add this
public Transform[] positionPoint;
//[Range(0, 1)]
//public float value; // Don't need this anymore either
// Start is called before the first frame update
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
// Update is called once per frame
void Update()
{
for (var i = 0; i < followers.Count; ++i)
{
if (followers[i].pathProgress < 1)
{
followers[i].pathProgress += Time.deltaTime / 10;
}
iTween.PutOnPath(followers[i].gameObject, positionPoint, followers[i].pathProgress);
}
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
public class PathFollower : MonoBehaviour
{
[Range(0, 1)]
public float pathProgress;
}
For some reason I need to start the scene with the menu open, then close it, then grab the coin and go to the shop menu in order for the shop ui to update my moneyAmount. If i start the scene with the shop menu closed and pick up the coin then go to my shop menu it doesnt update. And when i buy my helmet it says reference not set to an object even though all im doing is getting my player health component and adding 50 to it so why do i need to reference any kind of object? here are the scripts with my GameControl script first.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameControl : MonoBehaviour
{
public Text moneyText;
public static int moneyAmount;
int isHelmetSold;
int isBeltSold;
int isPantsSold;
int isShirtSold;
int isBootsSold;
// Start is called before the first frame update
void Start()
{
moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
isHelmetSold = PlayerPrefs.GetInt("IsHelmetSold");
isBeltSold = PlayerPrefs.GetInt("IsBeltSold");
isPantsSold = PlayerPrefs.GetInt("IsPantsSold");
isShirtSold = PlayerPrefs.GetInt("IsShirtSold");
isBootsSold = PlayerPrefs.GetInt("IsBootsSold");
}
// Update is called once per frame
void Update()
{
moneyText.text = moneyAmount.ToString();
}
Here is my PageOneShop script which makes my item buyable when amount is reached (for the time being ive only finished my helmet not the rest so if you can ignore all of the public texts and buttons as i know i havent added them yet)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PageOneShop : MonoBehaviour
{
public static int moneyAmount;
int isHelmetSold;
int isBeltSold;
int isPantsSold;
int isShirtSold;
int isBootsSold;
public Text moneyText;
public Text helmetPrice;
public Text beltPrice;
public Text pantsPrice;
public Text shirtPrice;
public Text bootsPrice;
public Button buyHelmetButton;
public Button buyBeltButton;
public Button buyPantsButton;
public Button buyShirtButton;
public Button buyBootsButton;
void Start()
{
moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
isHelmetSold = PlayerPrefs.GetInt("IsHelmetSold");
isBeltSold = PlayerPrefs.GetInt("IsBeltSold");
isPantsSold = PlayerPrefs.GetInt("IsPantsSold");
isShirtSold = PlayerPrefs.GetInt("IsShirtSold");
isBootsSold = PlayerPrefs.GetInt("IsBootsSold");
}
// Update is called once per frame
void FixedUpdate()
{
moneyText.text = moneyAmount.ToString();
isHelmetSold = PlayerPrefs.GetInt("IsHelmetSold");
if (moneyAmount >= 150 && isHelmetSold == 0)
buyHelmetButton.interactable = true;
else
buyHelmetButton.interactable = false;
isBeltSold = PlayerPrefs.GetInt("IsBeltSold");
if (moneyAmount >= 120 && isBeltSold == 0)
buyBeltButton.interactable = true;
else
buyBeltButton.interactable = false;
isPantsSold = PlayerPrefs.GetInt("IsPantsSold");
if (moneyAmount >= 100 && isPantsSold == 0)
buyPantsButton.interactable = true;
else
buyPantsButton.interactable = false;
isShirtSold = PlayerPrefs.GetInt("IsShirtSold");
if (moneyAmount >= 100 && isShirtSold == 0)
buyShirtButton.interactable = true;
else
buyShirtButton.interactable = false;
isBootsSold = PlayerPrefs.GetInt("IsBootsSold");
if (moneyAmount >= 80 && isBootsSold == 0)
buyBootsButton.interactable = true;
else
buyBootsButton.interactable = false;
}
public void buyHelmet()
{
moneyAmount -= 150;
GetComponent<PlayerHealth>().maxHealth += 50;
PlayerPrefs.SetInt("IsHelmetSold", 1);
helmetPrice.text = "Sold!";
buyHelmetButton.gameObject.SetActive(false);
}
public void buyBelt()
{
moneyAmount -= 120;
GetComponent<PlayerHealth>().maxHealth += 50;
PlayerPrefs.SetInt("IsBeltSold", 1);
helmetPrice.text = "Sold!";
buyBeltButton.gameObject.SetActive(false);
}
public void buyShirt()
{
moneyAmount -= 100;
GetComponent<PlayerHealth>().maxHealth += 50;
PlayerPrefs.SetInt("IsShirtSold", 1);
helmetPrice.text = "Sold!";
buyShirtButton.gameObject.SetActive(false);
}
public void buyPants()
{
moneyAmount -= 100;
GetComponent<PlayerHealth>().maxHealth += 50;
PlayerPrefs.SetInt("IsPantsSold", 1);
helmetPrice.text = "Sold!";
buyPantsButton.gameObject.SetActive(false);
}
public void buyBoots()
{
moneyAmount -= 80;
GetComponent<PlayerHealth>().maxHealth += 50;
PlayerPrefs.SetInt("IsBootsSold", 1);
helmetPrice.text = "Sold!";
buyBootsButton.gameObject.SetActive(false);
}
And here is my coin script on my coins that i pick up.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Coin : MonoBehaviour
{
void OnTriggerEnter2D (Collider2D col)
{
PageOneShop.moneyAmount += 200;
GameControl.moneyAmount += 200;
Destroy(gameObject);
}
It's important to figure out the pieces involved. Starting from the minimum amount of code, I think this is a good start:
"GameControl"
using UnityEngine;
using UnityEngine.UI;
public class GameControl : MonoBehaviour
{
public Text moneyText;
public static int moneyAmount;
// Start is called before the first frame update
// Start is only called while this is active and enabled
void Start()
{
moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
}
void Update()
{
moneyText.text = moneyAmount.ToString();
}
}
"PageOneShop"
using UnityEngine;
using UnityEngine.UI;
public class PageOneShop : MonoBehaviour
{
public static int moneyAmount;
public Text moneyAmountText;
public Text helmetPrice;
// Start is called before the first frame update
// Start is only called while this is active and enabled
void Start()
{
moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
}
// Update is called once per frame
void Update()
{
moneyAmountText.text = moneyAmount.ToString();
}
public void buyHelmet()
{
moneyAmount -= 150;
helmetPrice.text = "Sold!";
}
}
"Coin"
using UnityEngine;
public class Coin : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D col)
{
PageOneShop.moneyAmount += 200;
GameControl.moneyAmount += 200;
Destroy(gameObject);
}
}
Everything in these files is used, and we can replicate our issue. Before this point, my previous answer was correct and you weren't updating the moneyAmount instance inside PageOneShop. Now there is a new issue and it's more subtle, because it's strictly speaking not in your code.
Start is a Unity called method, and is called "before the first frame update". Start is also only called if the component is enabled and the object it's attached to is active. If the object it's attached to is de-activated (like I'm guessing your menu is when you load your scene) Start will be called the first time you activate the object (open the menu). Since nowhere are you updating the "MoneyAmount" in PlayerPrefs, that value is still 0. If you pick up the coin, then open the menu for the first time, the value would be 200 but instead is re-set to 0 when this runs:
void Start()
{
moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
}
Probably the quickest way to fix this is to add this line to coin:
public class Coin : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D col)
{
PageOneShop.moneyAmount += 200;
GameControl.moneyAmount += 200;
// Set the PlayerPrefs value
PlayerPrefs.SetInt("MoneyAmount", GameControl.moneyAmount);
Destroy(gameObject);
}
}
At this point even if the menu opens after the coin is picked up, the correct value is retrieved from PlayerPrefs so nothing is overwritten.
Potentially a new problem has been introduced, which is even in the editor during testing, this write to PlayerPrefs is occurring so money may accumulate as multiple play sessions are run.
There are a few other issues as well. As #derHugo accurately points out you should stop polling for changes in update to an event based approach, and the use of two static variables which are kept in sync like this is at best wasteful, and at worst can cause some real serious headaches.
Let's start by addressing the double static variable use. You could replace all the references of one with the other, but I propose introducing a third class to handle the player's "Wallet" where they keep their money. You could write something as simple as:
public static class Wallet
{
public static int MoneyAmount;
}
All the references to the other two static moneyAmount variables could be replaced with this Wallet.MoneyAmount.
The polling could now be replaced with events pretty quickly by adding an event to the Wallet class, and replacing the field with a property:
using System;
public static class Wallet
{
public static event Action OnMoneyAmountChanged;
private static int moneyAmount;
public static int MoneyAmount
{
get
{
return moneyAmount;
}
set
{
moneyAmount = value;
// maybe null check, or follow a "never null" approach
OnMoneyAmountChanged();
}
}
}
Instead of always checking moneyAmount you can now add some code like:
void Start()
{
// Listen for changes
Wallet.OnMoneyAmountChanged += handleMoneyAmountChanged;
}
private void OnDestroy()
{
// Remember to always remove your listeners when you're done with them
Wallet.OnMoneyAmountChanged -= handleMoneyAmountChanged;
}
// set the text to the value held in the wallet whenever the amount changes
void handleMoneyAmountChanged()
{
moneyText.text = Wallet.MoneyAmount.ToString();
}
Maybe you don't want the PlayerPrefs.SetInt call in Coin any more, and instead you could move it into the Wallet now. If you put it in a [Conditional] method you could also protect yourself from constantly overwriting PlayerPrefs with every play session in the editor.
using System;
using System.Diagnostics;
using UnityEngine;
public static class Wallet
{
public static event Action OnMoneyAmountChanged;
private static readonly string moneyAmountKey = "MoneyAmount";
private static int moneyAmount;
public static int MoneyAmount
{
get
{
return moneyAmount;
}
set
{
moneyAmount = value;
OnMoneyAmountChanged();
// this method call is conditional on a defined constant
saveMoneyAmount();
}
}
// This part will only run if ENABLE_PLAYERSPREFS is defined.
[Conditional("ENABLE_PLAYERPREFS")]
private static void saveMoneyAmount()
{
PlayerPrefs.SetInt(moneyAmountKey, moneyAmount);
}
}
You can type whatever you want into the scripting define symbols text box described in the "Platform custom #defines" section on this page. If you define "ENABLE_PLAYERPREFS" that method will call.
You probably now want to initialize your wallet as well, and to keep things symmetrical you could "close" it as well. This would let you cut down on a lot of reads and writes to player prefs.
public static void Open()
{
// this is another way to interact with platform define constants
#if ENABLE_PLAYERPREFS
moneyAmount = PlayerPrefs.GetInt(moneyAmountKey);
#else
moneyAmount = 0;
#endif
}
public static void Close()
{
// maybe you want to do other stuff in here
saveMoneyAmount();
}
If you called Open at the start of your application, and Close at the end you could just use the variables in memory the rest of the time and remove the saveMoneyAmount call from the MoneyAmount setter.
As for this second question you added later than my original answer, "And when i buy my helmet it says reference not set to an object even though all im doing is getting my player health component and adding 50 to it so why do i need to reference any kind of object?". You didn't post the line number, but I can guess that it originates on any/all the calls that look like this GetComponent<PlayerHealth>().maxHealth += 50; since those are all in methods on PageOneShop so unless you've added your PlayerHealth component to your menu object that GetComponent will be null, at which point you can refer to What is a NullReferenceException, and how do I fix it?
I want to have a singleton which will store, update and show player score through all levels (scenes), but something works wrong.
This my singletone script GameStatus.cs:
using UnityEngine;
using TMPro;
public class GameStatus : MonoBehaviour
{
public static GameStatus instance;
[SerializeField] int pointsPerBlock = 50;
[SerializeField] TextMeshProUGUI scoreText;
[SerializeField] public static int currentScore = 0;
private void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
public void AddToScore()
{
currentScore += pointsPerBlock;
scoreText.text = currentScore.ToString();
}
}
I also have another script for objects player need to destroy, called Block.cs. Here it is:
using UnityEngine;
public class Block : MonoBehaviour
{
Level level;
GameStatus gameStatus;
private void Start()
{
level = FindObjectOfType<Level>();
gameStatus = FindObjectOfType<GameStatus>();
level.CountBreakableBlocks();
}
private void OnCollisionEnter2D(Collision2D collision)
{
DestroyBlock();
}
private void DestroyBlock()
{
level.BlockDestroyed();
gameStatus.AddToScore();
Destroy(gameObject);
}
}
And on level 1 everything works fine, but when the game goes to the next level this happens:
Player score stops updating.
If I use Debug.Log(currentScore); in GameStatus.cs I can see that this variable doesn't change when player breaks blocks, but if use Debug.Log(gameStatus.currentScore); in Block.cs then I can see that this variable is getting updated.
Debug.Log(FindObjectsOfType().Length); shows that there is one GameStatus object in the first level and two objects in the next levels, although I can't see the second one GameStatus in hierarchy.
So my question is - what's wrong and how to fix it?
If you use singleton, there is no point to make
currentScore
static variable, just make it
public int currentScore;
Also in your block cs you can just call
GameStatus.instance.AddToScore();
No need to make reference at start
I have a number of Prefabs stored in an array and instantiate one at a time by clicking a button. The object appears but is always inactive.
I've searched for hours for an answer and tried a lot but the problem stays the same. I hope it's ok to ask, even though there are several similar questions but none of the answers solves my problem.
Like I've already described, I want to instantiate a GameObject from an array per button click and the object indeed appears but when I try to start a coroutine on it(if that's helpful, it's an IEnumerator that shall let the Object fade out by handling it's colours alpha channel), I always get an error that says the GameObject is inactive. I'm not able to set it active by writing myPrefab.gameObject.SetActive(true) and I've tried to call it at several places in my code. It always stays inactive. Has anybody any idea what might be the problem?
public class Class1 : MonoBehaviour
{
[SerializeField]
private MyClass[] myPrefabs;
private MyClass myCurrentPrefab;
private int myIndex;
public void ButtonEffect()
{
InstantiatePrefab();
myCurrentPrefab.OnButtonEffect();
}
private void InstantiatePrefab()
{
myIndex = Random.Range(0, myPrefabs.Length);
myCurrentPrefab = myPrefabs[myIndex];
Instantiate(myCurrentPrefab);
}
}
public class MyClass : MonoBehaviour
{
private SpriteRenderer mySprite;
private void Start()
{
mySprite = GetComponent<SpriteRenderer>();
}
private void Awake()
{
this.gameObject.SetActive(true)
}
private void OnButtonEffect()
{
StartCoroutine(FadeOut(mySprite, 3));
}
public IEnumerator FadeOut(SpriteRenderer spriteToFade, float duration)
{
//DoFadeOutStuff
}
}
Here I've tried to set the object active in the Awake function of its own code but I've also tried it in the both functions of Class1 and its Start function. I've also tried to handle it for the whole array in an foreach loop. Always the same result. All I want to do is to set it active, right now I don't even care if my fade out stuff works correctly. First I thought it was because my instantiated object is a clone but I can't find anything about it, so even if the solution is pretty obvious, please help!
The problem is that you're referencing the actual prefab itself, which isn't actually active in the scene. You need to create a gameobject and set its value to the instantiated prefab. The following should work
using UnityEngine;
public class Class1 : MonoBehaviour
{
[SerializeField]
private GameObject[] myPrefabs;
public void ButtonEffect()
{
var go = InstantiatedPrefab();
go.GetComponent<MyClass>().OnButtonEffect();
}
private GameObject InstantiatedPrefab()
{
var index = Random.Range(0, myPrefabs.Length);
return Instantiate(myPrefabs[index]);
}
}
using System.Collections;
using UnityEngine;
public class MyClass : MonoBehaviour
{
private SpriteRenderer mySprite;
private void Start()
{
mySprite = GetComponent<SpriteRenderer>();
}
public void OnButtonEffect()
{
StartCoroutine(FadeOut(mySprite, 3));
}
private IEnumerator FadeOut(SpriteRenderer spriteToFade, float duration)
{
print("FadeOut");
yield return 0;
}
}
I have a scene where I write down my player stats. In the next scene (basically in the next 2 scenes but it doesn't matter) I want to buy some weapons and change the variables.
The thing is I'm saving the object with "DontDestroyOnLoad" and when I go to the next scene I want to find out how can I change the variables.
First Scene:
The code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class statsTextsToDisplayAndChanges : MonoBehaviour
{
public static statsTextsToDisplayAndChanges _INstance;
buyWeapons bw;
public Text m_LevelText;
public Text m_AttackText;
public Text m_DefendText;
public Text m_MoneyText;
public int level = 0;
public int money = 500;
public int health = 400;
public int attack = 10;
public int def = 5;
string answer;
string url = "http://alex3685.dx.am/display.php";
public int sword1 = 200;
public void Start()
{
_INstance = this;
DontDestroyOnLoad(this.gameObject);
display();
}
public void display()
{
m_LevelText.text = level.ToString();
m_AttackText.text = attack.ToString();
m_DefendText.text = def.ToString();
m_MoneyText.text = money.ToString();
}
public void onPurchase()
{
if (money >= sword1)
{
Debug.Log("YOU BOUGHT IT");
money -= sword1;
//Destroy(GameObject.Find("playerStats"));
display();
}
}
}
Second scene:
When I press the button the debug.log from the purchase function works but in the text nothing changes (from 500 coins-200 coins of the sword=300 coins).
Any ideas?
Thanks in advance.
Hmmm....initial thoughs:
This is one of the times where you want a true manager object with a scrip attached that only knows how to store the relevant stat.
Then, in whatever scripts that handles the purchasing they have a private GameObject with a reference to the manager object.private GameObject _Manager;
But the object exists in another scene in my editor so I cant drag and drop the reference!
No problem,
Lets say that the object with the component that stores the stats are called "PlayerManager". In the script that handles the purchasing in the start() method add: _Manager = gameobject.Find("PlayerManager");
Now you can change all the variables to your hearts content, assuming of course that you have set the variables in the manager to be public, or if you are more advanced and concerned about robust code, you have the proper get;set; methods in place.
Hope this helped!
Use PlayerPrefs to save and retrieve data.
Source : https://docs.unity3d.com/ScriptReference/PlayerPrefs.html