Music is not getting stop when scene reload in unity - c#

I am using a toggle button to play and stop music and I am using playerPrefs to save the state. Toggle button is playing or stopping the music but when I reload the scene It gets messed up. Music keeps playing even if the toggle button is on(Means set the music off).
For the player Prefs. I am using Player prefs Manager script:
public static void SetMusicOnOFF(int value)
{
PlayerPrefs.SetInt(Music, value);
}
public static int GetMusicOnOff()
{
return PlayerPrefs.GetInt(Music, 5);
}
For the toggle button I am using:
class MusicToggleButton : MonoBehaviour
{
Toggle t;
// Use this for initialization
void Start ()
{
t = GetComponent<Toggle>();
if (PlayerPrefsManager.GetMusicOnOff() == 1)
{ //ERROR CALLING THE METHOD TO CHANGE MUSIC TO ON
t.isOn = true;
}
}
When the toggle button is pressed I am calling StartStopMusicPlayer method:
class MusicPlayer : MonoBehaviour
{
public static bool stopPlayer;
// Use this for initialization
void Awake ()
{
if (PlayerPrefsManager.GetMusicOnOff() == 2)
{
audioSource.Play();
audioSource.playOnAwake = true;
audioSource.loop = true;
}
else
{
audioSource.Stop();
}
}
public void StartStopMusicPlayer()
{
stopPlayer = !stopPlayer;
if (stopPlayer)
{
PlayerPrefsManager.SetMusicOnOFF(1);
audioSource.Stop();
}
else
{
PlayerPrefsManager.SetMusicOnOFF(2);
audioSource.Play();
}
}
}
Music Player Class is not destroying on reload. But the MusicToggleButton class is destroyed on reload.
Thank you for your help.

Calling PlayerPrefs.SetInt(Music, value) is not enough. You should call PlayerPrefs.Save() after that. Or your changes will not take effect after restart.
public static void SetMusicOnOFF(int value)
{
PlayerPrefs.SetInt(Music, value);
PlayerPrefs.Save();
}

Solution was so simple. If anyone want to know. Just change the toggle button with normal button. and Inside the MusicToggleButton class.
public class MusicToggleButton : MonoBehaviour
{
public Image offOnImage;
public bool changeValue;
public Color TargetColor;
public Color originalColor;
// Use this for initialization
void Start ()
{
changeValue = !(PlayerPrefsManager.GetMusicOnOff() == 1);
if (PlayerPrefsManager.GetMusicOnOff() == 1)
{
Debug.Log("stop Music");
offOnImage.color = TargetColor;
}
else
{
Debug.Log("Playing Music");
offOnImage.color = originalColor;
}
}
public void musicButtonClick()
{
changeValue = !changeValue;
if (changeValue)
{
//Debug.Log("changing to target color");
//offOnImage.CrossFadeColor(TargetColor, 0.5f, false, false);
offOnImage.color = originalColor;
Debug.Log("Playing");
}
else
{
//Debug.Log("changing to original color");
//offOnImage.CrossFadeColor(Color.white, 0.5f, false, false);
Debug.Log("pause");
offOnImage.color = TargetColor;
}
}
}
This will do Play and pause music. Act like a toggle button.

Related

Instantiate Object Only once on game start Unity 3D

I have a game with several levels, each level has 6 scenes, the game start directly without any menu scene, and when the player open the game he can continue from the last scene that he already reached.
I want to instantiate some elements only on game opening (like Best score, Tap to play etc...), I mean that they should be instantiated only once on the start of the game (on the level he reached).
I tried this code in GameManager but it instantiate the elements in every scene:
public GameObject PlayButton;
bool GameHasEnded = false;
public float RestartDelay = 2f;
public float NextLevelDelay = 5f;
public int level_index;
private static bool loaded = false;
private void Start()
{
if (!loaded)
{
loaded = true;
level_index = PlayerPrefs.GetInt("Last_Level");
SceneManager.LoadScene(level_index);
}
GameObject canvas = GameObject.Find("Canvas");
GameObject play = Instantiate(PlayButton, canvas.transform.position, Quaternion.identity);
play.transform.SetParent(canvas.transform, false);
}
public void CompleteLevel()
{
Invoke("NextLevel", NextLevelDelay);
}
public void EndGame()
{
if (GameHasEnded == false)
{
GameHasEnded = true;
Invoke("Restart", RestartDelay);
}
}
void NextLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex +1);
level_index = SceneManager.GetActiveScene().buildIndex + 1;
PlayerPrefs.SetInt("Last_Level", level_index);
PlayerPrefs.Save();
}
void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().path);
}
You already have an if block there with the static flag loaded
Since you there load another scene you need a similar second flag e.g.
private static bool loadedPrefab = false;
private void Start()
{
if (!loaded)
{
loaded = true;
level_index = PlayerPrefs.GetInt("Last_Level");
SceneManager.LoadScene(level_index);
// Return because you don't want to execute the rest yet
// but instead in the new loaded scene
return;
}
// The same way skip if the prefab was already loaded before
if(!loadedPrefab)
{
loadedPrefab = true;
GameObject canvas = GameObject.Find("Canvas");
GameObject play = Instantiate(PlayButton, canvas.transform.position, Quaternion.identity);
play.transform.SetParent(canvas.transform, false);
}
}

