audio.Play() not working - c#

I have the a script called Timer.cs. This script is connected to some GUI Text, which displays the amount of time remaining in the game.
Also attached to this script is an Audio Source with my desired sound selected. When the clock reaches zero, the text changes to say "GAME OVER!" and the character controls lock up; however, the sound does not play.
All other instances of audio.Play() in my scene are working fine, and when I set the Audio Source to "Play On Awake", it plays without a problem. What could be the problem?
Using UnityEngine;
using System.Collections;
public class Timer : MonoBehaviour {
public float timer = 300; // set duration time in seconds in the Inspector
public static int sound = 1;
public static int go = 1;
bool isFinishedLevel = false; // while this is false, timer counts down
void Start(){
PlayerController.speed = 8;
PlayerController.jumpHeight = 12;
}
void Update (){
if (!isFinishedLevel) // has the level been completed
{
timer -= Time.deltaTime; // I need timer which from a particular time goes to zero
}
if (timer > 0)
{
guiText.text = timer.ToString();
}
else
{
guiText.text = "GAME OVER!"; // when it goes to the end-0,game ends (shows time text over...)
audio.Play();
int getspeed = PlayerController.speed;
PlayerController.speed = 0;
int getjumpHeight = PlayerController.jumpHeight;
PlayerController.jumpHeight = 0;
}
if (Input.GetKeyDown("r")) // And then i can restart game: pressing restart.
{
Application.LoadLevel(Application.loadedLevel); // reload the same level
}
}
}

Given that you are calling it as part of your Update routine, I'd have to guess that the problem is you calling it repeatedly. I.e. you're calling it every frame as long as timer <= 0.
You shouldn't call Play() more than once. Or at least not again while it is playing. A simple fix would be something along the lines of
if(!audio.isPlaying)
{
audio.Play();
}
See if that solves your problem, and then you can take it from there.

I had error using audio.Play(); and used following it fixed the error for me
GetComponent<AudioSource>().Play();

Related

I'm trying to implement a time delay in Unity. I have done it using while loop, for loop and coroutines, but none of them seem to work

Here is my code.. I have explained the issue after..
public bool isPipeActive;
[SerializeField] private float timer;
void Start()
{
isPipeActive = false;
timer = 0f;
}
void FixedUpdate()
{
if (Input.GetKeyDown(KeyCode.Backspace))
{
isPipeActive = !isPipeActive; //bool flag invert
}
if (isPipeActive == true) //start pipe animations
{
for (int j = 0; j < ParentOf_arrow.transform.childCount; j++)
{
Initiate_arrow_FLOW_INDICATOR(j);
StartCoroutine(Time_Delay());
//while (timer < 1.0f)
for (timer = 0f; timer < 2.0f; timer += Time.fixedDeltaTime)
{
//just a blank function to see if it creates a delay..
timer += Time.fixedDeltaTime;
}
//timer = 0f;
}
}
}
IEnumerator Time_Delay()
{
yield return new WaitForSeconds(2f);
Debug.Log("2s delay initiated");
}
Initiate_arrow_FLOW_INDICATOR(j) visibly changes the color of one 3D arrow in a sequence of 3D arrows (arrow1, then arrow2, etc) to show direction. something like this.. i just want to add a time delay in between each color change, but none of the attempts i've made seem to create a time delay when i enter play mode and press Backspace key.
the colors flash extremely fast. There is no waiting between color changes whatsoever.. even when running the coroutine, while loop and for loop together :(
What is going on and how do i fix it??
The issue with the for loop is that you aren't waiting for the actual time between fixed updates and rather using the time between the last fixed update and adding it as fast as your CPU will until timer is larger than 2.
The coroutine will wait 2 seconds before logging it's output.
You need to put your arrow change code in the coroutine, because the Coroutine essentially works in "parallel" to your FixedUpdate.
So either do:
void FixedUpdate()
{
timer += Time.deltaTime;
if(timer >= 2.0f) {
//arrow thingy
timer = 0;
}
}
or in the Coroutine:
IEnumerator TimeDelay()
{
yield return new WaitForSeconds(2f);
//arrow thingy
}
In this state the FixedUpdate version will loop indefinitely and call arrow thingy roughly each two seconds, and the Coroutine will do so once.
A quick side note you should probably use Update and DeltaTime for this and not FixedUpdate with FixedDeltaTime.

How to count down both cooldown and duration

In a small simulation game (A.I. spaceship shooter) that I am developing, I am trying to come up with an effective shield function or IEnumerator which can be called or started and do multiple things:
Count down the shield's cooldown if it is above zero
Activate the shield for the set duration (5 seconds) if the cooldown has ended
Deactivate the shield when the duration expires
However, I run into some problems when trying this using only an Ienumerator. I have been able to use IEnumerators to count down timers and cooldowns before but trying to do both a cooldown and duration doesn't seem to work as Unity does not let me WaitForSeconds twice without leaving the IEnumerator.
Similarly, each ship has a turret and inside of that turret is an IEnumerator which fires or counts down its cooldown, whichever is needed for the situation.
// Fire continuously if in range and we have more than 1 shot left
// Otherwise, reload for (rate) seconds and reset shots left
public IEnumerator Fire(Vector2 target) {
firing = true;
if (cooldown <= 0) {
if (bullets > 0) {
// Fire a bullet
bullets--;
// Instatiate the bullet
}
} else {
// Reload
cooldown = rate;
bullets = count;
}
} else {
yield return new WaitForSeconds(1);
cooldown--;
}
firing = false;
yield break;
}
The Fire Coroutine is called by using the firing flag to check whether it is running or not and if it is not call
var fire = turret.Fire(shootTarget + offset);
if (!turret.firing && InRange() == true) {
StartCoroutine(fire);
}
every second or so if the ship is alive and we have a target.
I do think that my current use of the IEnumerator is not recommended because it has to be called at least every second, but with how small the environment is at the moment, it doesn't appear to be an issue.
Any help is appreciated.
Quick code without coroutines, no idea if it works in game. Should give you some idea though, I hope.
public class Shield : MonoBehaviour {
public float duration;
public float cooldown;
public float lastActivated;
public bool IsActivated => (lastActivated - (Time.time - duration)) > 0;
public bool onCoolDown => (lastActivated - (Time.time - cooldown)) > 0;
public void Activate(){
if(onCoolDown) return;
lastActivated = Time.time;
}
void LateUpdate(){
if(IsActivated) //Show shield effects, blahblah
else //Do nothing, blahblah
}
}

