using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class BackToMainMenu : MonoBehaviour
{
public GameObject[] objsToDisable;
public AudioMixer audioMixer;
public static bool gameSceneLoaded;
private void Awake()
{
gameSceneLoaded = true;
}
// Start is called before the first frame update
void Start()
{
audioMixer.SetFloat("gamemusicvolume", Mathf.Log10(PlayerPrefs.GetFloat("mainmenumusicvolume")) * 20);
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
DisableEnableUiTexts(true);
SceneManager.UnloadSceneAsync(0);
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
MenuController.LoadSceneForSavedGame = false;
SceneManager.LoadScene(0, LoadSceneMode.Additive);
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
Cursor.visible = true;
}
}
}
private void SceneManager_sceneLoaded(Scene arg0, LoadSceneMode arg1)
{
audioMixer.SetFloat("gamemusicvolume", Mathf.Log(0.0001f) * 20);
DisableEnableUiTexts(false);
}
private void DisableEnableUiTexts(bool enabled)
{
foreach (GameObject go in objsToDisable)
{
if (go.name == "Cameras")
{
foreach(Transform child in go.transform)
{
if(child.name == "Main Camera")
{
if (enabled == false)
{
child.GetComponent<Camera>().enabled = false;
}
else
{
child.GetComponent<Camera>().enabled = true;
}
}
}
}
else
{
go.SetActive(enabled);
}
}
}
}
When running the game the Main Menu scene start then when making a new game the Game scene is loaded and then here in the Start I'm getting the Main Menu volume float parameter and set it to the Game Music volume.
void Start()
{
audioMixer.SetFloat("gamemusicvolume", Mathf.Log10(PlayerPrefs.GetFloat("mainmenumusicvolume")) * 20);
}
When in the Main Menu scene the volume is -4.01 dB of the main menu music.
Main Menu music volume is -4.01 dB
Then when it's getting the volume of the main menu and set it to the Game music volume the Game music volume is 35.99 dB and I can't figure out why it's setting the volume to so high value ?
The game music volume value is 35.99 dB
Could be the calculation to get the volume in the Start is wrong ?
It should not be Log10 ? Or not * 20 ?
audioMixer.SetFloat("gamemusicvolume", Mathf.Log10(PlayerPrefs.GetFloat("mainmenumusicvolume")) * 20);
How come it's getting from -4.01 dB to 35.99 dB ?
This script in the Mein Menu scene is setting the music and sfx volumes of the main menu using ui sliders :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
using TMPro;
using System;
using UnityEngine.Events;
using System.Linq;
public class Settings : MonoBehaviour
{
[SerializeField] private AudioSource[] audioSources;
public AudioMixer audioMixer;
public TMP_Dropdown resolutionDropdown;
public TMP_Dropdown qualityDropdown;
public Text musicText;
public Text sfxText;
public Slider[] audioSliders;
public Toggle fullScreenToggle;
private Resolution[] resolutions;
private void Awake()
{
audioSources = GetComponents<AudioSource>();
resolutionDropdown.onValueChanged.AddListener(new UnityAction<int>(index =>
{
PlayerPrefs.SetInt("resolutionvalue", resolutionDropdown.value);
PlayerPrefs.Save();
}));
qualityDropdown.onValueChanged.AddListener(new UnityAction<int>(index =>
{
PlayerPrefs.SetInt("qualityvalue", qualityDropdown.value);
PlayerPrefs.Save();
}));
fullScreenToggle.onValueChanged.AddListener(new UnityAction<bool>(index =>
{
PlayerPrefs.SetInt("fullscreen", boolToInt(fullScreenToggle.isOn));
PlayerPrefs.Save();
}));
}
private void Start()
{
qualityDropdown.value = PlayerPrefs.GetInt("qualityvalue");
var resolutions = Screen.resolutions.Where(resolution => resolution.refreshRate == 60).ToArray();
resolutionDropdown.ClearOptions();
List<string> options = new List<string>();
int currentResolutionIndex = 0;
for(int i = 0; i < resolutions.Length; i++)
{
string option = resolutions[i].width + " x " + resolutions[i].height;
options.Add(option);
if(resolutions[i].width == Screen.currentResolution.width &&
resolutions[i].height == Screen.currentResolution.height)
{
currentResolutionIndex = i;
}
}
resolutionDropdown.AddOptions(options);
resolutionDropdown.value = PlayerPrefs.GetInt("resolutionvalue", currentResolutionIndex);
resolutionDropdown.RefreshShownValue();
float musicvolume = PlayerPrefs.GetFloat("mainmenumusicvolume");
float sfxvolume = PlayerPrefs.GetFloat("mainmenusfxvolume");
musicText.text = musicvolume.ToString();
sfxText.text = sfxvolume.ToString();
audioSliders[0].value = musicvolume / 100f;
audioSliders[1].value = sfxvolume / 100f;
fullScreenToggle.isOn = intToBool(PlayerPrefs.GetInt("fullscreen", 0));
}
public void SetResolution(int resolutionIndex)
{
if (resolutions != null)
{
Resolution resolution = resolutions[resolutionIndex];
Screen.SetResolution(resolution.width, resolution.height, Screen.fullScreen);
}
}
public void SetMusicVolume(float volume)
{
audioMixer.SetFloat("mainmenumusicvolume", Mathf.Log10(volume) * 20);
musicText.text = Math.Round(volume * 100, MidpointRounding.AwayFromZero).ToString();
PlayerPrefs.SetFloat("mainmenumusicvolume", (float)Math.Round(volume * 100, MidpointRounding.AwayFromZero));
}
public void SetSfxVolume(float volume)
{
audioMixer.SetFloat("mainmenusfxvolume", Mathf.Log10(volume) * 20);
sfxText.text = Math.Round(volume * 100, MidpointRounding.AwayFromZero).ToString();
PlayerPrefs.SetFloat("mainmenusfxvolume", (float)Math.Round(volume * 100, MidpointRounding.AwayFromZero));
if (!audioSources[1].isPlaying)
audioSources[1].Play();
}
public void SetQuality(int qualityIndex)
{
QualitySettings.SetQualityLevel(qualityIndex);
}
public void SetFullscreen(bool isFullscreen)
{
Screen.fullScreen = isFullscreen;
}
int boolToInt(bool val)
{
if (val)
return 1;
else
return 0;
}
bool intToBool(int val)
{
if (val != 0)
return true;
else
return false;
}
}
The SetMusicVolume is called by the slider event of the main menu music.
It seems that you are mixing some of the string parameters.
In your first script you're setting the audio mixer gamemusicvolume parameter like this:
audioMixer.SetFloat("gamemusicvolume", Mathf.Log10(PlayerPrefs.GetFloat("mainmenumusicvolume")) * 20);
And then in the second script you're setting the audio mixer mainmenumusicvolume parameter instead of the gamemusicvolume parameter.
audioMixer.SetFloat("mainmenumusicvolume", Mathf.Log10(volume) * 20);
Moreover, later in the first script you set the gamemusicvolume to an even lower value:
audioMixer.SetFloat("gamemusicvolume", Mathf.Log(0.0001f) * 20);
All in all, this code feels wrong and overcomplicated. Why do you save a value and then do Log * 20 manipulations? Why not just save the actual value that you want, keep your code simple.
Related
So I recently finished Sebastian Lague's Create a Game series and everything works fine except for the music. I don't know the cause of issue but while in gameplay scene another theme just starts playing, same thing happens when I restart the game and this also happens in Sebastian's finale version of the game so I can't find the answer there. I didn't really try anything since I don't have an idea what cause of the issue may be, so I decided to write here and maybe someone will know the answer. Thanks in advance!
Audio Manager:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class AudioManager : MonoBehaviour
{
public enum AudioChannel { Master, Sfx, Music };
public float masterVolumePercent { get; private set; }
public float sfxVolumePercent { get; private set; }
public float musicVolumePercent { get; private set; }
private AudioSource sfx2DSource;
private AudioSource[] musicSources;
private int activeMusicSourceIndex;
public static AudioManager instance;
private Transform audioListener;
private Transform playerT;
private SoundLibrary library;
private void OnEnable()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
library = GetComponent<SoundLibrary>();
musicSources = new AudioSource[2];
for (int i = 0; i < 2; i++)
{
GameObject newMusicSource = new GameObject("Music source " + (i + 1));
musicSources[i] = newMusicSource.AddComponent<AudioSource>();
newMusicSource.transform.parent = transform;
}
GameObject newSfx2Dsource = new GameObject("2D sfx source");
sfx2DSource = newSfx2Dsource.AddComponent<AudioSource>();
newSfx2Dsource.transform.parent = transform;
audioListener = FindObjectOfType<AudioListener>().transform;
if (FindObjectOfType<PlayerInput>() != null)
{
playerT = FindObjectOfType<PlayerInput>().transform;
}
masterVolumePercent = PlayerPrefs.GetFloat("master vol", 1);
sfxVolumePercent = PlayerPrefs.GetFloat("sfx vol", 1);
musicVolumePercent = PlayerPrefs.GetFloat("music vol", 1);
}
}
void Update()
{
if (playerT != null)
{
audioListener.position = playerT.position;
}
}
public void SetVolume(float volumePercent, AudioChannel channel)
{
switch (channel)
{
case AudioChannel.Master:
masterVolumePercent = volumePercent;
break;
case AudioChannel.Sfx:
sfxVolumePercent = volumePercent;
break;
case AudioChannel.Music:
musicVolumePercent = volumePercent;
break;
}
musicSources[0].volume = musicVolumePercent * masterVolumePercent;
musicSources[1].volume = musicVolumePercent * masterVolumePercent;
PlayerPrefs.SetFloat("master vol", masterVolumePercent);
PlayerPrefs.SetFloat("sfx vol", sfxVolumePercent);
PlayerPrefs.SetFloat("music vol", musicVolumePercent);
PlayerPrefs.Save();
}
public void PlayMusic(AudioClip clip, float fadeDuration = 1)
{
activeMusicSourceIndex = 1 - activeMusicSourceIndex;
musicSources[activeMusicSourceIndex].clip = clip;
musicSources[activeMusicSourceIndex].Play();
StartCoroutine(AnimateMusicCrossfade(fadeDuration));
}
public void PlaySound(AudioClip clip, Vector3 pos)
{
if (clip != null)
{
AudioSource.PlayClipAtPoint(clip, pos, sfxVolumePercent * masterVolumePercent);
}
}
public void PlaySound(string soundName, Vector3 pos)
{
PlaySound(library.GetClipFromName(soundName), pos);
}
public void PlaySound2D(string soundName)
{
sfx2DSource.PlayOneShot(library.GetClipFromName(soundName), sfxVolumePercent * masterVolumePercent);
}
IEnumerator AnimateMusicCrossfade(float duration)
{
float percent = 0;
while (percent < 1)
{
percent += Time.deltaTime * 1 / duration;
musicSources[activeMusicSourceIndex].volume = Mathf.Lerp(0, musicVolumePercent * masterVolumePercent, percent);
musicSources[1 - activeMusicSourceIndex].volume = Mathf.Lerp(musicVolumePercent * masterVolumePercent, 0, percent);
yield return null;
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode sceneMode)
{
if (playerT == null)
{
if (FindObjectOfType<PlayerInput>() != null)
playerT = FindObjectOfType<PlayerInput>().transform;
}
}
}
Music Manager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MusicManager : MonoBehaviour
{
[SerializeField] private AudioClip mainTheme;
[SerializeField] private AudioClip menuTheme;
private string sceneName;
private void OnEnable()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void PlayMusic()
{
AudioClip clipToPlay = null;
if(sceneName == "Main Menu")
{
if(clipToPlay == null)
clipToPlay = menuTheme;
}
else if(sceneName == "Gameplay")
{
if(clipToPlay == null)
clipToPlay = mainTheme;
}
if(clipToPlay != null)
{
AudioManager.instance.PlayMusic(clipToPlay, 2);
Invoke("PlayMusic", clipToPlay.length);
Debug.Log(clipToPlay.length);
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode sceneMode)
{
if(sceneName != scene.name)
{
sceneName = scene.name;
Invoke("PlayMusic", .2f);
}
}
}
Line number 53 in the else :
SceneManager.LoadScene(0, LoadSceneMode.Additive);
I want that if this scene 0 is already loaded with any other scene in my case there are two scenes only for now but if scene 0 the main menu is already loaded Additive then don't load it again when clicking the escape key.
This script sits in Game scene 1
The problem is if in the main menu I click for a new game and the game scene has loaded but before it removed unloaded the main menu scene and I click escape too fast it will load the main menu scene, again and again, all the time.
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Experimental.GlobalIllumination;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class BackToMainMenu : MonoBehaviour
{
public GameObject[] objsToDisable;
public AudioMixer audioMixer;
public static bool gameSceneLoaded;
public GameObject fadeImage;
public Light lights;
private float volumeLinearToDecibel;
private void Awake()
{
gameSceneLoaded = true;
}
// Start is called before the first frame update
void Start()
{
GetGameMusicVolume();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
lights.enabled = true;
DisableEnableUiTexts(true);
SceneManager.UnloadSceneAsync(0);
if (fadeImage != null)
fadeImage.SetActive(true);
GetGameMusicVolume();
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
lights.enabled = false;
MenuController.LoadSceneForSavedGame = false;
SceneManager.LoadScene(0, LoadSceneMode.Additive);
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
Cursor.visible = true;
}
}
}
private void SceneManager_sceneLoaded(Scene arg0, LoadSceneMode arg1)
{
fadeImage = GameObject.FindWithTag("Game Scene Fader");
if (fadeImage != null)
fadeImage.SetActive(false);
audioMixer.SetFloat("gamemusicvolume", Mathf.Log(0.0001f) * 20);
DisableEnableUiTexts(false);
var pauseResumeMainMenuMode = FindInActiveObjectByName("MenuDefaultButtons_Canvas_Pause_Resume");
var newFreshGameMainMenuMode = FindInActiveObjectByName("MenuDefaultButtons_Canvas_NewFreshGame_SaveGame_Not_Exist");
newFreshGameMainMenuMode.SetActive(false);
pauseResumeMainMenuMode.SetActive(true);
SceneManager.sceneLoaded -= SceneManager_sceneLoaded;
}
private void DisableEnableUiTexts(bool enabled)
{
foreach (GameObject go in objsToDisable)
{
if (go.name == "Cameras Control")
{
foreach (Transform child in go.transform)
{
if (child.name == "Main Camera")
{
if (enabled == false)
{
child.GetComponent<Camera>().enabled = false;
}
else
{
child.GetComponent<Camera>().enabled = true;
}
}
}
}
else
{
go.SetActive(enabled);
}
}
}
private float LinearToDecibel(float linear)
{
float dB;
if (linear != 0)
dB = 20.0f * Mathf.Log10(linear);
else
dB = -144.0f;
return dB;
}
private void GetGameMusicVolume()
{
volumeLinearToDecibel = LinearToDecibel(PlayerPrefs.GetFloat("mainmenumusicvolume") / 100f);
audioMixer.SetFloat("gamemusicvolume", volumeLinearToDecibel);
}
GameObject FindInActiveObjectByName(string name)
{
Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
for (int i = 0; i < objs.Length; i++)
{
if (objs[i].hideFlags == HideFlags.None)
{
if (objs[i].name == name)
{
return objs[i].gameObject;
}
}
}
return null;
}
}
You can check if the menu object cached already exist open the menu object, if not load the menu scene. Simple as that.
The more general way would be using SceneManager.GetSceneByBuildIndex
This method will return a valid Scene if a Scene has been added to the build settings at the given build index AND the Scene is loaded. If it has not been loaded yet the SceneManager cannot return a valid Scene.
so simply check IsValid like
if(SceneManager.GetSceneByBuildIndex(0).IsValid())
so I have like 5 game object in my scene but I only scale each of them separately. However when I try to do that all of them start scaling simultaneously. Also, I have a placement indicator that would be used to instantiate the object on the plane. It seems that instead of the object itself, the placement indicator is the one that gets scaled. How should I fix that?
I have tried deactivating the placement indicator but did not work.
Here is the code for instantiating objects:
I limited the obj number to 5.
I use this script instead of the usual "PlaceonPlane" script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.Experimental.XR;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;
public class ARTaptoPlaceObject : MonoBehaviour
{
private ARSessionOrigin arOrigin;
GameObject spawnedobj;
public GameObject placementIndicator;
private ARRaycastManager arRaycast;
public Pose placementPose;
public UIContoller sc;
public bool placementPoseIsValid = false;
private int count;
private string valu;
string prefabs;
void Start()
{
arOrigin = FindObjectOfType<ARSessionOrigin>();
arRaycast = FindObjectOfType<ARRaycastManager>();
count = 0;
}
// Update is called once per frame
void Update()
{
UpdatePlacementPose();
UpdatePlacementIndicator();
for (var i = 0; i < Input.touchCount; ++i)
{
if (Input.GetTouch(i).phase == TouchPhase.Began)
{
if (placementPoseIsValid && Input.GetTouch(i).tapCount == 2)
{
PlaceObject();
}
}
}
}
public void PlaceObject()
{
if (count <= 4)
{
if (sc.objectToPlace != null)
{
spawnedobj = Instantiate(sc.objectToPlace, placementPose.position, placementPose.rotation);
arOrigin.MakeContentAppearAt(spawnedobj.transform, spawnedobj.transform.position, spawnedobj.transform.rotation);
count++;
}
}
else
{
placementIndicator.SetActive(false);
}
}
private void UpdatePlacementIndicator()
{
if (placementPoseIsValid && count <= 4 && sc.active == false)
{
placementIndicator.SetActive(true);
placementIndicator.transform.SetPositionAndRotation(placementPose.position, placementPose.rotation);
}
else
{
placementIndicator.SetActive(false);
}
}
private void UpdatePlacementPose()
{
var screenCenter = Camera.current.ViewportToScreenPoint(new Vector3(0.5f, 0.5f));
var hits = new List<ARRaycastHit>();
arRaycast.Raycast(screenCenter, hits, UnityEngine.XR.ARSubsystems.TrackableType.Planes);
placementPoseIsValid = hits.Count > 0;
if (placementPoseIsValid)
{
placementPose = hits[0].pose;
var cameraForward = Camera.current.transform.forward;
var cameraBearing = new Vector3(cameraForward.x, 0, cameraForward.z).normalized;
placementPose.rotation = Quaternion.LookRotation(cameraBearing);
}
}
}
and here is the Scaler script that's attached to the button that would scale the object.
public class Scaler : MonoBehaviour
{
public UIContoller uc;
public ARTaptoPlaceObject ap;
private GameObject ReferenceToScale;
public void OnValueChange()
{
ReferenceToScale = (UnityEngine.GameObject)Resources.Load(uc.s_count, typeof(GameObject));
Vector3 t = ReferenceToScale.transform.localScale;
Vector3 scaleValue = t * 1.1f;
ReferenceToScale.transform.localScale = scaleValue;
}
Also the "objectToPlace" itself is in the "UI.Controller" script as I could not view it in the scene when it was in the "ARTaptoPlace" script
The first script and the second both attached to the doors.
In this case I have 12 doors.
No matter what the first door of the 12 the player controller or a NPC enter the door it will open but stay opened. The next door the player controller or the NPC will enter will open and then also will be closed and then all the doors.
But each time the first door never close. It's working only from the second door each time when running the game.
On this script HoriDoorManager I'm using public static flag exitedDoor and set it to true inside the OnTriggerExit:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class HoriDoorManager : MonoBehaviour
{
public static bool exitedDoor = false;
private bool doorLockState;
private List<DoorHori> doors = new List<DoorHori>();
private void Start()
{
if (transform.parent != null)
{
Transform parent = transform.parent;
var children = parent.GetComponentsInChildren<Transform>();
if(children != null)
{
foreach (Transform door in children)
{
if (door.name == "Door_Left" || door.name == "Door_Right")
doors.Add(door.GetComponent<DoorHori>());
}
}
}
}
void OnTriggerEnter()
{
if (doorLockState == false)
{
if (doors != null)
{
for(int i =0; i < doors.Count; i++)
{
doors[i].OpenDoor();
}
}
}
}
private void OnTriggerExit(Collider collide)
{
if (doorLockState == false)
{
exitedDoor = true;
}
}
public void ChangeLockState(bool lockState)
{
doorLockState = lockState;
}
}
In the second script I'm checking if the flag exitedDoor is true and then start closing the door: Inside the method WaitToClose:
using UnityEngine;
using System.Collections;
public class DoorHori : MonoBehaviour
{
public float translateValue;
public float easeTime;
public OTween.EaseType ease;
public float waitTime;
private Vector3 StartlocalPos;
private Vector3 endlocalPos;
private void Start()
{
StartlocalPos = transform.localPosition;
gameObject.isStatic = false;
}
public void OpenDoor()
{
OTween.ValueTo(gameObject, ease, 0.0f, -translateValue, easeTime, 0.0f, "StartOpen", "UpdateOpenDoor", "EndOpen");
GetComponent<AudioSource>().Play();
}
private void UpdateOpenDoor(float f)
{
Vector3 pos = transform.TransformDirection(new Vector3(1, 0, 0));
transform.localPosition = StartlocalPos + pos * f;
}
private void UpdateCloseDoor(float f)
{
Vector3 pos = transform.TransformDirection(new Vector3(-f, 0, 0));
transform.localPosition = endlocalPos - pos;
}
private void EndOpen()
{
endlocalPos = transform.localPosition;
StartCoroutine(WaitToClose());
}
private IEnumerator WaitToClose()
{
if (HoriDoorManager.exitedDoor == true)
{
yield return new WaitForSeconds(waitTime);
OTween.ValueTo(gameObject, ease, 0.0f, translateValue, easeTime, 0.0f, "StartClose", "UpdateCloseDoor", "EndClose");
GetComponent<AudioSource>().Play();
}
}
}
Try changing the OnTriggerEnter to this in your first script.
private void OnTriggerEnter(Collider collide){
if (doorLockState == false)
{
if (doors != null)
{
for(int i =0; i < doors.Count; i++)
{
doors[i].OpenDoor();
}
}
}
}
You are not using unity's defined method when you remove the parameters of the method, so it is no longer referencing the same OnTriggerEnter.
It can then also be used to check what is triggering the on enter flag, because I am assuming you don't want any collisions to trigger this logic.
I'm trying to make a simple condition:
If the value I have, is less than the price it costs the item, the button is disabled.
If the value I have, is greater than or equal to the price it costs the item the button is enabled and I can buy it.
But when I test, I have some problems.
First, if I have less than the item cost the button is enabled, and only when I click on it it is when it disables.
Second, if I have less than the item cost and I click on it it disables, but if I get enough to purchase the item, the button is not enabled again.
How do I to be checked these variables all the time? If I have enough the button is enabled if you do not have it disables.
Bellow my scrip:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class BuySkin : MonoBehaviour {
public int price;
public Button buyBee1;
void OnEnable ()
{
//Register Button Events
buyBee1.onClick.AddListener (() => buySkin (buyBee1));
}
public void buySkin(Button button)
{
if (BeeCoinScore.coin >= price) {
BeeCoinScore.coin -= price;
buyBee1.interactable = false;
}
if (BeeCoinScore.coin < price) {
buyBee1.interactable = false;
}
}
void OnDisable ()
{
//Un-Register Button Events
buyBee1.onClick.RemoveAllListeners ();
}
}
Try this out with some prefabs!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class GameController : MonoBehaviour
{
public int coins;
private int spherePrice = 100, cubePrice = 50;
public GameObject player;
public GameObject[] availablePrefabs;
public List<GameObject> mySkins;
public Button btnSphere, btnCube;
public Text txtSphere, txtCube;
void Start ()
{
string serializedMySkins = PlayerPrefs.GetString ("skins", "");
string serializedPlayer = PlayerPrefs.GetString ("player", "");
// skins desserialization
if (serializedMySkins == "")
mySkins = new List<GameObject> ();
else {
var a = serializedMySkins.Split (',');
for (int i = 0; i < a.Length; i++) {
if (a [i] == "Sphere") {
mySkins.Add (availablePrefabs [0]);
}
if (a [i] == "Cube") {
mySkins.Add (availablePrefabs [1]);
}
}
}
// player desserialization
if (serializedPlayer != "") {
if (serializedPlayer == "Sphere") {
player = availablePrefabs [0];
}
if (serializedPlayer == "Cube") {
player = availablePrefabs [1];
}
} else {
player = mySkins [0];
}
coins = PlayerPrefs.GetInt ("coins", 0);
coins = 1000;
}
void Update ()
{
if (mySkins.Contains (availablePrefabs [0])) {
txtSphere.text = "Usar esfera";
} else {
btnSphere.interactable = coins >= spherePrice;
}
if (mySkins.Contains (availablePrefabs [1])) {
txtCube.text = "Usar cubo";
} else {
btnCube.interactable = coins >= cubePrice;
}
}
public void play ()
{
player = (GameObject)Instantiate (player, new Vector2 (0, 0), Quaternion.identity);
}
public void verifySkin (GameObject skinPrefab)
{
if (mySkins.Contains (skinPrefab)) {
useSkin (skinPrefab);
} else if (coins >= priceOf (skinPrefab)) {
buySkin (skinPrefab, priceOf (skinPrefab));
}
}
public void buySkin (GameObject skinPrefab, int price)
{
mySkins.Add (skinPrefab);
coins -= price;
string skinsHash = "";
for (int i = 0; i < mySkins.Count; i++) {
skinsHash += mySkins [i].name + ",";
}
Debug.Log (skinsHash);
PlayerPrefs.SetInt ("coins", coins);
PlayerPrefs.SetString ("skins", skinsHash);
PlayerPrefs.Save ();
}
public void useSkin (GameObject skinPrefab)
{
player = skinPrefab;
PlayerPrefs.SetString ("player", player.name);
PlayerPrefs.Save ();
}
private int priceOf (GameObject skinPrefab)
{
if (skinPrefab == availablePrefabs [0])
return spherePrice;
else if (skinPrefab == availablePrefabs [1])
return cubePrice;
else
return 0;
}
}
OnEnable()is called when the object becomes enabled and active.
you need Update() as it is getting called every frame it will check whether your value is less than or greater than price of item.You may also try like this.
// I think that you are making an buymenu, so you can disable and enable your menu with ui button and check money you have
using System.Collections;
using UnityEngine.UI;
public class BuySkin : MonoBehaviour
{
public int price;
public static int money;// money you have
public Button thisbuyBee1;
public void buychkr()
{
if(price>= money)
{
thisbuyBee1.interactable = false;
}
else
{
thisbuyBee1.interactable = true;
}
}
void Update()
{
buychkr();
}
}