Unity ads not working on real device

In my current Unity program I wanted to implement ads. The ads do work in the Unity editor when I run the game, but when I try to run the ads on my iPhone 7 or iPad Air, there are no ads showing up. Does someone know what I am doing wrong?
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Advertisements;
public class GameManager : MonoBehaviour
{
void Start()
{
Advertisement.Initialize("Appstore-id");
}
bool gameHasEnded = false;
public float restartDelay = 1f;
public float addDelay = 1f;
public GameObject completeLevelUI;
public void CompleteLevel ()
{
completeLevelUI.SetActive(true);
Invoke("ShowAdd", addDelay);
}
public void EndGame()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Debug.Log("Game over");
Invoke("Restart", restartDelay);
}
}
public void ShowAdd()
{
if (Advertisement.IsReady())
{
Advertisement.Show ();
}
}
void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
I had the same problem and the way I fixed it was a recursive function until the ad was ready. Something like:
IEnumerator ShowAd()
{
yield return new waitForSeconds(1);
if (Advertisement.IsReady())
{
Advertisement.Show ();
}
else { StartCoroutine(ShowAd()); }
}
This way it will call the method until the ad is ready to show.
Also, make sure you have test (or debug) mode enabled on Unity Ads Settings.
Just to add another option besides recursively starting an IEnumerator:
IEnumerator ShowAd()
{
while(!Advertisement.isReady())
{
yield return new waitForSeconds(1);
}
Advertisement.Show();
}

Unity PauseMenu doesn't work in second level

I am making a pause menu for my game. In level1 my pause menu works, but in level2 if you press esc it appears but the buttons aren't interactive for some reason. I copied the canvas from level.
public class PauseMenu : MonoBehaviour {
public string levelSelect;
public string mainMenu;
public bool isPaused;
public GameObject pauseMenuCanvas;
void Start (){
}
void Update () {
if(isPaused)
{
pauseMenuCanvas.SetActive(true);
Time.timeScale = 0f;
} else {
pauseMenuCanvas.SetActive(false);
Time.timeScale = 1f;
}
if(Input.GetKeyDown(KeyCode.Escape))
{
isPaused = !isPaused;
}
}
public void Resume()
{
isPaused = false;
}
public void LevelSelect()
{
Application.LoadLevel(levelSelect);
}
public void Quit()
{
Application.LoadLevel(mainMenu);
}
}
You need to add EventSystem
The EventSystem allows you to interact with buttons

Disable instantiate and button click