Unity - Change character only when animation stopped

i have two objects(the same character, but, in different functions) which i want change the character when animation stop and when it runs triggered by a click. For example, I have the Kick_Player where there is the animation triggered by the click, and when the Kick_Player ends the animation, i want it automatically changes to Player_Stopped. The poses are different each other, 'cause this i need to do these changes.
I tried something with this.MyAnimator.GetCurrentAnimatorStateInfo(0).IsName("My_Animation") but, i got unsuccessful tries. Is there a way to do that ?
public class TapController : MonoBehaviour {
Animator Anim;
public GameObject CharacterToController; //Kick_Player
public GameObject CharacterToBeStopped; //Player_Stopped
void Start(){
Anim = CharacterToController.GetComponent<Animator>();
CharacterToBeStopped.SetActive(false);
}
void Update(){
if(input.GetMouseButtonDown(0)){
if(!CharacterToController.activeSelf){
CharacterToController.SetActive(true);
}
Anim.Play("Kick_Ball");
if(!this.Anim.GetCurrentAnimatorStateInfo(0).IsName("Kick_Ball") {
CharacterToController.SetActive(false);
CharacterToBeStopped.SetActive(true);
}
}
}
I made this code to test, but it doesn't work
Using the IsName function requires that you prefix the base layer name of the animation state before the actual animation state.
The default base name is usually "Base Layer"
if(!this.Anim.GetCurrentAnimatorStateInfo(0).IsName("Base Layer.Kick_Ball")
Note that you have to do that outside your if(input.GetMouseButtonDown(0)){ otherwise that will never get chance to be checked.
I've seen reports of IsName not working for some people so if you do that but still have issues, consider doing it another way.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (!CharacterToController.activeSelf)
{
CharacterToController.SetActive(true);
}
Anim.Play("Kick_Ball");
StartCoroutine(PlayAndWaitForAnim(Anim, "Kick_Ball"));
}
}
const string animBaseLayer = "Base Layer";
int animHash = Animator.StringToHash(animBaseLayer + ".Kick_Ball");
public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
{
targetAnim.Play(stateName);
//Wait until we enter the current state
while (targetAnim.GetCurrentAnimatorStateInfo(0).fullPathHash != animHash)
{
yield return null;
}
float counter = 0;
float waitTime = targetAnim.GetCurrentAnimatorStateInfo(0).length;
//Now, Wait until the current state is done playing
while (counter < (waitTime))
{
counter += Time.deltaTime;
yield return null;
}
//Done playing. Do something below!
Debug.Log("Done Playing");
CharacterToController.SetActive(false);
CharacterToBeStopped.SetActive(true);
}

Timer counting not working correctly

I’d like to show some text when the player kills e.g. 3, 4, or 5 enemies in a given time (in Unity3d).
I have a timer (comboTimer) which is in my PlayerControl-script that starts when an enemy gets shot by the player. When the timer starts a counter (comboCounter) gets increased everytime an enemy gets shot by the player. The other script (EnemyControl) controls the way how the appropriate text gets displayed when the kill-counter (comboCounter) reaches a certain value (e.g. 3 kills = “Combo x3”). This should be done within the timer’s value.
The problem is the text that gets shown is in almost most cases 3 kills (“Combo x3”). I never reach 4 or 5 kills within the timer’s value even when I increase the waitTime to e.g. 5 or 10 seconds. There is a bug within the logic but can’t find it.
This is the Timer of my PlayerControl-script:
public static bool comboTimerRunning = false;
public static int comboCounter;
float comboWaitTime = 1f;//1.0 Sekunden
float comboTimer;
public void ComboTimer() {
comboTimer += Time.deltaTime;
if (comboTimer > comboWaitTime)
{
ResetComboTimer();
}
}
public void ResetComboTimer () {
comboTimer = 0f;
comboTimerRunning = false;
comboCounter = 0;
}
This is the script that controls the handling of the displayed text (EnemyControl):
if (!PlayerControl.comboTimerRunning) {
PlayerControl.comboTimerRunning = true;
}
PlayerControl.comboCounter++;
if (PlayerControl.comboCounter >= 3) {
if (PlayerControl.comboCounter == 3) {
comboTxtObj.GetComponent<ComboTxt>().ShowComboText("Combo x3");
} else if (PlayerControl.comboCounter == 4) {
comboTxtObj.GetComponent<ComboTxt>().ShowComboText("Awesome");
} else if (PlayerControl.comboCounter >= 5) {
comboTxtObj.GetComponent<ComboTxt>().ShowComboText("Mega-Kill");
}
PlayerControl.comboTimerRunning = false;
}

Sprite not changing when key is pressed - unity 2D

Currently I'm simply trying to change the sprites candle from unlit to lit when the player has 'picked up' both the candle and the matches and the candle will 'go out' after a certain amount of time. However, when the space bar is pressed the transition from unlit to lit isn't occurring, even though the debug log is returning true when it should. I'm posting here to get some guidance as I have spent most of the day looking online and literally have no idea how to proceed.
Basically the images I am trying to transition between are two different images which are in the sprites folder under assets.
This is what I've got so far.
//the two sprites transition
public Sprite unlitCandle;
public Sprite litCandle;
private SpriteRenderer spriteRenderer;
bool pickUpMatches = false;
bool pickUpCandle = false;
float timeRemaining =5;
bool candleLit = false;
// Use this for initialization
void Start () {
spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite == null)
spriteRenderer.sprite = unlitCandle;
}
// Update is called once per frame
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.CompareTag("Matches"))
{
collision.gameObject.SetActive(false);
pickUpMatches = true;
}
if (collision.gameObject.CompareTag("UnlitCandle"))
{
collision.gameObject.SetActive(true);
pickUpCandle = true;
}
}
public void CandleTimer()
{
if (candleLit == true)
{
timeRemaining = 5;
timeRemaining -= Time.deltaTime;
if (timeRemaining <= 0)
{
candleLit = false;
spriteRenderer.sprite = unlitCandle;
}
}
}
public void ChangeSprite()
{
if (spriteRenderer.sprite == unlitCandle)
{
spriteRenderer.sprite = litCandle;
}
}
void Update () {
if (pickUpCandle == true && pickUpMatches == true)
{
//Debug.Log(candleLit);
if (Input.GetKey(KeyCode.Space) && !candleLit)
{
CandleTimer();
ChangeSprite();
Debug.Log(timeRemaining);
candleLit = true;
//Debug.Log(candleLit);
}
}
}
}
Try comparing with a method like equals() instead of == in
spriteRenderer.sprite == unlitCandle
Because right now you are just comparing references and not the objects.
At least I think thats the problem.
There are a few possible issues with your code. First, you are calling changeSprite at the top of Update, which means that it is unconditionally being called every frame. Therefore, after a single frame of your candle being unlit, it will immediately change its sprite to litCandle.
I assume that the reason you are calling changeSprite every frame is in order to process the timer if you have a lit candle already. Really, you should move the code to process the timer (your whole second if statement in changeSprite) to a separate function and name it something like processCandleTimer. Call that at the top of Update and save the changeSprite method to only be called on the keypress.
Lastly, the issue that I suspect is giving you the most trouble is that you aren't resetting your timer, timeRemaining. The first time you light the candle the timer will go down to 0 after the 5 seconds pass. Every time changeSprite is run after that, you will change the sprite to litCandle in the first if statement and then immediately change it back to unlitCandle because the timer is 0 in the second. To remedy this, you need to add a line like timeRemaining = 5.0f; when the key is hit.

Categories