Guys When I gave it something tagged with pizza first coroutine doesn't stop How Can I stop it?
Please help me guys I couldn't find the way. What should I do? Btw I am new sorry for bad posting:/
I'm trying to make a pizza restaurant game. So customer will sit then waitforpizza coroutine will start if we give tag with pizza waitforpizza coroutine should start then eatpizza will start but my waitforpizza doesn't stop.
IEnumerator EAT, PAY, WAIT;
private void Start()
{
EAT = EatPizza();
WAIT = WaitForPizza();
PAY = WaitForTheCase();
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Pizza"))
{
canEat = true;
}
if (other.gameObject.CompareTag("Out"))
{
Destroy(this.gameObject);
}
}
void Update()
{
if (isEating)
{
if (Vector3.Distance(transform.position, agent.destination) <= 1f)
{
anim.SetTrigger("sit");
isEating = false;
}
}
if (!isEating && !isPaying && !isOut && !canEat)
{
StartCoroutine(WaitForPizza());
}
if (!isEating && !isPaying && !isOut && canEat)
{
StopCoroutine(WAIT);
StartCoroutine(EatPizza());
}
if (isPaying)
{
isEating = false;
anim.SetTrigger("walk");
agent.destination = checkoutTarget.position;
if (Vector3.Distance(transform.position, agent.destination) <= 1f)
{
anim.SetTrigger("wait");
if (ifCashier)
{
//throw money
isPaying = false;
isOut = true;
}
if (!ifCashier)
{
StartCoroutine(WaitForTheCase());
}
}
}
if (isOut)
{
anim.SetTrigger("walk");
isEating = false;
isPaying = false;
agent.destination = outTarget.position;
}
if (canEat)
{
StopCoroutine(WAIT);
}
}
IEnumerator WaitForTheCase()
{
anim.SetTrigger("wait");
yield return new WaitForSeconds(randomFloatWait);
angry.SetActive(true);
isEating = false;
isPaying = false;
isOut = true;
}
IEnumerator EatPizza()
{
angry.SetActive(false);
StopCoroutine(WaitForPizza());
happy.SetActive(true);
yield return new WaitForSeconds(randomFloatWait);
happy.SetActive(false);
isEating = false;
isPaying = true;
isOut = false;
}
IEnumerator WaitForPizza()
{
while (!canEat)
{
yield return new WaitForSeconds(randomFloatWait);
angry.SetActive(true);
isEating = false;
isPaying = false;
isOut = true;
}
}
First, define WAIT as Coroutine then when you want to start waiting use WAIT = StartCoroutine(WaitForPizza()); and when you want to finish it use StopCoroutine(WAIT);.
Related
I'm working on some script and I have the following two coroutines:
private IEnumerator blockTimer(float duration)
{
blocking = true;
yield return new WaitForSeconds(duration);
blocking = false;
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
yield return null;
}
private IEnumerator dashTimer(float duration)
{
dashing = true;
yield return new WaitForSeconds(duration);
dashing = false;
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
yield return null;
}
They are called in my update function upon different inputs:
private void Update()
{
if (dashing || blocking || movementCooldown) return;
if (Input.GetButtonDown("Dash") & (movementX!=0||movementY!=0))
{
sprite.color = Color.red;
StartCoroutine(dashTimer(dashTime));
}
if (Input.GetButtonDown("Block"))
{
sprite.color = Color.blue;
StartCoroutine(blockTimer(blockTime));
}
}
Obviously, these two coroutines are very similar. I've been playing around with some different ways to generalize them. I just can't figure out how I'm meant to pass a bool as a parameter into one general coroutine and set it from within. I can set the booleans by pointing directly to them but how do I make it so I can call on a parameter bool and update it during the coroutine? Any help is much appreciated!
You can use a call back function as a parameter, like this :
private IEnumerator GenericTimer(float duration, Func<bool, bool> callback)
{
callback(true);
yield return new WaitForSeconds(duration);
callback(false);
movementCooldown = true;
sprite.color = Color.green;
yield return new WaitForSeconds(duration);
movementCooldown = false;
sprite.color = Color.white;
}
And then you just make a lambda that assign this value to either blocking or dashing variables:
private void Update()
{
if (dashing || blocking || movementCooldown) return;
if (Input.GetButtonDown("Dash") & (movementX!=0||movementY!=0))
{
sprite.color = Color.red;
StartCoroutine(GenericTimer(dashTime, (bool value) => dashing = value));
}
if (Input.GetButtonDown("Block"))
{
sprite.color = Color.blue;
StartCoroutine(GenericTimer(blockTime, (bool value) => blocking = value));
}
}
public class green : MonoBehaviour
{
private AudioSource source;
public AudioClip sound;
static int result = 0;
// Use this for initialization
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("a");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
Thread.Sleep(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
yield return new WaitForSeconds(3f * 60f);
gm.life -= 1;
Debug.Log(gm.life + "값");
source.Stop();
Debug.Log("z");
if (gm.life >= 0)
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
}
// Update is called once per frame
public void Update()
{
if (result == 1 && gm.checkeat == true)
{
Debug.Log("e");
gm.life += 1;
Debug.Log("j");
Debug.Log(gm.life + "값");
source.Stop();
gm.checkeat = false;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
if (result == 2 && gm.checkshit == true)
{
Debug.Log("f");
gm.life += 1;
Debug.Log("o");
Debug.Log(gm.life + "값");
source.Stop();
gm.checkshit = false;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
else if (result == 3 && gm.checksleep == true)
{
Debug.Log("g");
gm.life += 1;
Debug.Log(gm.life);
Debug.Log(gm.life + "값");
source.Stop();
gm.checksleep = false;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
}
}
public class gm : MonoBehaviour
{
static public int life = 0;
static public bool checkeat = false;
static public bool checkshit = false;
static public bool checksleep = false;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void eating(string eat)
{
Debug.Log(life + "값");
checkeat = true;
}
public void shitting(string shit)
{
Debug.Log(life + "값");
checkshit = true;
}
public void sleeping(string sleep)
{
Debug.Log(life + "값");
checksleep = true;
}
}
when i click a button , program stops for a while and then works... i think it is because of thread or something...
please share your opinion..
.when i click a button , program stops for a while and then works... i think it is because of thread or something...
please share your opinion..
Stop using :
Thread.Sleep(timeToWait);
This stalls the entire thread, in this case Unity completely from running.
Since your using routines anyway, use this instead :
yield return new WaitForSeconds(timeToWait);
And change this line :
int timeToWait = ran.Next(1, 50) * 1000;
To this :
int timeToWait = ran.Next(1, 50);
Good Day! I have this code but I have an error, for example (I set two players me, and 1 computer). I take the first turn, and the dice respawn with a value of 4 (just an example), the game piece then move from 1st to 4th tile when I touch the screen, when computer turns, it also move from 1st to 4th tile (because I set the result to 4 just an example). Now its my turn again, the dice never respawn and it doesn't wait to touch the screen if (Input.GetMouseButtonDown(0)) and move again by 4...
public class singlePlay : MonoBehaviour {
//Player
public GameObject[] playerprefab;
//Player Clone
public GameObject[] playerprefabC;
//Game Cards and Dice
public GameObject[] situationCard;
public GameObject dice;
int diceresult;
//Game Cards and Dice clone
public GameObject diceclone;
public int currentPlayer;
public int compPlayer;
public int playerTurn;
public string compPlayerstring;
public string playerTurnstring;
//GUI Boolean
bool play = false;
//Game Boolean
bool pieces = false;
bool giveturn = false;
bool myturn = false;
bool diceSpawn = false;
bool moving = false;
bool routine = false;
bool checking = false;
bool compturn = false;
//icon1
public GameObject[] icon;
//population
int[] population = new int[3];
//Tile
public GameObject[] Tile;
int[] playerTile = new int[3]; //current location
int[] playerTileUp = new int [3]; // updated location after dice roll
bool endTurn = false;
void Update ()
{
if (giveturn == true) {
int h = 0;
Giveturn(h);
giveturn = false;
}
if (play == true) {
if (pieces == true){
SpawnPlayer();
pieces = false;
}
if (myturn == true){
compturn = false;
if(diceSpawn == true) {
dice.transform.position = new Vector3(0,0,-1);
diceclone = Instantiate(dice, dice.transform.position, Quaternion.identity) as GameObject;
diceSpawn = false;
}
if (Input.GetMouseButtonDown(0))
{
Debug.Log("click");
diceresult = 4;
Destroy(diceclone);
moving = true;
Updateposition(diceresult);
}
}
else
{
Debug.Log("comp");
myturn = false;
diceresult = 4;
moving = true;
Updateposition(diceresult);
}
}
}
void Giveturn(int k)
{
Debug.Log("" + k);
currentPlayer = k;
if (k == playerTurn) {
Debug.Log("Yes");
compturn = false;
myturn = true;
diceSpawn = true;
moving = false;
}
else
{
Debug.Log("No");
compturn = true;
myturn = false;
moving = false;
}
}
void Updateposition(int diceresult)
{
if (moving == true) {
playerTileUp[currentPlayer] = playerTile[currentPlayer] + diceresult;
Debug.Log("" + playerTileUp[currentPlayer]+ " " +currentPlayer);
routine = true;
StartCoroutine(MyMethod());
}
moving = false;
}
IEnumerator MyMethod()
{
if (routine == true) {
if (myturn == true) {
compturn = false;
}
else
{
myturn = false;
}
int f = playerTile[currentPlayer] + 1;
Debug.Log(" " + currentPlayer );
while (f <= playerTileUp[currentPlayer]) {
Debug.Log("waiting");
yield return new WaitForSeconds(1);
Debug.Log(" " + Tile[f]);
playerprefabC[currentPlayer].transform.position = Tile[f].transform.position;
Debug.Log(" " + currentPlayer);
f++;
}
checking = true;
TrapCheck();
}
routine = false;
}
void TrapCheck()
{
if (checking == true) {
if (playerTileUp[currentPlayer] == 8) {
Debug.Log("Trap spawning");
Instantiate(situationCard[0], situationCard[0].transform.position, Quaternion.identity);
population[currentPlayer] = population[currentPlayer] -1;
}
playerTile[currentPlayer] = playerTileUp[currentPlayer];
Endturn();
myturn = false;
compturn = false;
checking = false;
}
}
void Endturn()
{
currentPlayer++;
Debug.Log(" " + currentPlayer);
if (currentPlayer > compPlayer) {
currentPlayer = 0;
}
Giveturn(currentPlayer);
}
}
There are few things that I could see wrong there already. First while the coroutine is running, it seems you are not preventing the update from running since play remains true. In TrapCheck, you call EndTurn which call GiveTurn and sets myTurn (true) and compTurn (false) booleans. But those two are reset in TrapCheck, myTurn is set back to false. You need to rethink the logic of your class.
A solution would be to use delegate. This would remove many of your boolean that you set and reset. Here is a basic idea:
Action currentUpdate;
bool playerTurn = true;
void Start(){
SetTurn();
}
void Update(){
if(currentUpdate != null)currentUpdate();
}
void SetTurn(){
// Prepare initial setting for moving
if(playerTurn == true){ currentUpdate = PlayerTurn; }
else{ currentUpdate = CompTurn; }
playerTurn = !playerTurn;
}
void PlayerTurn(){
// Check input
// Get dice value
currentUpdate = Move;
}
void CompTurn(){
// Get dice value
currentUpdate = Move;
}
void Move(){
if(position != target){
}else{
SetTurn();
}
}
This is fairly simplified but once you get the thing about delegate (maybe you already know), this will make it all so much more flexible.
I want to play three sounds simultaneously, but second sound must play after one seconds, third sound after two seconds. I have this code:
private void Play()
{
AxWindowsMediaPlayer player1 = new AxWindowsMediaPlayer();
player1.CreateControl();
AxWindowsMediaPlayer player2 = new AxWindowsMediaPlayer();
player2.CreateControl();
AxWindowsMediaPlayer player3 = new AxWindowsMediaPlayer();
player3.CreateControl();
player1.URL = "sounds\\1.wav";
player1.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player2.URL = "sounds\\2.wav";
player2.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player3.URL = "sounds\\3.wav";
player3.Ctlcontrols.play();
Why all this sounds are playing in one time after two seconds?
I ended up using SharpDX (available via NuGet packages SharpDX
and SharpDX.XAudio2.
An example of its usage can be found in one of my GitHub projects: 2DAI
You can hear the various sounds overlapping in this screen recording as well.
Playing a sound:
var backgroundMusicSound = new AudioClip(#".\Assets\Sounds\Music\Background.wav" /*Sound path*/, 1.0 /* Volumne*/, true /*Loop Forever?*/)
backgroundMusicSound.Play();
The class that I pieced together:
public class AudioClip
{
private XAudio2 _xaudio = new XAudio2();
private WaveFormat _waveFormat;
private AudioBuffer _buffer;
private SoundStream _soundstream;
private SourceVoice _singleSourceVoice;
private bool _loopForever;
private bool _isPlaying = false; //Only applicable when _loopForever == false;
private bool _isFading;
private string _wavFilePath; //For debugging.
private float _initialVolumne;
public AudioClip(string wavFilePath, float initialVolumne = 1, bool loopForever = false)
{
_loopForever = loopForever;
_wavFilePath = wavFilePath;
_initialVolumne = initialVolumne;
var masteringsound = new MasteringVoice(_xaudio); //Yes, this is required.
var nativefilestream = new NativeFileStream(wavFilePath,
NativeFileMode.Open, NativeFileAccess.Read, NativeFileShare.Read);
_soundstream = new SoundStream(nativefilestream);
_waveFormat = _soundstream.Format;
_buffer = new AudioBuffer
{
Stream = _soundstream.ToDataStream(),
AudioBytes = (int)_soundstream.Length,
Flags = BufferFlags.EndOfStream
};
if (loopForever)
{
_buffer.LoopCount = 100;
}
}
public void Play()
{
lock (this)
{
if (_loopForever == true)
{
if (_isPlaying)
{
if (_isFading)
{
_isFading = false;
_singleSourceVoice.SetVolume(_initialVolumne);
}
return;
}
_singleSourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
_singleSourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
_singleSourceVoice.SetVolume(_initialVolumne);
_singleSourceVoice.Start();
_isPlaying = true;
return;
}
}
var sourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
sourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
sourceVoice.SetVolume(_initialVolumne);
sourceVoice.Start();
}
public void Fade()
{
if (_isPlaying && _isFading == false)
{
_isFading = true;
(new Thread(FadeThread)).Start();
}
}
private void FadeThread()
{
float volumne;
_singleSourceVoice.GetVolume(out volumne);
while (_isFading && volumne > 0)
{
volumne -= 0.25f;
volumne = volumne < 0 ? 0 : volumne;
_singleSourceVoice.SetVolume(volumne);
Thread.Sleep(100);
}
Stop();
}
public void Stop()
{
if (_loopForever == true)
{
if (_singleSourceVoice != null && _isPlaying)
{
_singleSourceVoice.Stop();
}
_isPlaying = false;
_isFading = false;
}
else
{
throw new Exception("Cannot stop overlapped audio.");
}
}
}
It should also be notes that loading the sounds can be a heavy process, so if you are doing it a lot then you might want to cache them as I did:
private Dictionary<string, AudioClip> _audioClips { get; set; } = new Dictionary<string, AudioClip>();
public AudioClip GetSoundCached(string wavFilePath, float initialVolumne, bool loopForever = false)
{
lock (_audioClips)
{
AudioClip result = null;
wavFilePath = wavFilePath.ToLower();
if (_audioClips.ContainsKey(wavFilePath))
{
result = _audioClips[wavFilePath];
}
else
{
result = new AudioClip(wavFilePath, initialVolumne, loopForever);
_audioClips.Add(wavFilePath, result);
}
return result;
}
}
I'd like to know how I can pause and unpause menu from the same button using the mouse pointer when I click on it.
Lets say I have this. C#
void Update () {
if (Button_Pause.OnPointerClick()) {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
active = !active;
}
}
public void PauseGame()
{
Button_Pause = Button_Pause.GetComponent<Button> ();
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = true;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = false;
}
In the first line, where I call the OnPointerClick I'm just guessing because I don't know what to do. What I've searched around, using click to show something it's having a TimeScale or something like that.
¿Can anyone help moi? Please.
Add a listener for your button and in your pause script set timescale to zero to pause the game
[SerializeField] private Button MyButton = null; // assign in the editor
void Start() { MyButton.onClick.AddListener(() => { pause();});
}
void pause(){
if (Time.timeScale == 1)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
I managed to solve the issue. It might not be efficient but it does what I need.
I created 2 buttons in the same place. Those buttons are represented with different sprites (Pause & Play). "Pause" is visible since the start. When I click on it, the menu pops up, the "Pause" stop being active and the "Play" sprite button activates and pops up too. When I click on it, I unpause and goes back to the "Pause" sprite visible in the screen.
void Start () {
Canvas_PauseMenu = Canvas_PauseMenu.GetComponent<Canvas> ();
Button_Pause = Button_Pause.GetComponent<Button> ();
Button_Resume = Button_Resume.GetComponent<Button> ();
Canvas_PauseMenu.enabled = false;
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
}
// Update is called once per frame
public void PauseTest () {
if(!active){
PauseGame();
}
else{
ResumeGame();
}
}
public void BackToMainMenu()
{
Application.LoadLevel (0);
}
public void PauseGame()
{
Canvas_PauseMenu.enabled = true;
Button_Exit.enabled = true;
Button_Pause.enabled = false;
Button_Pause.gameObject.SetActive (false);
Button_Resume.enabled = true;
Button_Resume.gameObject.SetActive (true);
active = true;
Time.timeScale = 0;
}
public void ResumeGame()
{
Canvas_PauseMenu.enabled = false;
Button_Exit.enabled = false;
Button_Pause.enabled = true;
Button_Pause.gameObject.SetActive (true);
Button_Resume.enabled = false;
Button_Resume.gameObject.SetActive (false);
active = false;
Time.timeScale = 1;
}