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
Related
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 am having a "problem" in a game that is being developed. When the character dies from a collision to the enemy, or trigger gameobjects, it displays a game over screen, which contains a "Try Again" button to restart the game, but the score collected from the previous game remains once the restart button is clicked.
How can I solve this problem? Thank you for your help!!
GameOver C# script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class CS_GameOverMenu : MonoBehaviour
{
public void RestartButton()
{
SceneManager.LoadScene("Level 1");
Debug.Log("Game open");
}
public void MenuButton()
{
SceneManager.LoadScene("MainMenu");
Debug.Log("Main Menu open");
}
public void ExitButton()
{
Application.Quit();
Debug.Log("Game closed");
}
//public void QuitButton()
//{
// Application.Quit();
//Debug.Log("Game closed");
}
As you have a static field, this data will persist while the game is still running even after a reset. Inside of your Reset function put code similar to this.
If you would rather not grab the object by name, use this snippet.
public void RestartButton()
{
ScoringSystem.theScore = 0;
SceneManager.LoadScene("Level 1");
Debug.Log("Game open");
}
You just need to set the score back to 0 when reloading the scene as the value you have is marked as static.
You could access the Player Object (or whichever Object holds the score) and simply set the variable to 0 (it has to be public for that).
It would work something like that:
scoreGameObject.getComponent<"ScriptName">().scoreValue = 0
Get the score class/file and reset the score
public void RestartButton()
{
GameObjectWithScoreFile.GetComponent<ScoreClass>().Score = 0; // Make sure the Score var is public
SceneManager.LoadScene("Level 1");
Debug.Log("Game open");
}
if you get an error because the variable is not static just make it static.
example:
public static int Score = 0;
I have created a Scriptable Object with [CreateAssetMenu] option in the editor and it's called 'Assets/MyCard1.asset'. In there, I have specified some values like name, sprite, attack, health etc.
So my goal is to spawn a deck of 30 cards based on the same Prefab, but when I use 'Instantiate(gamobject)', it spawns a gameobject with default Prefab parameters. How do I assign 'Assets/MyCard[i].asset' data to EACH of newly spawned cards (with code)? I can do that with Inspector just fine by dragging Asset to the Prefab's script component.
[CreateAssetMenu(fileName = "New Card", menuName = "Card")]
public class CardScriptable : ScriptableObject
{
public new string name;
public string description;
public Sprite artwork;
public int manaCost;
public int attack;
public int health;
}
public class SpawnStuff : MonoBehaviour
{
public GameObject myPrefab;
GameObject[] tempKarta = new GameObject[30];
void Start()
{
for (int i = 0; i < 30; i++)
{
tempKarta[i] = Instantiate(myPrefab);
temp.Karta[i]. ?? DRAW_DATA_FROM "Assets/MyCard1.asset" (); // ??
}
}
}
Is my approach rational? If not, what is a better approach to this?
UPD:
Here's my presets, and prefab
also script that just displays stuff from CardScriptable
public class CardDisplay : MonoBehaviour
{
public CardScriptable card;
public Text nametext;
public Text descriptionText;
public Image artworkImage;
public Text manaText;
public Text attackText;
public Text healthText;
void Awake()
{
nametext.text = card.name;
descriptionText.text = card.description;
artworkImage.sprite = card.artwork;
}
}
You allready have your structure. All you would need is not do your stuff in Awake but rather have a method for it like
public class CardDisplay : MonoBehaviour
{
public Text nametext;
public Text descriptionText;
public Image artworkImage;
public Text manaText;
public Text attackText;
public Text healthText;
public void Initialize(CardScriptable card)
{
nametext.text = card.name;
descriptionText.text = card.description;
artworkImage.sprite = card.artwork;
}
}
Then have e.g. an array of CardScriptable[] in
public class SpawnStuff : MonoBehaviour
{
// Rather make this of the correct type!
public CardDisplay myPrefab;
private CardDisplay[] tempKarta = new CardDisplay[30];
// Adjust in Inspector
public CardScriptable[] availableCardConfigs;
void Start()
{
for (int i = 0; i < 30; i++)
{
var config = availableCardConfigs[Random.Range(0, availableCardConfigs.Length)];
// If you make the prefab of correct type this already returns a CardDisplay
tempKarta[i] = Instantiate(myPrefab);
tempKarta[i].Initialize(config);
}
}
}
After a few more details were added I think I have a handle on the issue.
You can create another ScriptableObject class which is used as a collection to avoid any external file issues which you may be having eg
Public class Deck : ScriptableObject {
Public CardScriptable[] cards;
}
ScriptableObjects can have methods of their own. The typical method I use in this situation is to make a method on your script able object to instantiate the cards and assign values there as opposed to instantiating the cards that way.
Edit: possible misinterpretation on my part, if the problem is you cannot easily change the text/sprites etc. I would make a handler class to put on your card prefab which holds references to where you need once instantiated.
That way you can use for eg GetComponent().sprite = newSprite;
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
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;
}
}