Load Scene Unity - c#

I use the function Application.LoadLevelAsync (s); in my game but it just stops at 89%. Help me. It's my code:
public void LoadScenes (string s)
{
if (!quit) {
SoundController.PlaySound (soundGame.ButtomClick);
progressBars.gameObject.SetActive (true);
background.SetActive (true);
text.gameObject.SetActive (true);
async = Application.LoadLevelAsync (s);
async.allowSceneActivation = false;
StartCoroutine (DisplayLoadingScreen ());
}
}
IEnumerator DisplayLoadingScreen ()
{
while (!async.isDone) {
loadProgress = (int)(async.progress * 100);
text.text = "Loading Progress " + loadProgress + "%";
progressBars.size = loadProgress;
yield return null;
}
if (async.isDone) {
Debug.Log ("Loading complete");
async.allowSceneActivation = true;
}
}

When you set async.allowSceneActivation = false, the loading stops at 90% or 0.9. This is because unity saves the last 10% to actually show you the scene that has been loaded. So 0 to 0.9 is when the actual loading process takes place and the last .1% is for displaying the loaded scene.
So in your case, you are checking for async.isDone which would become true only when progress is 100% but you have also set async.allowSceneActivation = false which would stop the progress at 90%. What you might want to check is async.progress >=0.9f and then set your async.allowSceneActivation = true.
Reference: https://docs.unity3d.com/ScriptReference/AsyncOperation-progress.html

From my experience, AsyncOperation.progress can cap out at about 89% as you've discovered. It may look like it's stalled at that message, when really it's still loading for however long it needs. It won't ever reach 100% even when it's done though, so it's rather useless if you want to implement a loading bar.
As such, async.isDone might never become true.
As a workaround, you could set async.allowSceneActivation = true; sooner than later, ignoring async.progress altogether:
async = Application.LoadLevelAsync (s);
async.allowSceneActivation = true;
I tend to use a progress-agnostic rotating loading icon instead of a loading bar because of this issue.
On a side note that I haven't tested, others have said that this is an Editor-only issue; async.progress and async.isDone might actually work on standalone builds.

Related

Game slows down when printing text

I have implemented the dialog system from this Brackeys video in my project. Everything works perfectly, but when I have done the build for android I have seen that printing long texts slows the game down.
The code divides the sentence to be displayed in the UI into an array of characters and then prints each character one by one, with a small delay. I have been doing several tests and first I thought that the problem was the coroutine from where the characters were printed. But then I have removed the code from the coroutine and I have seen that the more characters it prints, the more the game slows down.
void FixedUpdate()
{
if(typeSentence)
{
if(t <= 0)
{
TypeChar();
t = charDelay;
}
t -= Time.fixedDeltaTime;
}
}
private void TypeChar()
{
GUIs[dialogue.UIIndex].dialogueText.text += charSentence[sentenceIndex];
sentenceIndex++;
if (sentenceIndex >= charSentence.Length)
{
typeSentence = false;
sentenceIndex = 0;
GUIs[dialogue.UIIndex].continueButton.SetActive(true);
}
}
I don't know if there is a more efficient way to do it, or if someone can explain to me what is happening and why it slows down so much.
Instead of triggering TypeChar() method in fixed update, you can convert TypeChar() to a Coroutine that can handle time more performing way.
private IEnumerator TypeChar()
{
while(sentenceIndex >= charSentence.Length)
{
if(typeSentence)
{
GUIs[dialogue.UIIndex].dialogueText.text += charSentence[sentenceIndex];
sentenceIndex++;
yield return new WaitForSeconds(charDelay);
}
}
typeSentence = false;
sentenceIndex = 0;
GUIs[dialogue.UIIndex].continueButton.SetActive(true);
}
And you can delete typeSentence variable completely if you do not change it out of scope.
And you can call it at Start instead of FixedUpdate.
private void Start()
{
StartCoroutine(nameof(TypeChar));
}

