Hello i load texture this code:
settingSplit this is string array.
IEnumerator DownloadLogos()
{
WWW www = new WWW(settingsSplit[0]);
while (www.progress < 1)
{
slider.GetComponent<UISlider>().value = www.progress;
if (slider.GetComponent<UISlider>().value > 0.880f)
{
slider.GetComponent<UISlider>().value = 1;
}
yield return new WaitForEndOfFrame();
}
yield return www;
if (www.error == null)
{
fadein = true;
model.GetComponent<Animation>().Play();
texTmp = www.textureNonReadable;
spr = Sprite.Create(texTmp, new Rect(0, 0, texTmp.width, texTmp.height), Vector2.zero, 50);
spr.texture.wrapMode = TextureWrapMode.Clamp;
mat.mainTexture = spr.texture;
decal.sprite = spr;
yield return new WaitForEndOfFrame();
slider.SetActive(false);
float multipier = 1;
if (settingsSplit[2] != null)
{
multipier = float.Parse(settingsSplit[2]);
}
decal.transform.localScale = new Vector3(decal.transform.localScale.x * multipier,
decal.transform.localScale.y * multipier, decal.transform.localScale.z);
BuildDecal(decal);
}
Work fine but
When texture load MainThread stop for some time (1-2 second).
How i can fix this ?
Thanks!
I don't know if you have solved this, but I was facing the same problem. The problematic line is
spr = Sprite.Create(texTmp, new Rect(0, 0, texTmp.width, texTmp.height), Vector2.zero, 50);
Because the creation of the Sprite takes a while and runs in the main thread, which causes your game to freeze.
My solution was to use a RawImage instead of an Image to display the loaded texture, just delete the mentioned line and replace
decal.sprite = spr;
with
decal.texture = www.texture;
and set the rest of properties/values you want to use.
I hope this helps someone having this problem.
WaitForEndOfFrame resumes at the end of the frame. I'm fairly certain if you yield for the end of the frame, at the end of the frame, you still wont progress to the next frame. Just yield null and you will resume the next frame.
while (www.progress < 1)
{
slider.GetComponent<UISlider>().value = www.progress;
if (slider.GetComponent<UISlider>().value > 0.880f)
{
slider.GetComponent<UISlider>().value = 1;
}
yield return null;
}
Related
I'm creating some lines of many diffent rectangles. Both lines and rectangles are created by code.
I do some logic with the rectangle's vertices and update that information in my instantiated rectangles. This works really well.
Then on each rectangle I have 2 scripts, one storing data and the other storing a corutine to make the rectangle flash or stop flashing when certain conditions are met after lines and rectangles move possitions.
It does not work, it might have to be done with some other outside scripts and even diccionaries or lists, but as I'm new to coroutines I would like to know if it's possible to do it from each instantiated object by simply checking those bool and int variables as they change during the game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class rectanguloAnim : MonoBehaviour{
rectangulo rect; //script containing data from this rectangle
Color32 colOrig;
Material material;
IEnumerator currentFlashCoroutine;
void Start()
{
rect = GetComponent<rectangulo>();
colOrig = GetComponent<rectangulo>().colorOriginal;
material = GetComponent<Renderer>().material;
}
void Update()
{
// this bool and int change when the line and rect are interacted with
if (rect.isIntermediate == true || rect.activeDirection != 0)
{
if (currentFlashCoroutine != null)
{
StopCoroutine(currentFlashCoroutine);
}
currentFlashCoroutine = ChangeColor(material, colOrig, Color.white);
StartCoroutine(currentFlashCoroutine);
}
else
{
if (currentFlashCoroutine != null)
{
StopCoroutine(currentFlashCoroutine);
}
}
}
IEnumerator ChangeColor(Material toChange, Color32 startColor, Color32 endColor)
{
float t = 0;
float colorDuration = Random.Range(2.49f, 6f);
while (t < colorDuration)
{
float timeDuration = Random.Range(.55f, .95f);
if (t > timeDuration)
{
t = 0;
}
t += Time.deltaTime;
toChange.color = Color.Lerp(startColor, endColor, t / colorDuration);
yield return null;
}
}
}
I think you should rather make your field
private Coroutine currentFlashCoroutine;
and then use
currentcurrentFlashCoroutine = StartCoroutine(ChangeColor(material, colOrig, Color.white);
and then do
if(currentFlashCoroutine != null)
{
StopCoroutine (currentFlashCoroutine);
currentFlashCoroutine = null;
}
Btw in doubt you could also use StopAllCoroutines since in your use case you seem to anyway only have a single routine in your class ;)
The second issue here is that you are stopping and starting a new routine every frame as long the condition is true.
You would rather do somthing like
void Update()
{
// this bool and int change when the line and rect are interacted with
if (rect.isIntermediate || rect.activeDirection != 0)
{
// only start a new routine if there is not already one running
if(currentFlashCoroutine == null)
{
currentFlashCoroutine = StartCoroutine(ChangeColor(material, colOrig, Color.white);
}
}
else
{
if(currentFlashCoroutine != null)
{
StopCoroutine (currentFlashCoroutine);
currentFlashCoroutine = null;
}
}
}
IEnumerator ChangeColor(Material toChange, Color32 startColor, Color32 endColor)
{
var t = 0f;
var colorDuration = Random.Range(2.49f, 6f);
while (t < colorDuration)
{
var timeDuration = Random.Range(.55f, .95f);
if (t > timeDuration)
{
t = 0;
}
t += Time.deltaTime;
toChange.color = Color.Lerp(startColor, endColor, t / colorDuration);
yield return null;
}
currentFlashRoutine = null;
}
I'm trying to code a behaviour for my boss where it charges at the player but before charging it is supposed to flicker a bit to show intent of charge. Below is how I am achieving this in Update():
if (chargeTimer <= 0)
{
if (!returnToStart)
{
StartCoroutine(TankSpriteFlicker());
if (chargeNow)
{
transform.position = Vector3.MoveTowards(transform.position, chargeTarget, Time.deltaTime * chargeSpeed);
// Target reached? If so, start moving back to the original position
if (Vector3.Distance(transform.position, chargeTarget) <= Mathf.Epsilon)
{
returnToStart = true;
this.chargeTimer = this.chargeRate;
}
chargeNow = false;
}
}
else
{
transform.position = Vector3.MoveTowards(transform.position, tankStartPosition, Time.deltaTime * returnSpeed);
// Original position reached? If so, start moving to the target
if (Vector3.Distance(transform.position, tankStartPosition) <= Mathf.Epsilon)
{
returnToStart = false;
this.chargeTimer = this.chargeRate;
}
}
}
else
{
this.chargeTimer -= Time.time;
}
IEnumerator TankSpriteFlicker()
{
for (int i = 0; i <= 2; i++)
{
tankSprite.color = Color.red;
yield return new WaitForSeconds(0.1f);
tankSprite.color = startColor;
yield return new WaitForSeconds(0.1f);
}
chargeNow = true;
}
chargeTarget is a fixed value of chargeTarget = new Vector3(-2.5f, transform.position.y, transform.position.z);
The problem with this is that it charges, but stops midway and then charges again.
Also as time passes by the flickering becomes very random and it starts flickering during and after a charge..
Here is the problem in action:
https://gfycat.com/latefrigidbullmastiff-rivalsofaether
I can't explain any of this behaviour and cant fix it, any help would be appreciated.
This is not how coroutines work
Lets look at just these lines:
StartCoroutine(TankSpriteFlicker());
if (chargeNow) { ... }
You start a coroutine, that's fine, but your next instruction asks if the coroutine has been completed (as chargeNow is not set to true until the last line of the coroutine). This cannot and will not ever be true at this point in the execution because coroutines are fundamentally "go do this stuff later" and later is not now.
You need to move these additional pieces of logic (the stuff that happens "after" the coroutine) to the end of the coroutine.
I just don't know how to write the if part. The rest is just instantiate position and quaternion stuff.... Probably.
I want to know if the GameObject rocketspawnblue and GameObject rocketspawnred are gone, so I can spawn the next pair until all the pairs in the loop are spawned.
This is my spawning coroutine I put in Start(). however that's probably won't work because it needs to be check every frame until i take all my rockets....
for (int i = 1; i < 6; i++)
{
yield return new WaitForSeconds(1);
GameObject rocketspawnblue = Instantiate(
rocketblue,
new Vector3(Random.Range(-15, 15), (Random.Range(-15, 15))),
Quaternion.identity);
SpriteRenderer rocketscolor1 = rocketspawnblue.GetComponent<SpriteRenderer>();
//rocketscolor.color = colors[Random.Range(0,colors.Length)];
rocketscolor1.color = Color.blue;
GameObject rocketspawnred = Instantiate(
rocketred,
new Vector3(Random.Range(-15, 15), (Random.Range(-15, 15))),
Quaternion.identity);
SpriteRenderer rocketscolor2 = rocketspawnred.GetComponent<SpriteRenderer>();
//rocketscolor.color = colors[Random.Range(0, colors.Length)];
rocketscolor2.color = Color.red;
}
Use a List as a field to track the rockets:
private List<GameObject> rockets;
At the beginning of Start(), instantiate the list:
rockets = new List<GameObject>();
In your coroutine, clear the list with Clear then use Add to add rockets to your list. After you're done adding, use WaitWhile to loop until there are no rockets left. We'll write a method called AnyRocketsLeft that returns true if there are any that are not yet destroyed.
After the WaitWhile, use WaitForSeconds to wait for a second to give time between batches.
for (int i = 1; i < 6; i++)
{
rockets.Clear();
GameObject rocketspawnblue = Instantiate(
rocketblue,
new Vector3(Random.Range(-15, 15), (Random.Range(-15, 15))),
Quaternion.identity);
SpriteRenderer rocketscolor1 = rocketspawnblue.GetComponent<SpriteRenderer>();
//rocketscolor.color = colors[Random.Range(0,colors.Length)];
rocketscolor1.color = Color.blue;
rockets.Add(rocketspawnblue);
GameObject rocketspawnred = Instantiate(
rocketred,
new Vector3(Random.Range(-15, 15), (Random.Range(-15, 15))),
Quaternion.identity);
SpriteRenderer rocketscolor2 = rocketspawnred.GetComponent<SpriteRenderer>();
//rocketscolor.color = colors[Random.Range(0, colors.Length)];
rocketscolor2.color = Color.red;
rockets.Add(rocketspawnred);
yield return new WaitWhile(() => AnyRocketsLeft());
yield return new WaitForSeconds(1);
}
// ran out of rockets
// set up the "next level" prompt, etc. here
To check if any rockets are not yet destroyed, we can check their activeInHierarchy property. Just loop through the list of rockets and return true if you find any, and false otherwise.
private bool AnyRocketsLeft() {
foreach (int i = 0 ; i < rockets.count ; i++) {
if (rockets[i].activeInHierarchy) return true;
}
return false;
}
If you're using Linq, you can use List.Any():
private bool AnyRocketsLeft() {
return rockets.Any(o => o.activeInHierarchy);
}
public IEnumerator Screen1()// coroutine
{
LaptopCamera.Play ("Laptop");
p_material_LaptopScreen.mainTexture =p_text_BlueScreen[0];
p_transform_CorporatePV.localScale = new Vector3 (0.5f, 0.5f, 0.5f);
yield return new WaitForSeconds (2.5f);
p_gameobject_Training_Laptop[0].SetActive (true);
p_gameobject_Training_Laptop[1].SetActive (true);
p_material_LaptopTraining.mainTexture = p_text_Tarining [0];
yield return new WaitForSeconds (2.5f);
p_audioSource_Galderma.Stop ();
p_audioSource_Galderma.clip = p_audioclip_link;
p_audioSource_Galderma.Play ();
yield return new WaitUntil(() => p_audioSource_Galderma.isPlaying == false);
P_GameObject_UI.SetActive (true);
p_gameoject_CheckList_Button.SetActive (true);
p_int_break_scene1 = 2;
}//p_int_break_scene1
public void PlayPause()//play and pause button
{
if(p_int_play_pause == 0)
{
p_int_play_pause = 1;
p_image_PlayPause.sprite = p_sprite_Pause;
Time.timeScale = 0;
AudioSource[] go = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
foreach (AudioSource g in go)
{
if (g.isPlaying)
{
g.Pause();
pausedSources.Add(g);
}
}
}//p_int_play_pause
else if (p_int_play_pause == 1)
{
p_int_play_pause = 0;
p_image_PlayPause.sprite = p_sprite_Play;
if (p_int_check_list_opened == 0)
{
Time.timeScale = 1;
foreach (AudioSource source in pausedSources)
{
source.Play ();
}
pausedSources.Clear ();
}
}//p_int_play_pause
I am calling the coroutine screen1.I have play pause button to play and pause the game. I want the coroutine to wait still my audio plays fully.
yield return new WaitUntil(() => p_audioSource_Galderma.isPlaying == false);
When i pause the game that will pause the audio source
g.Pause();
then the p_audioSource_Galderma.isPlaying == false); and the coroutine complete with out playing the audio source.
Is there a way to coroutine to wait still my audio plays out completely even if i pause the game will not effect this.
I do not want to use yield return new WaitForSeconds since that is frame dependent.Is there a another way to coroutine wait still audio plays completely even if i pause the game.
yield return new WaitForSeconds (p_audioSource_Galderma.clip.length);
will not work for since there is more delay needed to play the animation and show the text.Is there a way to delay still audio plays fully
Since you are using Time.timeScale = 0 to pause, you can use:
yield return new WaitUntil(
() => !p_audioSource_Galderma.isPlaying
&& Time.timeScale != 0
);
You may need to change how you unpause, changing Time.timeScale after you play the AudioSources:
foreach (AudioSource source in pausedSources)
{
source.Play ();
}
Time.timeScale = 1;
Sidenote, you don't need to write out something == false, you can just do !something and it is often easier to read.
If you change yield return new WaitUntil(() => p_audioSource_Galderma.isPlaying == false); to yield return new WaitForSeconds(p_audioSource_Galderma.clip.length); you will achieve the same effect.
I even prefer it this way, since audio is independent from frames rendering.
I develop Web Player application.
I need to download *.png image and use this image in scene.
Download code:
public Material mat;
string fullFilename;
Texture2D texTmp;
Sprite spr;
void Awake()
{
fullFilename = "http://585649.workwork.web.hostingtest.net/Images/Logo.png";
StartCoroutine(Download());
texTmp = new Texture2D(50, 50);
spr = Sprite.Create(texTmp, new Rect(0, 0, texTmp.width, texTmp.height), Vector2.zero, 100);
spr.texture.wrapMode = TextureWrapMode.Clamp;
mat.mainTexture = spr.texture;
}
IEnumerator Download()
{
WWW www = new WWW(fullFilename);
yield return www;
www.LoadImageIntoTexture(texTmp);
}
This work fine,but after loading scene uploaded picture appears after a while.
How i can fix it ?
Sorry for my English :)
Thanks!
This is natural. Because you download picture from internet, and there are some delays. So you add loading screen or wait all scene until picture is downloaded by you. But i think it is not good solution because you only load picture. Maybe disabling other buttons/interactive elements before starting download and then enable them after download is finished is good solution.
For example:
void Awake()
{
fullFilename = "http://585649.workwork.web.hostingtest.net/Images/Logo.png";
disableButtons();
StartCoroutine(Download());
texTmp = new Texture2D(50, 50);
spr = Sprite.Create(texTmp, new Rect(0, 0, texTmp.width, texTmp.height), Vector2.zero, 100);
spr.texture.wrapMode = TextureWrapMode.Clamp;
mat.mainTexture = spr.texture;
}
IEnumerator Download()
{
WWW www = new WWW(fullFilename);
yield return www;
www.LoadImageIntoTexture(texTmp);
enableButtons();
}