So the problem here is that i'm trying to delay the sceneload and show a win screen for a few seconds, unlock the next level(which works btw) and fade the player into a portal. Instead it just loads the next scene instantly when i enter my portal. Can't seem to figure it out myself.
`public float menuCounter; public int nextSceneLoad;
void Start()
{
nextSceneLoad = SceneManager.GetActiveScene().buildIndex 1;
}
void Update()
{
menuCounter -= Time.deltaTime;
if (menuCounter is >= 0.1f and <= 0.2f)
{
SceneManager.LoadScene(nextSceneLoad);
}
if (menuCounter is >= 1.8f and <= 1.9f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.9f);
}
if (menuCounter is >= 1.7f and <= 1.8f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.8f);
}
if (menuCounter is >= 1.6f and <= 1.7f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.7f);
}
if (menuCounter is >= 1.5f and <= 1.6f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.6f);
}
if (menuCounter is >= 1.4f and <= 1.5f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.5f);
}
if (menuCounter is >= 1.3f and <= 1.4f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.4f);
}
if (menuCounter is >= 1.2f and <= 1.3f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.3f);
}
if (menuCounter is >= 1.1f and <= 1.2f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.2f);
}
if (menuCounter is >= 1f and <= 1.1f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.1f);
}
if (menuCounter is >= 0.2f and <= 1f)
{
GameObject.Find("Sprite").GetComponent<SpriteRenderer>().enabled = false;
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
if (SceneManager.GetActiveScene().buildIndex == 4)
{
Debug.Log("You Completed ALL Levels");
//Show Win Screen or Somethin.
}
else
{
//Move to next level
//Setting Int for Index
if (nextSceneLoad > PlayerPrefs.GetInt("levelAt"))
{
PlayerPrefs.SetInt("levelAt", nextSceneLoad);
}
menuCounter = 2f;
GameObject.Find("Player").GetComponent<Movement>().enabled = false;
GameObject.Find("Player").GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Static;
GameObject.Find("StageClear").GetComponent<TextMeshProUGUI>().enabled = true;
GameObject.Find("StageClearSound").GetComponent<AudioSource>().enabled = true;
GameObject.Find("MusicControl").GetComponent<AudioSource>().enabled = false;
}
}
}
} `
I've tried adding a coroutine and Invoke with a delay but couldn't get it to work.
CodePudding user response:
I would definitely use a routine instead of Update
for this.
Main reason: The Update
runs all the time. So it is pretty much possible that you run through all of the conditions before you collide since menuCounter
will with or without collision eventually reach <= 0.2f
=> directly jumps into
SceneManager.LoadScene(nextSceneLoad);
Another reason: With your setup yo might easily skip a condition and maintenance will be really bad if you want to adjust the times or add/remove steps ;)
I would probably rather do something like this
int currentScene;
int nextSceneLoad;
void Start()
{
currentScene = SceneManager.GetActiveScene().buildIndex;
nextSceneLoad = currentScene 1;
}
private bool isAlreadyLoading;
// "OnTriggerEnter2D" can return IEnumerator in which case
// Unity will automatically tread and run it as a coroutine
IEnumerator OnTriggerEnter2D(Collider2D other)
{
// if already loading ignore
if(isAlreadyLoading) yield break;
// if not player ignore
if (!other.CompareTag("Player")) yield break;
if (currentScene == 4)
{
Debug.Log("You Completed ALL Levels");
//Show Win Screen or something
}
else
{
if (nextSceneLoad > PlayerPrefs.GetInt("levelAt"))
{
PlayerPrefs.SetInt("levelAt", nextSceneLoad);
// I would also save this
PlayerPrefs.Save();
}
// In general "Find" is very expensive!
// you already seem to have a reference to the player since it collided with you!
other.GetComponent<Movement>().enabled = false;
other.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Static;
GameObject.Find("StageClear").GetComponent<TextMeshProUGUI>().enabled = true;
GameObject.Find("StageClearSound").GetComponent<AudioSource>().enabled = true;
GameObject.Find("MusicControl").GetComponent<AudioSource>().enabled = false;
// set flag to ignore any later collisions
isAlreadyLoading = true;
// store these ONCE
var sprite = GameObject.Find("Sprite").GetComponent<SpriteRenderer>();
var material = sprite.material;
// if I'm not completely mislead I think you want to fade out your sprite
// from fully white opaque to fully transparent
var startColor = Color.white;
var targetColor = new Color(1f, 1f, 1f, 0f);
// Coudld be a const or even better adjustable via the Inspector
float fadeDuration = 2f;
// Every frame move the timePassed forward and interpolate the sprite color
for(var timePassed = 0f; timePassed < fadeDuration; timePassed = Time.deltatime)
{
// will be a factor moving 0 -> 1 within fadeDuration
var factor = timePassed / fadeDuration;
// interpolate startColor -> targetColor within fadeDuration
sprite.color = Color.Lerp(statColor, targetColor, factor);
// "pause" routine here, render this frame and continue from here in next frame
yield return null;
}
sprite.enabled = false;
// wait an additional second
yield return new WaitForSeconds(1f);
// finally load the scene
SceneManager.LoadScene(nextSceneLoad);
}
}