Coroutine only works the first time

I assume that there is something fundamental about coroutines that I don't understand because I cannot get my head around why this is happening.
I have this coroutine that works perfectly as intended the first time but completely fails the second time I try to use it.
public IEnumerator CharacterDialogue()
{
inDialogue = true;
playerController.enabled = false;
mouselook.enabled = false;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
dialogueMenu.SetActive(true);
yield return new WaitForEndOfFrame();
for (int i = 0; i < dialogueStrings.Length; i++)
{
while (!Input.GetKeyDown("e"))
{
yield return null;
}
yield return new WaitForEndOfFrame();
dialogueText.text = dialogueStrings[i];
}
yield return new WaitForEndOfFrame();
while (!Input.GetKeyDown("e"))
{
yield return null;
}
yield return new WaitForEndOfFrame();
QuestManager.Instance.SpawnDouxland();
inDialogue = false;
playerController.enabled = true;
mouselook.enabled = true;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
dialogueMenu.SetActive(false);
}
It is pretty straightforward: I disable the controls of my player and make the dialogue window pop. I then wait for the input of the player between each string of text so that he may read at his own pace. Once he's done reading I reactivate the controls and close the dialogue window.
This code works exactly like I want the first time but the second time it just goes through the for loop without waiting for the input.
What am I doing wrong here and why does it work the first time?
Edit:
Comments pointed out that the issue must be in the way I call the coroutine. This now makes sense to me as I use the same key (e) to call the coroutine. So maybe it reads the key as pressed and runs through the for loop. Bu why would it only do so the second time?
Here's the snippet of code where I call my coroutine:
if (hit.collider.CompareTag("Character"))
{
raycastedObj = hit.collider.gameObject;
CrosshairActive();
interactionManager.InteractiveFeedbackTextCall("CharacterQuest");
if (Input.GetKeyDown("e"))
{
Debug.Log("I have interacted with: " + hit.collider.gameObject.name + ".");
StartCoroutine(canvasAnimManager.CharacterDialogue());
}
}
Thanks to some comments I figured out what the issue was.
if (Input.GetKeyDown("e"))
{
Debug.Log("I have interacted with: " + hit.collider.gameObject.name + ".");
StartCoroutine(canvasAnimManager.CharacterDialogue());
}
I thought the idea of GetKeyDown was that it was triggered only once... there must be something I'm not getting. Anyways the issue was that this was called multiple times and it make the coroutine go through the loop even after I was finished with my dialogue.
I just added a little bool check to fix the issue:
if (Input.GetKeyDown("e") && !canvasAnimManager.inDialogue)
{
Debug.Log("I have interacted with: " + hit.collider.gameObject.name + ".");
StartCoroutine(canvasAnimManager.FoukiDialogue());
}
Cheers and thanks for the help!

How to wait a certain amount of time without freezing code in C#/Unity?

I'm making a practice game to get used to coding where you have to shoot a bird. When you run out of bullets, you need to press the 'r' key to reload your bullets. I want there to be a delay between when the button is pressed and when the bullets reload, but so far what I found is code that freezes everything (shown below). Is there a way to keep the code from freezing everything?
Summary: The code below freezes everything (the whole game) when pressing the 'r' button. Is there code I can use that won't freeze everything and will only wait 2 seconds before running the next action?
IEnumerator TimerRoutine()
{
if (Input.GetKeyDown(KeyCode.R))
{
yield return new WaitForSeconds(2); //Fix this, freezes everything
activeBullets = 0;
}
}
Use Coroutines To set This delay
if (Input.GetKeyDown(KeyCode.R) && isDelayDone) // defined isDelayDone as private bool = true;
{
// When you press the Key
isDelayDone = false;
StartCoroutine(Delay());
IEnumerator Delay()
{
yield return new WaitForSeconds(2);
isDelayDone = true;
activeBullets = 0;
}
}
Your problem is that you are waiting 2 seconds after the key press but not waiting for the actual key event it.
Here is a modified version of your method doing what you want.
IEnumerator TimerRoutine()
{
while(activeBullets == 0) // Use the bullets value to check if its been reloaded
{
if (Input.GetKeyDown(KeyCode.R)) // Key event check each frame
{
// Key event fired so wait 2 seconds before reloading the bullets and exiting the Coroutine
yield return new WaitForSeconds(2);
activeBullets = reloadBulletsAmount;
break;
}
yield return null; // Use null for the time value so it waits each frame independant of how long it is
}
}
(I know this has an accepted answer I just feel this method would be better)

