i have two objects(the same character, but, in different functions) which i want change the character when animation stop and when it runs triggered by a click. For example, I have the Kick_Player where there is the animation triggered by the click, and when the Kick_Player ends the animation, i want it automatically changes to Player_Stopped. The poses are different each other, 'cause this i need to do these changes.
I tried something with this.MyAnimator.GetCurrentAnimatorStateInfo(0).IsName("My_Animation") but, i got unsuccessful tries. Is there a way to do that ?
public class TapController : MonoBehaviour {
Animator Anim;
public GameObject CharacterToController; //Kick_Player
public GameObject CharacterToBeStopped; //Player_Stopped
void Start(){
Anim = CharacterToController.GetComponent<Animator>();
CharacterToBeStopped.SetActive(false);
}
void Update(){
if(input.GetMouseButtonDown(0)){
if(!CharacterToController.activeSelf){
CharacterToController.SetActive(true);
}
Anim.Play("Kick_Ball");
if(!this.Anim.GetCurrentAnimatorStateInfo(0).IsName("Kick_Ball") {
CharacterToController.SetActive(false);
CharacterToBeStopped.SetActive(true);
}
}
}
I made this code to test, but it doesn't work
Using the IsName function requires that you prefix the base layer name of the animation state before the actual animation state.
The default base name is usually "Base Layer"
if(!this.Anim.GetCurrentAnimatorStateInfo(0).IsName("Base Layer.Kick_Ball")
Note that you have to do that outside your if(input.GetMouseButtonDown(0)){ otherwise that will never get chance to be checked.
I've seen reports of IsName not working for some people so if you do that but still have issues, consider doing it another way.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (!CharacterToController.activeSelf)
{
CharacterToController.SetActive(true);
}
Anim.Play("Kick_Ball");
StartCoroutine(PlayAndWaitForAnim(Anim, "Kick_Ball"));
}
}
const string animBaseLayer = "Base Layer";
int animHash = Animator.StringToHash(animBaseLayer + ".Kick_Ball");
public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
{
targetAnim.Play(stateName);
//Wait until we enter the current state
while (targetAnim.GetCurrentAnimatorStateInfo(0).fullPathHash != animHash)
{
yield return null;
}
float counter = 0;
float waitTime = targetAnim.GetCurrentAnimatorStateInfo(0).length;
//Now, Wait until the current state is done playing
while (counter < (waitTime))
{
counter += Time.deltaTime;
yield return null;
}
//Done playing. Do something below!
Debug.Log("Done Playing");
CharacterToController.SetActive(false);
CharacterToBeStopped.SetActive(true);
}
Related
I'd like to move up and down a certain part of a 2D-enemy-spaceship via DoTween's DOMoveY-shortcut. So far so good - it almost works... but when I try to change the value of the transitionTarget during gameplay the animation doesn't change accordingly.
So the problem seems to be that the code doesn't update the Tweener. Now I'd like to know what do I have to change of my code so that the Tweener gets updated when I change the value (via inspector) of the transitionTarget during gameplay?
This is the code:
public float transitionTarget = 0f;
private Tweener transitionTweener;
private bool toggleTransition = true;
void Start()
{
TransitionTween(transitionTarget);
transitionTweener.OnRewind(() => {
Debug.Log("<<- Transition played backward and completed!");
toggleTransition = true;
});
transitionTweener.OnComplete(() => {
Debug.Log("->> Transition played and completed!");
if (toggleTransition) toggleTransition = false;
else toggleTransition = true;
});
}
void TransitionTween(float targetY) {
transitionTweener = this.transform.DOMoveY(targetY, 3f, false)
.SetEase(Ease.Linear)
.SetAutoKill(false)
.SetId("tran")
.Pause();
}
void Update() {
if (toggleTransition) {
transitionTweener.PlayForward();
}
else {
transitionTweener.PlayBackwards();
}
}
Solution 1:
Assuming that it suffices for you to have the updated transitionTarget take effect at the moment when the animation-cycle starts, there is a simple solution to your problem
utilizing the ChangeEndValue method.
Moreover I suggest a simplification:
Instead of rewinding the tween manually, I suggest that you use
SetLoops(-1, LoopType.Yoyo)
The same amount of control can be achieved by utilizing the OnStepCompleted callback.
public class EnemySpaceship : MonoBehaviour {
private Tweener transitionTweener;
public float transitionTarget = 0f;
private Vector3 Endvalue => new Vector3(0.0f, transitionTarget, 0.0f);
void Start()
{
transitionTweener = transform.DOMove(Endvalue, 3f, false)
.SetOptions(AxisConstraint.Y)
.SetEase(Ease.Linear)
.SetLoops(-1, LoopType.Yoyo)
.SetAutoKill(false);
transitionTweener.OnStepComplete(OnStepCompleted);
}
private void OnStepCompleted() {
if (transitionTweener.CompletedLoops() % 2 == 0) {
Debug.Log("->> Transition played and completed!");
transitionTweener.ChangeEndValue(Endvalue);
} else {
Debug.Log("<<- Transition played backward and completed!");
}
}
}
Solution 2:
If you do need the animation to use the updated target value instantly while the animation is still playing, then we need more clarifications.
Consider the following cases for the time of the change of the transitionTarget value:
during transition from the start location to the transitionTarget.
the new transitionTarget value is yet to be reached
the new transitionTarget value has already been surpassed
during transition back from the transitionTarget to the start location.
I will ignore case 2. entirely, because the spaceship will have to return to the start location anyways, and that location which never changes - so in this solution like in the first, the change will only take effect, as soon as the loop is complete when the start location has been reached.
regarding 1., I suppose we can generally assume, that the movement of the spaceship should be continuous, so we will avoid any sort of "teleportation".
Unfortunately the ChangeEndValue method rewinds the tween.
So if we want to use this method† for case 1.1, we will have to manually "scrub" the tween to the correct position, which can be achieved with the Goto method.
However, it appears that the Goto method does not work properly with infinite Loops (which should be reported as issue). The solution will just execute a single loop, still using LoopType.Yoyo (the number of loops has to be 2 to go forth and back once), and restart the tween afterwards (which is a bit closer to the sample code from the question).
In case of 1.2 we just scrub forward to the position in time, where we move back to the start-position, while we are at the same position, which is 2 * duration - transitionTweener.position
so without further ado, the solution:
public class EnemySpaceship : MonoBehaviour {
private Tweener transitionTweener;
public float transitionTarget = 0f;
private float lastValue;
private Vector3 startValue;
private Vector3 Endvalue => new Vector3(0.0f, transitionTarget, 0.0f);
private const float duration = 3f;
void Start() {
lastValue = transitionTarget;
startValue = transform.position;
transitionTweener = transform.DOMove(Endvalue, duration)
.SetOptions(AxisConstraint.Y)
.SetEase(Ease.Linear)
.SetLoops(2, LoopType.Yoyo)
.SetAutoKill(false);
transitionTweener.OnComplete(RestartTween);
}
private void RestartTween() {
transitionTweener.ChangeEndValue(Endvalue);
transitionTweener.Restart();
}
private void Update() {
if (lastValue != transitionTarget && transitionTweener.CompletedLoops() == 0) {
var t = duration * (transform.position.y - startValue.y) / (transitionTarget - startValue.y);
if (t > duration) {
transitionTweener.Goto(2 * duration - transitionTweener.position, true);
} else {
transitionTweener.ChangeEndValue(Endvalue);
transitionTweener.Goto(t, true);
}
lastValue = transitionTarget;
}
}
}
Note:
To comply with your spec, that the tween should update when the transitionTarget is changed from within the inspector, the solution compares lastValue with transitionTarget every frame in the update method.
To avoid this in the real application, you could probably do the following:
rename the update method to something like UpdateTarget, so you trigger it manually.
use a property to encapsulate transitionTarget and use the properties setter to invoke UpdateTarget
additionally invoke UpdateTarget when the tween is completed: transitionTweener.OnComplete(RestartTween);
†An alternative option not considered in this Answer would be to recreate the tweens in the event of a change of transitionTarget.
A simpler solution than IARI's (but perhaps less efficient) is to kill the current tween when you need to transition and create a new one with the new destination.
In a small simulation game (A.I. spaceship shooter) that I am developing, I am trying to come up with an effective shield function or IEnumerator which can be called or started and do multiple things:
Count down the shield's cooldown if it is above zero
Activate the shield for the set duration (5 seconds) if the cooldown has ended
Deactivate the shield when the duration expires
However, I run into some problems when trying this using only an Ienumerator. I have been able to use IEnumerators to count down timers and cooldowns before but trying to do both a cooldown and duration doesn't seem to work as Unity does not let me WaitForSeconds twice without leaving the IEnumerator.
Similarly, each ship has a turret and inside of that turret is an IEnumerator which fires or counts down its cooldown, whichever is needed for the situation.
// Fire continuously if in range and we have more than 1 shot left
// Otherwise, reload for (rate) seconds and reset shots left
public IEnumerator Fire(Vector2 target) {
firing = true;
if (cooldown <= 0) {
if (bullets > 0) {
// Fire a bullet
bullets--;
// Instatiate the bullet
}
} else {
// Reload
cooldown = rate;
bullets = count;
}
} else {
yield return new WaitForSeconds(1);
cooldown--;
}
firing = false;
yield break;
}
The Fire Coroutine is called by using the firing flag to check whether it is running or not and if it is not call
var fire = turret.Fire(shootTarget + offset);
if (!turret.firing && InRange() == true) {
StartCoroutine(fire);
}
every second or so if the ship is alive and we have a target.
I do think that my current use of the IEnumerator is not recommended because it has to be called at least every second, but with how small the environment is at the moment, it doesn't appear to be an issue.
Any help is appreciated.
Quick code without coroutines, no idea if it works in game. Should give you some idea though, I hope.
public class Shield : MonoBehaviour {
public float duration;
public float cooldown;
public float lastActivated;
public bool IsActivated => (lastActivated - (Time.time - duration)) > 0;
public bool onCoolDown => (lastActivated - (Time.time - cooldown)) > 0;
public void Activate(){
if(onCoolDown) return;
lastActivated = Time.time;
}
void LateUpdate(){
if(IsActivated) //Show shield effects, blahblah
else //Do nothing, blahblah
}
}
My goal is to write one script that I can use on different game objects and it should have specific variables tied to it on that game object only without affecting other scripts in the process.
For example, if I take this script and put it on two game objects each game object should have their own unique variable value in that same script.
If my question is not clear enough, I'm more than happy to elaborate further.
I have a good understanding of the Unity Editor, however, I'm pretty new to C# so I don't think it's unreasonable that I made a rookie mistake somewhere in my code.
The way I've got things setup is that I have two separate scripts:
Fighting controls the values like the Team, Health, Attack Damage, Cool Down, Cooling down and Snap
TrigDetect controls the detection of a trigger being activated as a result of an enemy entering the trigger radius.
The problem I'm currently having lies in the TrigDetect script I guess.
It should also be noted that an empty attached to each game object in question contains both of these scripts and is tagged as "Troop".
TrigDetect
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrigDetect : MonoBehaviour
{
//public GameObject[] Enemy;
bool once = false;
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Troop"))
{
//Debug.Log("Entered");
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Troop"))
{
//Debug.Log("Exitted");
}
}
void OnTriggerStay(Collider other)
{
if (other.CompareTag("Troop"))
{
Fighting self = GetComponent<Fighting>();
GameObject g = GameObject.Find("Detection");
Fighting fScript = g.GetComponent<Fighting>();
//Enemy = GameObject.FindGameObjectsWithTag("Troop");
//Debug.Log("Staying");
//Debug.Log(Enemy);
//Debug.Log(self.Health);
//Debug.Log(fScript.Health);
if (once == false)
{
Debug.Log("I am the team:" + self.Team);
Debug.Log("I have detected the team:" + fScript.Team);
once = true;
}
if (self.Team != fScript.Team)
{
if (self.CoolingDown == false)
{
self.CoolingDown = true;
fScript.Health -= self.AttackDamage;
}
else
{
self.CoolDown -= Time.deltaTime;
if (self.CoolDown <= 0)
{
self.CoolingDown = false;
self.CoolDown = self.original;
}
}
}
}
}
}
Fighting
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fighting : MonoBehaviour
{
public int Team = 1;
public int Health = 100;
public int AttackDamage = 10;
public float CoolDown = 2;
public float original = 2;
public bool CoolingDown = false;
public bool Snap = false;
// Update is called once per frame
void Update () {
if (Snap == true || Health <= 0)
{
//Destroy(gameObject, .5f);
Destroy(transform.parent.gameObject);
}
if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);
}
}
The expected result when I move one game object into the trigger radius of the other is that they should both start subtracting Health from each other based on the AttackDamage value. They should do this every time the CoolingDown value is false. When an attack is executed, it's flipped to true and a timer starts, when the timer is done it's flipped back to false.
However, upon moving the two objects into each other's radius', the first object has its health taken away as expected and then proceeds to do nothing until it's health reaches 0 then it dies because of the object attacking it. The object attacking is successfully attacking the other object but, is still not being affected by the object it's attacking.
Basically, Find(name) only returns the first instance of anything by that name, thus your g = Find(name) is almost guaranteed to never be the object related to your trigger/collision condition. The OnTriggerStay(Collider other) already gives you the 'other' collider that's in your trigger zone, so use it. :)
Replace this:
GameObject g = GameObject.Find("Detection");
Fighting fScript = g.GetComponent<Fighting>();
with this:
Fighting fScript = other.GetComponent<Fighting>();
To your question header:
Every instaced (non-static) value is allways unique to the according component and thereby to the according GameObject it is attached to. You might want to refrase the question because this is actually not your issue.
The problem is that when you do
GameObject.Find("Detection");
it actually finds the same object both times: Namely the first one in the hierarchy. So in one of of the two components you find your own empty object and skip the rest in
if(self.Team != FScript.Team)
.. you could try to use
other.Find("Detection");
instead to only search in the according context .. However, you should not use Find at all!
It is very performance intense
You should allways reuse references and not search them over and over again
You don't need it in your case
Since you say both scripts are attached to the same object you can simply use
GetComponent<Fighting>();
and you can do so already in Awake and reuse the reference instead:
private Fighting myFighting;
private void Awake()
{
myFighting = GetComponent<Fighting>();
}
Than for the collision you don't have to use Find either because you already have the reference of the object you collide with: other.gameObject. I don't know your entire setup but you can search for the component either downwards in the hierachy
// the flag true is sued to also find inactive gameObjects and components
// leave it without parameters if you don't want this
var otherFighting = other.GetComponentInChildren<Fighting>(true);
or searcg upwards in the hierachy
var otherFighting = other.GetComponentInParent<Fighting>(true);
or if you already know you collide exactly with the correct GameObject anyway simply use
var otherFighting = other.GetComponent<Fighting>();
I will use the latter in my example.
Than cheking the health all the time in Update is a huge perfomance issue. You should rather have a method e.g. TakeDamage and do your check only if your health is actually changed:
Fighting
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fighting : MonoBehaviour
{
public int Team = 1;
public int Health = 100;
public int AttackDamage = 10;
public float CoolDown = 2;
public float original = 2;
// you don't need that flag see below
//public bool CoolingDown = false;
public bool Snap = false;
private void Update()
{
// you might also put this in a callback instead of update at some point later
if(Snap == true)
{
Destroy(transform.parent.gameObject);
}
// Note: this also makes not muh sense because if you destroyed
// the parent than you cannot instantiate it again!
// use a prefab instead
if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);
}
public void TakeDamge(int DamageAmount)
{
Health -= DamageAmount;
if (Health > 0) return;
Destroy(transform.parent.gameObject);
}
}
Another performance issue in general: Even if Start, Update etc are empty, if they are present in your script Unity will call them. So if you don't use them then completely remove them to avoid that useless overhead.
So I would have
TrigDetect
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrigDetect : MonoBehaviour
{
bool once = false;
private Fighting myFighting;
private void Awake()
{
myFighting = GetComponent<Fighting>();
}
void OnTriggerStay(Collider other)
{
// if wrong tag do nothing
if (!other.CompareTag("Troop")) return;
Fighting fScript = other.GetComponent<Fighting>();
// here you should add a check
if(!fScript)
{
// By using the other.gameObject as context you can find with which object
// you collided exactly by clicking on the Log
Debug.LogError("Something went wrong: Could not get the Fighting component of other", other.gameObject);
}
if (!once)
{
Debug.Log("I am the team:" + self.Team);
Debug.Log("I have detected the team:" + fScript.Team);
once = true;
}
// if same team do nothing
if (self.Team == fScript.Team) return;
// you don't need the CoolingDown bool at all:
self.CoolDown -= Time.deltaTime;
// if still cooling down do nothing
if(self.CoolDown > 0) return;
fScript.TakeDamage(self.AttackDamage);
self.CoolDown = self.original;
}
}
Currently I'm simply trying to change the sprites candle from unlit to lit when the player has 'picked up' both the candle and the matches and the candle will 'go out' after a certain amount of time. However, when the space bar is pressed the transition from unlit to lit isn't occurring, even though the debug log is returning true when it should. I'm posting here to get some guidance as I have spent most of the day looking online and literally have no idea how to proceed.
Basically the images I am trying to transition between are two different images which are in the sprites folder under assets.
This is what I've got so far.
//the two sprites transition
public Sprite unlitCandle;
public Sprite litCandle;
private SpriteRenderer spriteRenderer;
bool pickUpMatches = false;
bool pickUpCandle = false;
float timeRemaining =5;
bool candleLit = false;
// Use this for initialization
void Start () {
spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite == null)
spriteRenderer.sprite = unlitCandle;
}
// Update is called once per frame
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.CompareTag("Matches"))
{
collision.gameObject.SetActive(false);
pickUpMatches = true;
}
if (collision.gameObject.CompareTag("UnlitCandle"))
{
collision.gameObject.SetActive(true);
pickUpCandle = true;
}
}
public void CandleTimer()
{
if (candleLit == true)
{
timeRemaining = 5;
timeRemaining -= Time.deltaTime;
if (timeRemaining <= 0)
{
candleLit = false;
spriteRenderer.sprite = unlitCandle;
}
}
}
public void ChangeSprite()
{
if (spriteRenderer.sprite == unlitCandle)
{
spriteRenderer.sprite = litCandle;
}
}
void Update () {
if (pickUpCandle == true && pickUpMatches == true)
{
//Debug.Log(candleLit);
if (Input.GetKey(KeyCode.Space) && !candleLit)
{
CandleTimer();
ChangeSprite();
Debug.Log(timeRemaining);
candleLit = true;
//Debug.Log(candleLit);
}
}
}
}
Try comparing with a method like equals() instead of == in
spriteRenderer.sprite == unlitCandle
Because right now you are just comparing references and not the objects.
At least I think thats the problem.
There are a few possible issues with your code. First, you are calling changeSprite at the top of Update, which means that it is unconditionally being called every frame. Therefore, after a single frame of your candle being unlit, it will immediately change its sprite to litCandle.
I assume that the reason you are calling changeSprite every frame is in order to process the timer if you have a lit candle already. Really, you should move the code to process the timer (your whole second if statement in changeSprite) to a separate function and name it something like processCandleTimer. Call that at the top of Update and save the changeSprite method to only be called on the keypress.
Lastly, the issue that I suspect is giving you the most trouble is that you aren't resetting your timer, timeRemaining. The first time you light the candle the timer will go down to 0 after the 5 seconds pass. Every time changeSprite is run after that, you will change the sprite to litCandle in the first if statement and then immediately change it back to unlitCandle because the timer is 0 in the second. To remedy this, you need to add a line like timeRemaining = 5.0f; when the key is hit.
I have a game with four scenes, a menu scene, a loading scene, and two game scenes. All is well, when I am transitioning from my menu scene to my game scenes, but whenever I transition from my game scenes back to my menu scene or reload the game scene, the loading scene simply stops responding. I get a warning message that says "NetworkManager detected a script reload in the editor. This has caused the network to be shut down" only when I try to reload the currently active game scene. This issue is also present when I play in the build! I used print statements to trace down where my code stopped running, and I figured out that it was the Yield Return New WaitForSeconds() which caused the game to freeze. Why is that?
I have two scripts that controls transitioning. One simple script called on UIButtons for telling the second more complex script called in the preload scene to load the scene it's supposed to load and create animations. I have made sure that I was loading on to the correct scene, and that all of the scenes were added into my build settings.
The following pictures show the loading scene not responding. The first picture shows what happens when I try to reload the current game scene, and the second picture shows what happens when I try to load the menu scene:
My Loading Scene Script:
public class LoadingScreenManager : MonoBehaviour {
[Header("Loading Visuals")]
public Image loadingIcon;
public Image loadingDoneIcon;
public Text loadingText;
public Image progressBar;
public Image fadeOverlay;
[Header("Timing Settings")]
public float waitOnLoadEnd = 0.25f;
public float fadeDuration = 0.25f;
[Header("Loading Settings")]
public LoadSceneMode loadSceneMode = LoadSceneMode.Single;
public ThreadPriority loadThreadPriority;
[Header("Other")]
// If loading additive, link to the cameras audio listener, to avoid multiple active audio listeners
public AudioListener audioListener;
AsyncOperation operation;
Scene currentScene;
public static int sceneToLoad = -1;
// IMPORTANT! This is the build index of your loading scene. You need to change this to match your actual scene index
static int loadingSceneIndex = 1;
public static void LoadScene(int levelNum) {
Application.backgroundLoadingPriority = ThreadPriority.High;
sceneToLoad = levelNum;
SceneManager.LoadScene(loadingSceneIndex);
}
void Start() {
if (sceneToLoad < 0)
return;
fadeOverlay.gameObject.SetActive(true); // Making sure it's on so that we can crossfade Alpha
currentScene = SceneManager.GetActiveScene();
StartCoroutine(LoadAsync(sceneToLoad));
}
private IEnumerator LoadAsync(int levelNum) {
ShowLoadingVisuals();
yield return null;
FadeIn();
StartOperation(levelNum);
float lastProgress = 0f;
// operation does not auto-activate scene, so it's stuck at 0.9
while (DoneLoading() == false) {
yield return null;
if (Mathf.Approximately(operation.progress, lastProgress) == false) {
progressBar.fillAmount = operation.progress;
lastProgress = operation.progress;
}
}
if (loadSceneMode == LoadSceneMode.Additive)
audioListener.enabled = false;
ShowCompletionVisuals();
//THE PRINT STATEMENT WORKS FINE RIGHT HERE! The value of waitOnLoadEnd is only 1
yield return new WaitForSeconds(waitOnLoadEnd);
//THE PRINT STATEMENT STOPS RUNNING RIGHT HERE!
FadeOut();
yield return new WaitForSeconds(fadeDuration);
if (loadSceneMode == LoadSceneMode.Additive)
SceneManager.UnloadScene(currentScene.name);
else
operation.allowSceneActivation = true;
}
private void StartOperation(int levelNum) {
Application.backgroundLoadingPriority = loadThreadPriority;
operation = SceneManager.LoadSceneAsync(levelNum, loadSceneMode);
if (loadSceneMode == LoadSceneMode.Single)
operation.allowSceneActivation = false;
}
private bool DoneLoading() {
return (loadSceneMode == LoadSceneMode.Additive && operation.isDone) || (loadSceneMode == LoadSceneMode.Single && operation.progress >= 0.9f);
}
void FadeIn() {
fadeOverlay.CrossFadeAlpha(0, fadeDuration, true);
}
void FadeOut() {
fadeOverlay.CrossFadeAlpha(1, fadeDuration, true);
}
void ShowLoadingVisuals() {
loadingIcon.gameObject.SetActive(true);
loadingDoneIcon.gameObject.SetActive(false);
progressBar.fillAmount = 0f;
loadingText.text = "LOADING...";
}
void ShowCompletionVisuals() {
loadingIcon.gameObject.SetActive(false);
loadingDoneIcon.gameObject.SetActive(true);
progressBar.fillAmount = 1f;
loadingText.text = "LOADING DONE";
}
}
Script on UIButtons that call the above script:
public class LoadingSceneButton : MonoBehaviour {
public void LoadSceneWithLoadingScreen(int sceneNumber){
if (sceneNumber < 0 || sceneNumber >= SceneManager.sceneCountInBuildSettings) {
Debug.LogWarning ("Can't Load Scene, because It Doesn't Exist!");
}
LoadingScreenManager.LoadScene (sceneNumber);
}
}
(1) Don't use "print", please use this:
Debug.Log("fadeDuration is ....... " , fadeDuration.ToString("f4");
add that line of code just before you call FadeOut and also please add it inside FadeOut
(2) problems with CrossFadeAlpha
Please note that CrossFadeAlpha is extremely difficult to use! It's a real pain! It only works on UnityEngine.UI.Graphic, and it's tricky when used with coroutines.
public static void FadeOut(this Graphic g)
{
g.GetComponent<CanvasRenderer>().SetAlpha(1f);
g.CrossFadeAlpha(0f,.15f,false);
}
(3) problems with loading a scene in Unity5 !!!
Yes there is a
known issue
where it gets stuck on 0.9. Maybe this is the main problem at hand.
check out ... http://answers.unity3d.com/answers/1146173/view.html
and ... http://answers.unity3d.com/answers/1073667/view.html
Some basic working code example....
public void LaunchSoundboard()
{
StartCoroutine(_soundboard());
}
private IEnumerator _soundboard()
{
Grid.music.Duck();
yield return new WaitForSeconds(.2f);
AsyncOperation ao;
ao = UnityEngine.SceneManagement
.SceneManager.LoadSceneAsync("YourSceneName");
while (!ao.isDone)
{
yield return null;
}
// here, the new scene IS LOADED
SoundBoard soundBoard = Object.FindObjectOfType<SoundBoard>();
if(soundBoard==null) Debug.Log("WOE!");
soundBoard.SomeFunctionInSoundboardScript();
}
Note that you wait on ".isDone", rather than watch the float.
(4) #You actually have to have a scene called "preload", which ONLY preloads.
unfortunately the menu scene can not be your preload scene.
You have to actually have a separate preload scene which does nothing but that, "preload".
Note that any "game managers" you have must be on the preload scene. It's a bit annoying but that's how it is.
The purpose of the "preload" scene is to hold any game managers you have.
The only scene that you mark "don't destroy on load" must be only the "preload" scene. It's that simple.
It's a bit of a nuisance but very simple and reliable.