I have a problem. Now I'm developing game in Unity when the condition is score 2. I want to wait for ten seconds before do the code change scene (Application.LoadLevel) (I'm using C# for develop)
But this code when score = 2 It will change to "scenea_5"
It can't wait for ten seconds
void OnTriggerEnter( Collider collider ){
if (collider.name == front_hztleft) {
audio.Play ();
}
if (collider.name == left_hztleft) {
audio.Play ();
score ++;
Debug.Log (string.Format (scoreSyntax, score));
endtime = DateTime.Now.ToString("HH:mm:ss");
InsertResult();
}
if (score == 2) {
StartCoroutine(Waiting());
Application.LoadLevel("scene_a5");
}
}
IEnumerator Waiting()
{
yield return new WaitForSeconds (10);
}
It can run and compile not without error.
Put the scene loading inside the Coroutine.
yield return new WaitForSeconds(10);
Application.LoadLevel("scene_a5");
Related
I tried to make a mob spawner which does followings:
1) spawns pre-defined amount of mobs with time interval of choice
2) checks if spawned gameobject destroyed if so spawns new ones till it reaches maximum amount again
Code works but i still think there can be improvements i want it to be mmo like slot spawner with pre defined maximum mob amount and intervals between every spawn
Issues im having:
1) at start works properly by 5 sec intervals between spawns but sometimes after you delete gameobject next spawn in line spawns instantly or very quickly
private void Start()
{
spawnedCount = gameObject.transform.childCount;
if (spawnedCount != 6)
isSpawning = false;
}
private void Update()
{
spawnedCount = gameObject.transform.childCount;
if (!isSpawning && spawnedCount < maxSpawnCount + 1) // check if should start spawn status and if coroutine currently working already isSpawning = false > yes you can can if you want to spawn or not isSpawning = True > no it is already spawning you cant check anymore and send requests
{
isSpawning = true; // set spawning status to true
StartCoroutine(DelayedSpawn(delayInterval));
}
}
IEnumerator DelayedSpawn(float delay)
{
yield return new WaitForSecondsRealtime(delay);
if (spawnedCount <= maxSpawnCount)
{
GetRandomZombie(); // gets random zombie prefab to instantiate
spawnedObj = Instantiate(PrefabToSpawn, new Vector3(gameObject.transform.position.x + Random.Range(-5f, 5), 0, gameObject.transform.position.z + Random.Range(-5f, 5)), transform.rotation);
spawnedObj.transform.parent = gameObject.transform;
}
if (spawnedCount <= maxSpawnCount )
StartCoroutine(DelayedSpawn(delayInterval));
else if (spawnedCount == 6)
{
isSpawning = false;
yield break;
}
}
I would do this like this. It seems cleaner.
Also I would suggest GetRandomZombie() method to return a prefab. That would be cleaner as well.
A reminder: The game object with script that has the coroutine method is disabled/deleted somehow, unity gives an error and coroutine stops. You can solve this like this:
private void OnDisable() //To prevent the error
{
StopAllCoroutines();
}
private void OnEnable() //To start the coroutine again whenever the spawner object is enabled again.
{
StartCoroutine(DelayedSpawn());
}
private IEnumerator DelayedSpawn()
{
while (true)
{
yield return new WaitForSecondsRealtime(delayInterval);
if (gameObject.transform.childCount <= maxSpawnCount)
{
GetRandomZombie(); // gets random zombie prefab to instantiate
spawnedObj = Instantiate(PrefabToSpawn, new Vector3(gameObject.transform.position.x + Random.Range(-5f, 5), 0, gameObject.transform.position.z + Random.Range(-5f, 5)), transform.rotation);
spawnedObj.transform.parent = gameObject.transform;
}
}
}
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.
in my project im trying to count the diferent objects and simulate a little animation, for example i have stars in my game, and i want to count the number of stars in the final of the game from 0 trough the number of stars the user got, so i did this:
public void youWin()
{
audio.Stop ();
StartCoroutine (activatePanel ());
}
IEnumerator activatePanel()
{
yield return new WaitForSeconds (3f);
pausePanel2.SetActive (true);
for (int i = 0; i <= stars; i++) {
yield return new WaitForSeconds (0.2f);
starText2.text = i + "";
}
}
my code worked well for 0.3f on the for loop wait for seconds, but it is too slow, i want it for 0.2f, but something strange happen sometimes it get like a bug and the first number seems to go back, it doesn't count right, someone know what is happening?
It very likely that the activatePanel function is being called from another place while it is already running or the script that contains this code is attached to multiple GameObjects and the activatePanel is again, being called by another function. You can use flag to stop this from happening.
If the coroutine function is already running, use yield break; to break out of it.
bool isRunning = false;
IEnumerator activatePanel()
{
//Exit if already running
if (isRunning)
{
yield break;
}
//Not running, now set isRunning to true then run
isRunning = true;
yield return new WaitForSeconds(3f);
pausePanel2.SetActive(true);
WaitForSeconds waitTime = new WaitForSeconds(0.2f);
for (int i = 0; i <= stars; i++)
{
yield return waitTime;
starText2.text = i.ToString();
}
//Done running, set isRunning to false
isRunning = false;
}
Well i solved it with all of you guys help, actually you all where right, i thaught i was calling the youWin function just 1 time, but i forgot this is unity and i called the youWin inside a trigerEnter function, that means that the object keep enter the triger function and called the youWin function, thank you all here is what i mean with that
Solved it with the bool entered
public class Victory : MonoBehaviour {
Manager gameManager;
// Use this for initialization
public AudioClip clip;
private AudioSource audio;
public Animator girl;
private bool entered;
void OnTriggerEnter(Collider c)
{
if (c.gameObject.tag == "Player" && !entered) {
gameManager.win = true;
audio.clip = clip;
audio.Play ();
gameManager.Ball.GetComponent<MoveBall> ().enabled = true;
girl.SetBool ("win",true);
entered = true;
gameManager.youWin ();
}
}
void Start () {
gameManager = GameObject.Find ("GameController").GetComponent<Manager> ();
audio = GetComponent<AudioSource> ();
entered = false;
}
// Update is called once per frame
void Update () {
}
}
I'm very new to unity engine, I am trying to use waitforseconds function and it doesn't seem to be working. Any help is much appreciated.
Code:
IEnumerator SetCountText(){
countText.text = "Count: " + count.ToString();
if (count >= 12) {
winText.text = "You win!";
yield return new WaitForSeconds (4);
NextLevel ();
}
}
I call the function in start() function by using startcoroutine( setcounttext());
Thanks in advance!
You mentioned you start your couroutine in the Start() function of the unity script. Start() is only called once, when the script has first initialized.
Considering your coroutine's logic, it only starts once and ends immediately.
If constant checking is desired, what you need is enclosing everything in a while loop:
IEnumerator SetCountText(){
while (count < 12) {
countText.text = "Count: " + count.ToString();
yield return new WaitForSeconds(1);
}
winText.text = "You win!";
yield return new WaitForSeconds (4);
NextLevel ();
}
What happens now is if the count variable is >= 12 then after 4 seconds, the level changes. Not sure if that is the effect you are trying to achieve.
I have discovered that this function does not work great all of the time , so I wrote my own simple class t o sort the problem. I have never had any problems counting seconds with this one.
public class MyCouroutine
{
public static IEnumerator WaitForRealSeconds(float duration)
{
float start = Time.realtimeSinceStartup;
while (Time.realtimeSinceStartup < start + duration)
{
yield return null;
}
}
}
Building a FSM for my Game AI class using C# in Unity3D game engine. I have 2 simple game objects right now, a Cube (AI) and a bullet (instantiates when a function is called, code below). Just building the foundation for a much more complex FSM, but early in the semester so building it as I'm learning.
My AI shoots out bullets in throws 5 bullets at a time, when bulletCount is 5 then it changes the state. So essentially I just want it to shoot 5 bullets, wait for a time I choose, reload, shoot 5 more, and continue same process. Basically what happens is perfectly what I want it to do first, as soon as it exits my IEnumerator, it shoots an infinite amount of bullets, even though the first time it did what I wanted.
AIClass
using UnityEngine;
using System.Collections;
public class AIClass : MonoBehaviour
{
public GameObject bullet;
int bulletCount;
float stunned;
public enum CombatAIStates
{
Firing = 0,
Stunned = 1,
Reloading = 2,
Following = 3,
Idle = 4
}
public CombatAIStates currentState = CombatAIStates.Firing;
void Update()
{
switch (currentState)
{
case CombatAIStates.Firing:
StartCoroutine (WaitMethod ());
if(bulletCount <= 5)
{
spawnBullets ();
Debug.Log ("Firing. ");
Debug.Log ("Bullet: ");
Debug.Log (bulletCount);
StartCoroutine (WaitMethod ());
++bulletCount;
}
if(bulletCount > 5)
{
currentState = CombatAIStates.Reloading;
}
break;
case CombatAIStates.Stunned:
Debug.Log ("Stunned.");
StartCoroutine(WaitMethod());
currentState = CombatAIStates.Firing;
//currentState = CombatAIStates.Firing;
break;
case CombatAIStates.Reloading:
Debug.Log ("Reloading.");
StartCoroutine (WaitMethod ());
currentState = CombatAIStates.Stunned;
break;
}
}
IEnumerator WaitMethod()
{
float waitTime = 10;
Debug.Log ("Before yield.");
yield return new WaitForSeconds (waitTime);
Debug.Log ("After yield.");
bulletCount = 0;
}
void spawnBullets()
{
Instantiate(bullet, transform.position, transform.rotation);
}
}
I suspect this is what you are trying to do, stripped down slightly for simplicity:
public int BulletCount = 0;
public enum CombatAIStates
{
Firing = 0,
Reloading = 1,
}
CombatAIStates currentState = CombatAIStates.Firing;
// Update is called once per frame
void Update () {
switch (currentState) {
case CombatAIStates.Firing:
if (BulletCount < 5) {
Debug.Log ("Firing: " + BulletCount);
++BulletCount;
} else {
currentState = CombatAIStates.Reloading;
StartCoroutine(Reload ());
}
break;
case CombatAIStates.Reloading:
// Nothing to do here, Reload() coroutine is handling things.
// Maybe play a 10 second animation here or twiddle thumbs
break;
}
}
IEnumerator Reload()
{
yield return new WaitForSeconds (10.0f);
BulletCount = 0;
//Now update the current combat state
currentState = CombatAIStates.Firing;
}
I didn't change much with the original code. I just moved a state change in to a Reload coroutine that switches back to Firing after 10 seconds and resets the bulletCount. Alternatively you could have the state change in the reload case of your switch. But instead of calling a coroutine just check if bulletCount >= 5, if not then reloading is done and you can switch back to firing.