Loading new scene in background

I'm creating a Unity application targeting the Samsung Gear VR. I currently have two scenes:
The initial scene
Second scene, with big quantity of data (it takes too much time to load the scene).
From the first scene, I want to load the second scene in background, and switch to it once it has been loaded. While the new scene is loading in background, the user should keep the ability to move their head to see any part of the VR environment.
I'm using SceneManager.LoadSceneAsync but it's not working:
// ...
StartCoroutiune(loadScene());
// ...
IEnumerator loadScene(){
AsyncOperation async = SceneManager.LoadAsyncScene("Scene", LoadSceneMode.Single);
async.allowSceneActivation = false;
while(async.progress < 0.9f){
progressText.text = async.progress+"";
}
while(!async.isDone){
yield return null;
}
async.allowSceneActivation = true;
}
With that code, the scene never changes.
I've tried this the typical SceneManager.LoadScene("name") in which case the scene changes correctly after 30 seconds.
This should work
while(async.progress < 0.9f){
progressText.text = async.progress.ToString();
yield return null;
}
Secondly, I've seen cases where isDone is never set to true, unless the scene has activated. Remove these lines:
while(!async.isDone){
yield return null;
}
On top of that, you are locking your code in that first while loop. Add a yield so the application can continue loading your code.
So your entire code looks like this:
IEnumerator loadScene(){
AsyncOperation async = SceneManager.LoadAsyncScene("Scene", LoadSceneMode.Single);
async.allowSceneActivation = false;
while(async.progress <= 0.89f){
progressText.text = async.progress.ToString();
yield return null;
}
async.allowSceneActivation = true;
}
The biggest culprit to your problem is the locking in the first while loop, though.

Sound stops working when function's added

When I add EndGame();
The sound stops playing when the game ends.
If I remove the function, the sound plays fine.
I tried adding the gover.Play to EndGame, but that didn't work either.
This bug doesn't really make sense to me as to why it's happening.
Happens in both Editor and on live device.
Thank you.
Here is my code:
Update() {
if (Input.GetMouseButtonDown(0))
{
}
else
{
AudioSource[] aSources = GetComponents<AudioSource> ();
perfecthit = aSources [0]; // Works
gover = aSources [1]; // Works without EndGame()
miss = aSources [2]; // Works
gover.Play ();
EndGame ();// Adding this makes gover.Play stop working
}
}
private void EndGame()
{
Social.ReportScore (scoreCount, "--", (bool success) => {
//SUCCESS or FAIL
});
PlayerPrefs.SetInt("byte", PlayerPrefs.GetInt("byte") + scoreCount / 2);
if (PlayerPrefs.GetInt ("score") < scoreCount)
PlayerPrefs.SetInt ("score", scoreCount);
gameOver = true;
endPanel.SetActive (true);
theStack[stackIndex].AddComponent<Rigidbody>();
stack.SetActive (false);
demoObj.SetActive (true);
}
I am assuming that it stops playing due to the AudioSource no longer being available.
Inside the EndGame() you are setting stack.SetActive (false);. If this AudioSource is attached to the object, then it will be no longer available. Especially considering you are re-obtaining your AudioSources At least 30 times a second!
With that I would also like to advice you to move your audio logic outside of the Update and maybe look into using the Start, or awake instead

Categories

Resources