i am trying to make a lives counter in unity with c# so i made a ui text in unity with the value Livesvalue = 3; in a other script i have the deatchscene so when i die the value goes to the other script en does -1 but i get an eroor that the value does not exist
UItext code:
public class livesscript : MonoBehaviour
{
public static int Livesvalue = 3;
Text Lives;
// Start is called before the first frame update
void Start()
{
Lives = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
Lives.text = "Lives: " + Livesvalue;
}
}
deathscene code:
private void StartDeathSequence()
{
state = State.Dead;
audioSource.Stop();
audioSource.PlayOneShot(death);
deathpart.Play();
mainEnginepart.Stop();
livesscript.Livesvalue -= 1;
Invoke("RespawnLevel", Waitdead); // parameterise time
LivesRespawn();
}
private void LivesRespawn()
{
if (Livesvalue == 0)
{
SceneManager.LoadScene(0);
}
}
When referencing a static variable you need to include the class name and a period before the variable.
private void LivesRespawn()
{
if (Livesvalue == 0)
{
SceneManager.LoadScene(0);
}
}
change to
private void LivesRespawn()
{
if (livesscript.Livesvalue < 1)
{
SceneManager.LoadScene(0);
}
}
Related
In my project, the banner opens after the scene is reloaded, everything seems to be in order in the editor.
Everything works fine in the editor, I checked it, but it’s only worth building the project on Android, it doesn’t work there normally. It will appear only after the scene is reloaded, and then not immediately with a delay of 2-3 seconds.
My code:
using UnityEngine;
using System.Collections;
using UnityEngine.Advertisements;
public class BannerAd : MonoBehaviour
{
[SerializeField] BannerPosition _bannerPosition;
[SerializeField] private string _androidAdUnitId = "Banner_Android";
[SerializeField] private string _iOSAdUnitId = "Banner_iOS";
private string _adUnitId;
private void Awake()
{
_adUnitId = (Application.platform == RuntimePlatform.IPhonePlayer)
? _iOSAdUnitId
: _androidAdUnitId;
}
private void Start()
{
Advertisement.Banner.SetPosition(_bannerPosition);
LoadBanner();
}
private IEnumerator LoadAdBanner()
{
yield return new WaitForSeconds(1f);
LoadBanner();
}
public void LoadBanner()
{
BannerLoadOptions options = new BannerLoadOptions
{
loadCallback = OnBannerLoaded,
errorCallback = OnBannerError
};
Advertisement.Banner.Load(_adUnitId, options);
}
private void OnBannerLoaded()
{
Debug.Log("Banner loaded");
ShowBannerAd();
}
private void OnBannerError(string message)
{
Debug.Log($"Banner Error: {message}");
}
public void ShowBannerAd()
{
BannerOptions options = new BannerOptions
{
clickCallback = OnBannerClicked,
hideCallback = OnBannerHidden,
showCallback = OnBannerShown
};
Advertisement.Banner.Show(_adUnitId, options);
}
public void HideBannerAd()
{
Advertisement.Banner.Hide();
}
private void OnBannerClicked() { }
private void OnBannerShown() { }
private void OnBannerHidden() { }
}
It might be the ad is still not initialized when you call LoadBanner so it doesn't work at first. The best is to call LoadBanner when Initialization is complete. Set _testMode to true or false based on your need.
public class BannerAd : MonoBehaviour, IUnityAdsInitializationListener
{
[SerializeField] bool _testMode = true;
private string _adUnitId;
void Awake()
{
InitializeAds();
}
public void InitializeAds()
{
_adUnitId = (Application.platform == RuntimePlatform.IPhonePlayer)
? _iOSGameId
: _androidGameId;
Advertisement.Initialize(_adUnitId, _testMode, this);
}
public void OnInitializationComplete()
{
LoadBanner();
}
//rest of the code
}
}
This question already has answers here:
array of events in C#?
(4 answers)
Closed 1 year ago.
I'm creating a touch manager, which fires Began and Ended events and other monobehaviours can subscribe to them. For some reason I am unable to find any information on creating a list of events actions.
This is an illustration of what I currently have:
public class TouchHandler : MonoBehaviour {
private static readonly int MAX_TOUCH_COUNT = 2;
public event Action<int> Began;
public event Action<int> Ended;
private void Update() {
if (Input.touchCount > 0) {
Touch[] touches = Input.touches;
int touchCount = Mathf.Min(touches.Length, MAX_TOUCH_COUNT);
for (int i = 0; i < touchCount; i++) {
Touch t = touches[i];
if (t.phase == TouchPhase.Began)
Began?.Invoke(i);
else if (t.phase == TouchPhase.Ended)
Ended?.Invoke(i);
}
}
}
}
public class Listener : MonoBehaviour {
[SerializeField] private TouchHandler th;
private int touchIndexToListen = 0;
private void OnEnable() {
th.Began += TouchBegan;
th.Ended += TouchEnded;
}
private void OnDisable() {
th.Began -= TouchBegan;
th.Ended -= TouchEnded;
}
private void TouchBegan(int index) {
if (index != touchIndexToListen)
return;
Debug.Log("TouchBegan");
}
private void TouchEnded(int index) {
if (index != touchIndexToListen)
return;
Debug.Log("TouchEnded");
}
}
This is how I'd want it to work:
public class TouchHandler : MonoBehaviour {
private static readonly int MAX_TOUCH_COUNT = 2;
public event Action[] Began = new Action[MAX_TOUCH_COUNT];
public event Action[] Ended = new Action[MAX_TOUCH_COUNT];
private void Update() {
if (Input.touchCount > 0) {
Touch[] touches = Input.touches;
int touchCount = Mathf.Min(touches.Length, MAX_TOUCH_COUNT);
for (int i = 0; i < touchCount; i++) {
Touch t = touches[i];
if (t.phase == TouchPhase.Began)
Began[i]?.Invoke();
else if (t.phase == TouchPhase.Ended)
Ended[i]?.Invoke();
}
}
}
}
public class Listener : MonoBehaviour {
[SerializeField] private TouchHandler th;
private int touchIndexToListen = 0;
private void OnEnable() {
th.Began[touchIndexToListen] += TouchBegan;
th.Ended[touchIndexToListen] += TouchEnded;
}
private void OnDisable() {
th.Began[touchIndexToListen] -= TouchBegan;
th.Ended[touchIndexToListen] -= TouchEnded;
}
private void TouchBegan(int index) {
Debug.Log("TouchBegan");
}
private void TouchEnded(int index) {
Debug.Log("TouchEnded");
}
}
So in short: I want to subscribe only to specific touch indexes, which also helps me get rid of the if (index != touchIndexToListen) check in other monobehaviours.
The reason I'm doing this touch manager is because I want a clean way to handle mouse input using the same class and I need to be able to fire the ended event when app is minimized in Android. I've left those parts out of this illustration, since they are irrelevant to this question.
First of all one important note: The i used for touches[i] is NOT guaranteed to refer to the same Touch across multiple frames!
For that you rather want to use the Touch.fingerId
The unique index for the touch.
All current touches are reported in the Input.touches array or by using the Input.GetTouch function with the equivalent array index. However, the array index is not guaranteed to be the same from one frame to the next. The fingerId value, however, consistently refers to the same touch across frames. This ID value is very useful when analysing gestures and is more reliable than identifying fingers by their proximity to previous position, etc.
Touch.fingerId is not the same as "first" touch, "second" touch and so on. It is merely a unique id per gesture. You cannot make any assumptions about fingerId and the number of fingers actually on screen, since virtual touches will be introduced to handle the fact that the touch structure is constant for an entire frame (while in reality the number of touches obviously might not be true, e.g. if multiple tappings occur within a single frame).
The array makes no sense actually. event can only be used for a single delegate (Action is just a shorthand for a delegate void Action();) it can't be used for an Action[].
You actually can store a single Action for each index and then use the += and -= operators on it.
You could go a complete different way and use a pattern like
public class TouchHandler : MonoBehaviour
{
private const int MAX_TOUCH_COUNT = 2;
// Store callback Actions by phase and index
// NOTE: I would still pass in the actual Touch in order to be able to use the information in it
private readonly Dictionary<TouchPhase, Dictionary<int, Action<Touch>>> _touchActions = new Dictionary<TouchPhase, Dictionary<int, Action<Touch>>>
{
{TouchPhase.Began, new Dictionary<int, Action<Touch>>()},
{TouchPhase.Ended, new Dictionary<int, Action<Touch>>()}
};
// I would keep one where the listeners can still check "manually"
public event Action<Touch> generalTouchEvent;
public void Subscribe(TouchPhase phase, int touchIndex, Action<Touch> action)
{
if (touchIndex < 0 || touchIndex > MAX_TOUCH_COUNT)
{
Debug.LogError($"Touch index {touchIndex} is not supported!", this);
return;
}
// First get the according inner dictionary by TouchPhase
if (!_touchActions.TryGetValue(phase, out var touchPhaseActions))
{
Debug.LogError($"Touch phase {phase} is not supported!", this);
return;
}
// Next check if there already is an action for given index
if (touchPhaseActions.TryGetValue(touchIndex, out var touchAction))
{
// If it already exists we append the new action to the existing one
// Unsubscribing is fine even if it wasn't added before
// This just makes sure it is only added once
touchAction -= action;
touchAction += action;
}
else
{
// otherwise this new action is the only one for now
touchAction = action;
}
// (over)write it back into the dictionary
touchPhaseActions[touchIndex] = touchAction;
}
public void UnSubscripe(TouchPhase phase, int touchIndex, Action<Touch> action)
{
if (touchIndex < 0 || touchIndex > MAX_TOUCH_COUNT)
{
Debug.LogError($"Touch index {touchIndex} is not supported!", this);
return;
}
// First get the according inner dictionary by TouchPhase
if (!_touchActions.TryGetValue(phase, out var touchPhaseActions))
{
Debug.LogError($"Touch phase {phase} is not supported!", this);
return;
}
if (touchPhaseActions.TryGetValue(touchIndex, out var touchAction))
{
touchAction -= action;
touchPhaseActions[touchIndex] = touchAction;
}
else
{
Debug.LogWarning($"Nothing was listening to {phase} on index {touchIndex} anyway");
}
}
private void Update()
{
if (Input.touchCount > 0)
{
// Get all touches, order them ascending by their fingerId then take up to MAX_TOUCH_COUNT of them
foreach (var t in Input.touches.OrderBy(t => t.fingerId).Take(MAX_TOUCH_COUNT))
{
InvokeTouchEvent(t);
}
}
}
private void InvokeTouchEvent(Touch touch)
{
generalTouchEvent?.Invoke(touch);
if (!_touchActions.TryGetValue(touch.phase, out var touchPhaseActions))
{
return;
}
if (!touchPhaseActions.TryGetValue(touch.fingerId, out var touchAction))
{
return;
}
touchAction?.Invoke(touch);
}
}
and then on the listener do e.g.
public class TouchListener : MonoBehaviour
{
[SerializeField] private TouchHandler _touchHandler;
[SerializeField] public int touchIndexToListenTo;
private void Start()
{
_touchHandler.Subscribe(TouchPhase.Began, touchIndexToListenTo, OnTouchBegan);
_touchHandler.Subscribe(TouchPhase.Ended, touchIndexToListenTo, OnTouchEnded);
_touchHandler.generalTouchEvent += OnGeneralTouchEvent;
}
private void OnGeneralTouchEvent(Touch touch)
{
Debug.Log($"Received a general callback for {touch.phase} with index {touch.fingerId}!", this);
}
private void OnTouchEnded(Touch touch)
{
Debug.Assert(touch.fingerId == touchIndexToListenTo, $"Why do I get an event for {touch.fingerId} if I'm only listening to {touchIndexToListenTo}?!", this);
Debug.Assert(touch.phase == TouchPhase.Ended, $"Why do I get an event for {touch.phase} if I'm only listening to {TouchPhase.Ended}?!", this);
Debug.Log($"Received a {touch.phase} event for index {touch.fingerId}", this);
}
private void OnTouchBegan(Touch touch)
{
Debug.Assert(touch.fingerId == touchIndexToListenTo, $"Why do I get an event for {touch.fingerId} if I'm only listening to {touchIndexToListenTo}?!", this);
Debug.Assert(touch.phase == TouchPhase.Began, $"Why do I get an event for {touch.phase} if I'm only listening to {TouchPhase.Began}?!", this);
Debug.Log($"Received a {touch.phase} event for index {touch.fingerId}", this);
}
}
You can use EventHandlerList for subscribing multiple kind of event in same object.
Be aware that keys are references, so passing int there and retrieving it by value will not work. You must save object references somewhere to be able to fire specific events.
Simple purpose demo app here:
class Program
{
static void Main(string[] args)
{
EventHandlerList _eventList = new EventHandlerList();
var mouseHandler = new MouseHandlerClass();
var appStateHandler = new AppStateHandlerClass();
//attach mouse handlers
_eventList.AddHandler(mouseHandler, (Action<int>)mouseHandler.DoSomething);
_eventList.AddHandler(mouseHandler, (Action<int>)mouseHandler.DoAnotherThing);
//attach appState handlers
_eventList.AddHandler(appStateHandler, (Action<int>)appStateHandler.DoSomething);
//fire mouse event
(_eventList[mouseHandler] as Action<int>).Invoke(99);
//fire appState event
(_eventList[appStateHandler] as Action<int>).Invoke(52);
}
}
public class MouseHandlerClass
{
public void DoSomething(int input)
{
Console.WriteLine($"MouseHandler processed: {input}");
}
public void DoAnotherThing(int input)
{
Console.WriteLine($"MouseHandler processed another thing: {input}");
}
}
public class AppStateHandlerClass
{
public void DoSomething(int input)
{
Console.WriteLine($"AppStateHandlerClass processed: {input}");
}
}
Edit
The handler method signature can be simplified to Action if you don't need to pass any parameters to attached handlers
I'm confused about finding reference GameObject but different Scene and set the onclick when difference scene, so I have GameManager who manage all but available only on the Main menu. So I decide to make Dontdestroyonload, the issue start at this, so when I play to the MainGame Scene, the field of GameManager at inspector will find, but I can't drag n drop different scene, right? That confuses me.
And if the GameManager at the MainMenu scene, the question is how to drag n drop at the onClick event, like I want pause button active or something else in the game.
]3
I tried with onLloadscene(scene s, Mode mode), but nothing happens, and here the scrip for the GameManager. :
public static GameManager gameManager;
[Header("Main Menu panels")]
public GameObject startPanel;
public GameObject settingPanel;
public GameObject levelPanel;
[Header("InGame Panels")]
#region Panel
public GameObject pausePanel;
public GameObject ObjectivePanel;
public GameObject shopPanel;
private int click = 0;
[Header("Int Tweaks")]
public int indexLevel;
public int onlevel;
public bool isPaused;
_levelSelect LevelSelect;
public static GameManager Instance { set; get; }
public int levelindexPlayerPrefs;
private void Awake()
{
if (gameManager != null)
{
Instance = this;
Destroy(gameObject);
}
else
{
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
LevelSelect = FindObjectOfType<_levelSelect>();
OnStart();
onlevel = int.Parse(LevelSelect.levelIndex) + 1;
indexLevel = int.Parse(LevelSelect.levelIndex);
getPlayerData();
}
// Update is called once per frame
void Update()
{
ExitApp();
}
public void OnStart()
{
startPanel.SetActive(true);
settingPanel.SetActive(false);
levelPanel.SetActive(false);
}
#region Buttons
public void startbutton()
{
levelPanel.SetActive(true);
startPanel.SetActive(false);
settingPanel.SetActive(false);
}
public void backButtonMainMenu()
{
levelPanel.SetActive(false);
startPanel.SetActive(true);
settingPanel.SetActive(false);
}
public void settingbutton()
{
levelPanel.SetActive(false);
startPanel.SetActive(false);
settingPanel.SetActive(true);
}
public void PauseButton()
{
Time.timeScale = 0f;
pausePanel.SetActive(true);
ObjectivePanel.SetActive(false);
}
public void Resume()
{
Time.timeScale = 1f;
}
#endregion
public void ExitApp()
{
if (Input.GetKey(KeyCode.Escape))
{
click++;
StartCoroutine(ClickTime());
if (click>1)
{
print("Exit Game");
Application.Quit();
}
}
}
IEnumerator ClickTime()
{
yield return new WaitForSeconds(0.5f);
click = 0;
}
public void getPlayerData()
{
levelindexPlayerPrefs = PlayerPrefs.GetInt("LevelIndex", 0);
}
public void updateLevel(int Index)
{
if (levelindexPlayerPrefs < Index)
{
PlayerPrefs.SetInt("LevelIndex", Index);
levelindexPlayerPrefs = PlayerPrefs.GetInt("LevelIndex");
}
}
#region onloadedScenePickRefferences
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
pausePanel = GameObject.FindGameObjectWithTag("PausePanel");
ObjectivePanel = GameObject.FindGameObjectWithTag("ObjectivePanel");
}
#endregion
//public IEnumerator EndChapter()
//{
// updateLevel(indexLevel + 1);
// getPlayerData();
//}
Here is what I would probably do:
Have a static class for storing and sharing all your references. It doesn't have to be in any scene but simply "lives" in the assets:
public static class GlobalReferences
{
// as example just for one reference but you can implement the rest equally yourself
// here this class actually stores the reference
private static GameObject startPanel;
// A public property in order to add some logic
// other classes will always access and set the value through this property
public static GameObject StartPanel
{
get
{
// if the reference exists return it right away
if(startPanel) return startPanel;
// as a fallback try to find it
startPanel = GameObject.FindGameObjectWithTag("StartPanel");
// ofcourse it might still fail when you simply try to access it
// in a moment it doesn't exist yet
return startPanel;
}
set
{
startPanel = value;
// invoke an event to tell all listeners that the startPanel
// was just assigned
OnStartPanelReady?.Invoke();
}
}
// An event you will invoke after assigning a value making sure that
// other scripts only access this value after it has been set
// you can even directly pass the reference in
public static event Action<GameObject> OnStartPanelReady;
}
So now in your component(s) that is(are) in the new loaded scene you assign the value as early as possible (Awake). Here you can already store it via the Inspector since it is a scene reference:
public class ExampleSetter : MonoBehaviour
{
// already reference it via the Inspector
[SerializeField] private GameObject startPanel;
private void Awake()
{
// as a fallback
if(!startPanel) startPanel = GameObject.FindObjectWithTag("startPanel");
// assign it to the global class
GlobalReferences.StartPanel = startPanel;
}
}
And in other scenes that where already loaded before you add a listener so they do their stuff as soon as the other scene is ready:
public class ExampleConsumer : MonoBehaviour
{
[Header("Debug")]
[SerializeField] private GameObject startPanel;
private void Awake()
{
// Try to get the reference
startPanel = GlobalReferences.StartPanel;
// if this failed then wait until it is ready
if(!startPanel)
{
// it is save to remove callbacks even if not added yet
// makes sure a listener is always only added once
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
GlobalReferences.OnStartPanelReady += OnStartPanelReady;
}
// otherwise already do what you want
else
{
OnStartPanelReady(startPanel);
}
}
private void OnDestroy()
{
// always make sure to clean up callbacks when not needed anymore!
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
}
private void OnStartPanelReady(GameObject newStartPanel)
{
startPanel = newStartPanel;
// always make sure to clean up callbacks when not needed anymore!
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
// NOTE: It is possible that at this point it is null anyway if another
// class has set this actively to null ;)
if(startPanel)
{
// Now do something with the startPanel
}
}
}
The other way round when you need a reference in the new loaded Scene form the main scene ... it should already be set since the mainscene was loaded first and has already assigned its according references.
Now you can either go for this static class or simply implement the same logic for each reference that needs to be shared directly in an according component where you reference them via drag&drop .. it makes no difference since anyway you will use static fields and events that are not bound to any instance but the type(s) itself.
im beginner and still learning please don't hate.
So my script is located in Canvas, (Canvas -> inv -> invslot) but I need to get currentSlot int from a script in invslot gameobj., how would I do that the right way? I've tried this so far but doesn't seem to work at all.
void UpdateUI () {
for (int i = 0; i < slots.Length; i++)
{
if (i < inventory.items.Count) {
currentSlot = GetComponentsInChildren<InventoryScroll>();
slots[i] = currentSlot;
currentSlot.AddItem(inventory.items[i]);
Debug.Log ("Updating UI");
} else
{
slots[i].ClearSlot();
}
}
}
EDIT!
Here is the top of my InventoryUI, where I want to bring the int currentSlot
public Transform itemsParent;
Inventory inventory;
InventorySlot[] slots;
// Start is called before the first frame update
void Start()
{
inventory = Inventory.instance;
inventory.onItemChangedCallback += UpdateUI;
slots = itemsParent.GetComponentsInChildren<InventorySlot>();
}
But the Inventoryscroll goes this way
List<GameObject> slots = new List<GameObject>();
public int currentSlot=0;
int slotsToScroll=3;
void Start() {
foreach(Transform child in this.transform) {
slots.Add(child.gameObject);
}
}
void Update () {
if (Input.GetKeyDown(KeyCode.Alpha1)) {
currentSlot=0;
UpdateDisplay();
}
if (Input.GetAxis("Mouse ScrollWheel") >0){
if (currentSlot<slotsToScroll) {
currentSlot++;
} else {
currentSlot=0;
}
UpdateDisplay();
}
}
void UpdateDisplay() {
for (int i = 0; i < slots.Count; i++)
{
if (i==currentSlot) {
slots[i].transform.GetChild(0).gameObject.SetActive(true);
} else {
slots[i].transform.GetChild(0).gameObject.SetActive(false);
}
}
}
Inventory script
#region Singleton
public static Inventory instance;
void Awake () {
if (instance != null) {
Debug.LogWarning("More than one instance of inventory found!");
return;
}
instance = this;
}
#endregion
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;
public int space = 6;
public List items = new List();
public bool Add (Item item) {
if (!item.isDefaultItem) {
if(items.Count >= space) {
Debug.Log("Not enough inventory space.");
return false;
}
items.Add(item);
if (onItemChangedCallback != null)
onItemChangedCallback.Invoke();
}
return true;
public void Remove (Item item) {
items.Remove(item);
if (onItemChangedCallback != null)
onItemChangedCallback.Invoke();
Careful, Unity has two methods:
GetComponentsInChildren
Returns all components of Type type in the GameObject or any of its children.
this returns a InventoryScroll []!
and GetComponentInChildren
Returns the component of Type type in the GameObject or any of its children using depth first search.
This returns one single InventoryScroll reference, the first one found!
Note the s!
From your description and how you use it in your code it seems like you wanted to use the latter but have an s too much.
The second mistake: From the variable name it sounds like you rather wanted to get an InventorySlot not an InventoryScroll!
So you should use
currentSlot = GetComponentInChildren<InventorySlot>();
Though it is hard to tell what your actual goal is with this code without seeing the types of slots and currentSlot.
It also appears really strange to me that you already get all slots in Start but here you overwrite
slots[i] = currentSlot;
for each i that is i < inventory.items.Coun. Also you iterate through slots.Length but you pass in inventory.izems[i] .. I don't understand what is supposed to happen here exactly.
first, there is a singleton object simply is subscribed to activeSceneChanged
SomeSingleton.cs
void Awake ()
{
Debug.LogError ("AWAKE");
if (instance == null) {
Debug.LogError ("instance == null");
instance = this;
MusicController.instance = this;
SceneManager.activeSceneChanged += OnSceneChanged;
DontDestroyOnLoad (this.gameObject);
} else {
Debug.LogError ("destroy");
Destroy (this.gameObject);
}
}
void OnSceneChanged (Scene previousScene, Scene changedScene)
{
Debug.LogError ("OnSceneChanged changedScene = " + changedScene.name);
}
from Lobby Scene player moves to Room Scene.
in room scene.
the "Arena" Scene gets preloaded for better game experience.
LoadSceneAsync("Arena")
with allowSceneActivation = false
when player clicks play button, sets allowSceneActivation = true
but when user decides to go back and clicks Leave Button, LoadScene("Lobby") gets called.
At this time in console, it will Log
LOGS
OnSceneChanged changedScene = Lobby // time : 0.793
OnSceneChanged changedScene = Room // time : 3.982
[when player clicks Leave Button]
OnSceneChanged changedScene = Arena // time : 7.583
OnSceneChanged changedScene = Lobby // time : 7.583
like this...
it just gets activated but wont actually load the scene. why is Arena getting activatd? how to solve this problem???
should i do some unload thing to the AsyncLoading?
==== EDITED =====
when leave button clicked
public void LeaveRoom ()
{
print ("Leave Room And Move To Lobby");
SetCanStartIfMasterClient (false);
PhotonNetwork.LeaveRoom ();
AdmobController.DestroyBanner ();
Waiting.instance.StartWaiting (waitingForLeaveRoomData);
SceneFader.instance.LoadSceneWhenFadingComplete (SceneType.Lobby);
}
in SceneFader.cs
public enum SceneFadeType
{
FadeIn = 1,
FadeOut = -1
}
public class SceneFader : MonoBehaviour
{
public static SceneFader instance;
void Awake ()
{
instance = this;
// StartFadeOut
StartFading (SceneFadeType.FadeOut, null);
}
public void LoadSceneWhenFadingComplete (SceneType sceneType)
{
// 1. start Fading
// 2. on fading complete, LoadScene
StartFading
(
fadeType: SceneFadeType.FadeIn,
onFadingComplete: () => {
SceneManager.LoadScene (sceneType.ToString ());
}
);
}
public void LoadSceneWhenFadingCompleteAsync (ScenePreloader scenePreloader)
{
// 1 start preloading scene
// 2 on preloading complete, start fading
// 3 on fading complete LoadScene
scenePreloader.AddOnPreloadCompleteAndTriggerIfLoaded (
onPreloadComplete: () => {
StartFading (
fadeType: SceneFadeType.FadeIn,
onFadingComplete: () => {
scenePreloader.ActivateSceneWhenReady ();
}
);
}
);
}
private void StartFading (SceneFadeType fadeType, Action onFadingComplete)
{
Debug.LogWarning ("StartFAding ");
ScreenFader.instance.BeginFade (fadeType, onFadingComplete);
AudioMasterController.instance.StartFading (fadeType, null);
}
}
in ScenePreloader.cs
public class ScenePreloader : MonoBehaviour
{
Action<float> onPreloadRateChanged;
Action onPreloadComplete;
public AsyncOperation sceneLoader;
public bool isPreloadCompleted;
public void StartPreloadingScene (SceneType sceneType, LoadSceneMode loadSceneMode, Action<float> onPreloadRateChanged = null, Action onPreloadComplete = null)
{
this.onPreloadComplete = onPreloadComplete;
this.onPreloadRateChanged = onPreloadRateChanged;
StartCoroutine (PreloadSceneOperation (sceneType, loadSceneMode));
}
public IEnumerator PreloadSceneOperation (SceneType sceneType, LoadSceneMode loadSceneMode = LoadSceneMode.Single)
{
print ("PreloadSceneOperation sceneType = " + sceneType.ToString ());
sceneLoader = SceneManager.LoadSceneAsync (sceneType.ToString (), loadSceneMode);
sceneLoader.allowSceneActivation = false;
while (!sceneLoader.isDone) {
yield return null;
if (sceneLoader.progress >= 0.9f) {
print ("onPreloadComplete");
isPreloadCompleted = true;
if (onPreloadComplete != null) {
onPreloadComplete ();
}
break;
} else {
if (onPreloadRateChanged != null) {
onPreloadRateChanged (sceneLoader.progress);
}
}
}
}
public void ActivateSceneWhenReady ()
{
sceneLoader.allowSceneActivation = true;
}
public void AddOnPreloadCompleteAndTriggerIfLoaded (Action onPreloadComplete)
{
AddOnPreloadComplete (onPreloadComplete);
if (isPreloadCompleted) {
print ("isAlreadyLoadedTrigeringCallback");
onPreloadComplete ();
}
}
public void AddOnPreloadComplete (Action onPreloadComplete)
{
this.onPreloadComplete += onPreloadComplete;
}
public void SetOnLoadProgressValueChanged (Action<float> onLoadProgressValueChanged)
{
this.onPreloadRateChanged = onLoadProgressValueChanged;
}
}