There is issue that i facing with two objects and one button. One is cube second is ground when we click on button cube is collide with ground destroy and instantiate again. On Cube collision score is decrement.Also in hierarchy there is Empty game object which name is controller which has method of text score.Score is working fine but i want that when score is 0 then button click does not work and cube is not instantiate.
Cube :
Ground :
Controller :
CubeScript:
public class Cube : MonoBehaviour {
Rigidbody2D body;
void Start () {
body = GetComponent<Rigidbody2D>();
body.isKinematic = true;
}
}
Ground Script:
public class Ground : MonoBehaviour {
private Button button;
private BoxCollider2D collide;
public GameObject object1Clone;
void Start () {
collide = GetComponent<BoxCollider2D>();
collide.isTrigger = true;
button = GameObject.FindGameObjectWithTag ("Button").GetComponent<Button> ();
button.onClick.AddListener (() => Magnetic ());
}
void OnTriggerEnter2D(Collider2D target) {
Destroy (target.gameObject);
Instantiate (object1Clone, new Vector3 (0f, 4.12f, 0f), Quaternion.identity);
}
public void Magnetic(){
GameObject.FindGameObjectWithTag ("Player").GetComponent<Rigidbody2D> ().isKinematic = false;
}
}
ScoreScript:
public class ScoreScript : MonoBehaviour {
public static int Score=1;
void OnTriggerEnter2D(Collider2D target) {
if (Score <=0) {
} else {
Score--;
Controller.instance.SetScore(Score);
}
}
}
Controller:
public class Controller : MonoBehaviour {
public static Controller instance;
public Text scoreText;
void Start () {
scoreText.text = ""+1;
if(instance==null){
instance=this;
}
}
public void SetScore(int score){
scoreText.text =""+score;
}
}
First change the listener registration to this:
button.onClick.AddListener (Magnetic);
this will make it easier to remove the listener.
I will show you two ways of doing it, an easy one and a proper one a bit harder to grasp. So if you don't quite get it, use the first and learn about the second.
Every time you decrease the score, check for it and call for the appropriate action:
public class ScoreScript : MonoBehaviour {
public static int Score=1;
void OnTriggerEnter2D(Collider2D target)
{
Score--;
Controller.instance.SetScore(Score);
if(Score <= 0){
GameObject.Find("ground").GetComponent<Ground>().ClearButtonListener();
}
}
}
And in the Ground component:
public void ClearButtonListener()
{
button.onClick.RemoveListener (Magnetic);
}
Now the second more appropriate way would be to use event and listener
public class ScoreScript : MonoBehaviour, IScoreHandler {
public static int Score=1;
public event Action OnScoreZero = () => {};
void OnTriggerEnter2D(Collider2D target)
{
Score--;
Controller.instance.SetScore(Score);
if(Score <= 0){
OnScoreZero();
}
}
}
public interface IScoreHandler{ event Action OnScoreZero; }
And your listeners listens.
public class Ground : MonoBehaviour {
private Button button;
private BoxCollider2D collide;
public GameObject object1Clone;
private IScoreHandler scoreHandler = null;
void Start () {
scoreHandler = GameObject.Find("Score").GetComponent<IScoreHandler>();
if(scoreHandler != null){
scoreHandler.OnScoreZero += ClearButtonListener;
}
collide = GetComponent<BoxCollider2D>();
collide.isTrigger = true;
button = GameObject.FindGameObjectWithTag ("Button").GetComponent<Button> ();
button.onClick.AddListener (Magnetic);
}
void OnDestroy(){
if(scoreHandler != null){
scoreHandler.OnScoreZero -= ClearButtonListener;
}
}
}
Thanks to interface and event, your class is no more relying on another class but on an interface which makes it more flexible and scalable.
You need to set the field interactable of the UnityEngine.UI.Button object to false, see http://docs.unity3d.com/ScriptReference/UI.Button.html, i.e. use
void OnTriggerEnter2D(Collider2D target) {
if (Score <=0) {
/* disable the button */
GameObject.FindGameObjectWithTag ("Button").GetComponent<Button>().interactable = false;
}
in your ScoreScript.cs.

How to get animation to play multiple times in Unity?

I want to get a sprite to play an animation of a drop of liquid falling every time that it is clicked, however the animation only plays the first time I click it and I have no idea why.
Here is the code used on the sprite:
public class PipetteScript : MonoBehaviour {
public Animator pipetteAnim;
public BoxCollider2D pipetteMove;
public IndicatorScript indicator;
// Use this for initialization
void Start () {
pipetteAnim.enabled = true;
pipetteMove.enabled = true;
indicator.enabled = true;
}
void OnMouseDown () {
pipetteAnim.Play ("Pipette_dropping");
Debug.Log ("Anim playing");
}
}
The debug log even prints out "Anim playing" every time I click on the sprite.
Use animation in Update function and Let me update
public class PipetteScript : MonoBehaviour {
public Animator pipetteAnim;
public BoxCollider2D pipetteMove;
public IndicatorScript indicator;
public bool boolval = false;
// Use this for initialization
void Start () {
pipetteAnim.enabled = true;
pipetteMove.enabled = true;
indicator.enabled = true;
}
void update()
{
if(boolval == true)
pipetteAnim.Play ("Pipette_dropping");
if(boolval == false)
pipetteAnim.Stop ("Pipette_dropping");
}
void OnMouseDown () {
boolval = True;
}
void OnMouseUp () {
boolval = False;
}

Categories