I just can't seem to get while loops to work for me inside Unity. No matter how simple, Unity always freezes on me.
function LoadingLevel (level : int) {
yield;
//progressBar.transform.localScale = Vector3(loadingProgress, 0, 0);
async = Application.LoadLevelAsync(1);
while (!async.isDone) {
loadingProgress = parseInt(async.progress * 100);
}
//Application.LoadLevel(level);
}
This is what I'm currently having trouble with: it compiles, but freezes at runtime. What am I doing wrong?
You are failing to understand how async stuff works in Unity.
Your while loop needs to yield. This is because Unity programs are single-threaded, and yield is how you give time to other "coroutines".
while (!async.isDone)
{
loadingProgress = parseInt(async.progress * 100);
yield;
}
Here are the Unity docs on how this works:
http://docs.unity3d.com/Manual/Coroutines.html
Related
I had a problem in my program, and at first I thought it was related to coroutines. Every script that featured a coroutine worked slower in it's entirety. I later discovered this was the case because of a difference in FPS. In the editor, the FPS was 800, while it was 60 in the build. When I changed the code, so it would be 800 in both, everything worked fine.
This fixed everything, but this feels like a weird solution. It's a very simple project, so I don't mind for now, but I'd still like to know what's going on. Any ideas?
public IEnumerator BeInvincible()
{
isInvincible = true;
for (float i = 0; i < invistime; i += invistimedelta)
{
// Alternate between 0 and 1 scale to simulate flashing
if (sprite.color == new Color(1, 1, 1, 1))
{
sprite.color = new Color(1, 0, 0, 1);
}
else
{
sprite.color = new Color(1, 1, 1, 1);
}
yield return new WaitForSecondsRealtime(invistimedelta);
}
sprite.color = new Color(1, 1, 1, 1);
isInvincible = false;
}
I use fixedupdate for movement, and update for inputs. When I put inputs in fixedupdate (50 FPS), the game reacts the bad way, even when the game runs in base 800 fps.
Bad in what way?
In any case, if there is a problem at the time of code execution
Or a direct delay in performance, most likely the problem is from here
yield return new WaitForSecondsRealtime(invistimedelta);
The execution of a coroutine can be paused at any point using the yield statement. When a yield statement is used, the coroutine pauses execution and automatically resumes at the next frame. See the Coroutines documentation for more details.
And also you can review this
I have an array of prefabs i want to show a preview of in my custom editor. This works for gameobjects with a mesh renderer, for example the basic quad. However when i try to use AssetPreview.GetAssetPreview(tilePrefab.gameObject); on gameobject with a UnityEngine.UI.Image and a canvas renderer it always returns null.
Below is the part of the code that draws the previews.
public class MapEditor : Editor
{
public override void OnInspectorGUI()
{
for (int prefabIndex = 0; prefabIndex < TileSet.TilePrefabs.Count; prefabIndex++)
DrawIconTexture(prefabIndex, columnCount);
}
private void DrawIconTexture(int prefabIndex, int columnCount)
{
TileBehaviour tilePrefab = TileSet.TilePrefabs[prefabIndex];
Texture iconTexture = AssetPreview.GetAssetPreview(tilePrefab.gameObject);
Rect iconRect = GetIconRect(prefabIndex, columnCount);
if (iconTexture != null)
GUI.DrawTexture(iconRect, iconTexture);
else if (AssetPreview.IsLoadingAssetPreview(tilePrefab.gameObject.GetInstanceID()))
Repaint();
}
}
I know GetAssetPreview loads assets async, that is solved by the repaint. I have also tried
while(iconTexture == null)
iconTexture = AssetPreview.GetAssetPreview(tilePrefab.gameObject);
But that never finishes.
I also tried to use the texture of the Image
if (iconTexture == null)
iconTexture = tilePrefab.GetComponent<Image>().sprite.texture;
But that does not work because the sprite is in an atlas and all of the atlas is shown.
Edit: misread the question. I actually tried to use IsLoadingAssetPreview and IsLoadingAssetPreviews for few hours, without success. I ended up using a sad little trick
if (_previews.All(pair => pair.Value != null)) return;
_previews = GeneratePreviews();
I put that in the Update() loop of my EditorWindow. It's pretty hacky, I'm going to ask Unity if the AssetPreview methods are actually working.
Old answer, irrelevant:
You are not using the while loop and GetAssetPreview correctly.
GetAssetPreview will launch an asynchronous loading of the preview. To know if the preview is fully loaded you need to call AssetPreview.IsLoadingAssetPreview.
A pretty simple and brutal way of doing it (it will block execution) is :
var preview = AssetPreview.GetAssetPreview(item);
while (AssetPreview.IsLoadingAssetPreview(item.GetInstanceID())) {
// Loading
}
As usual, careful with while loops. Note that there is also a AssetPreview.IsLoadingAssetPreviews method with no parameters.
you should just use "using UnityEditor"
I recently started making a new game and I'm kinda an amateur coder.
var FlashlightOn : boolean = true;
function Update () {
ButtonClicket();
}
function ButtonClicket () {
if (Input.GetButton("Flashlight")) && FlashlightOn == true {
Destroy(Flahslight);
FlashlightOn = false;
}
else
{
Instantiate (Flashlight, Vector3(i * 0, 0, 0), Quaternion.identity);
FlashlightOn = true;
}
}
In the compiler error part it says I need to put brackets at the end and some other junk that doesn't need to be done. What am I doing wrong here?
Having run the code through the compiler myself, the errors it's giving are valid. Your code simply has a syntax problem and a typo:
if (Input.GetButton("Flashlight") && FlashlightOn == true) {
The close parenthesis for the if statement was in the wrong place.
Destroy(Flashlight);
You misspelled 'Flashlight'.
Also, i isn't defined isn't this code snippet, which is fine if it's a global variable, but you may want to double check it.
I'm learning unity scripting. But I don't understand the following :
static private var lastRecalculation = -1;
static function RecalculateValue () {
if (lastRecalculation == Time.frameCount)
return;
ProcessData.AndDoSomeCalculations();
}
I don't get the third line or the condition in the IF statement. I know its a bit amateur, but pls help.
Thank You.
This is from the Time.frameCount documentation. This example shows how to create a function that executes only once per frame, regardless of how many objects you attach your script to. I suspect though that this example is incomplete because it never updates lastRecalculation (or it was assumed you would do so in AndDoSomeCalculations() ).
The reason setting lastRecalculation = -1 initially is so this function runs during the first frame.
Working version:
static var lastRecalculation = -1;
static function RecalculateValue () {
if (lastRecalculation == Time.frameCount) {
return;
}
lastRecalculation = Time.frameCount;
Debug.Log (Time.frameCount);
//ProcessData.AndDoSomeCalculations();
}
function Update () {
RecalculateValue();
}
Attach this script to 2 different GameObjects and run it. You will only see unique frame values 1,2,3,4,5.... even though 2 GameObjects are each calling RecalculateValue()
Now comment out the return and run it again. Now the ProcessData portion of that code runs for both objects every frame and you'll see something like 1,1,2,2,3,3,4,4......
I can't understand why.
I already read lots of documents about it and there are lots of comments that
StopCoroutine(string) can only stop the coroutine starts with StartCoroutine(string)
the code is below.
In Class CharTouchControl.cpp
if( Input.GetKeyDown( KeyCode.Q ) )
{
_CharControl.StartCoroutine("useFever", 10);
}
_CharControl is a member of CharTouchControl and of course _CharControl is referencing the CharControl instance below.
And InClass CharControl
public IEnumerator useFever(float _duration = 10)
{
if( m_nUseFever < _nFeverMax )
{
Debug.Log("Stop!!");
StopCoroutine("useFever");
yield return new WaitForEndOfFrame();
}
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
yield return new WaitForEndOfFrame();
} // end of useFever
When m_nUseFever < _nFeverMax is true, i can see "Stop!!" log,
but the coroutine don't stop and simulate paticles.
anybody help for this?
Just as Jerdak mentioned, you should use yield break when your inside the Coroutine.
the coroutine will automatically stop when it finishes its code block. Using yield break, should send it to the end of the code block.
Additionally you could modify your code so that it only runs the code block if the condition is true. Ive done this in the example below. If the condition is false the coroutine will just wait for the end of the frame and then exit.
public IEnumerator useFever()
{
if( m_nUseFever > _nFeverMax )
{
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
}
yield return new WaitForEndOfFrame();
} //Coroutine automatically exits here
EDIT:
Dan Puzey brought up a good point, Are you sure shouldn't be using
Invoke("useFever",10) or InvokeRepeating ("useFever",10,1)
instead? From your code it looks like you just want to run the useFever function in 10 seconds. If thats the case, you should be invoking it instead of running it as a coroutine, and useFever should be a normal function.
Just for reference, there is also CancelInvoke("useFever")