When I add EndGame();
The sound stops playing when the game ends.
If I remove the function, the sound plays fine.
I tried adding the gover.Play to EndGame, but that didn't work either.
This bug doesn't really make sense to me as to why it's happening.
Happens in both Editor and on live device.
Thank you.
Here is my code:
Update() {
if (Input.GetMouseButtonDown(0))
{
}
else
{
AudioSource[] aSources = GetComponents<AudioSource> ();
perfecthit = aSources [0]; // Works
gover = aSources [1]; // Works without EndGame()
miss = aSources [2]; // Works
gover.Play ();
EndGame ();// Adding this makes gover.Play stop working
}
}
private void EndGame()
{
Social.ReportScore (scoreCount, "--", (bool success) => {
//SUCCESS or FAIL
});
PlayerPrefs.SetInt("byte", PlayerPrefs.GetInt("byte") + scoreCount / 2);
if (PlayerPrefs.GetInt ("score") < scoreCount)
PlayerPrefs.SetInt ("score", scoreCount);
gameOver = true;
endPanel.SetActive (true);
theStack[stackIndex].AddComponent<Rigidbody>();
stack.SetActive (false);
demoObj.SetActive (true);
}
I am assuming that it stops playing due to the AudioSource no longer being available.
Inside the EndGame() you are setting stack.SetActive (false);. If this AudioSource is attached to the object, then it will be no longer available. Especially considering you are re-obtaining your AudioSources At least 30 times a second!
With that I would also like to advice you to move your audio logic outside of the Update and maybe look into using the Start, or awake instead
Related
For the life of me I can't understand why it stops looping. I have an engine acceleration script that works great, except for the fact that it stops looping after a certain amount of time. I'm only calling the audiosource to be stopped if the user presses a button, it should work just fine. It has worked before implementing this too, I've no idea what breaks it.
private void PlayAccelerateSound()
{
m_audioSource2.loop = true;
m_audioSource2.clip = m_engineSound;
if (!alreadyPlayed)
{
m_audioSource2.PlayOneShot(m_audioSource2.clip);
alreadyPlayed = true;
}
if (rb.velocity.x < minPitch)
{
m_audioSource2.pitch = minPitch;
}
else if (rb.velocity.x > maxPitch)
{
m_audioSource2.pitch = maxPitch;
}
else
{
m_audioSource2.pitch = rb.velocity.x;
}
}
Fixed it by using m_audioSource2.Play() instead of m_audioSource2.PlayOneShot(m_audioSource2.clip).
I have an animation that I want to play after my character dies. I'm trying to activate the Game Over screen after this animation is complete, but it doesn't work after yield return new WaitForSecondsRealtime(3f);
Here is my code:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "DeathArea")
{
StartCoroutine(Dead());
}
}
IEnumerator Dead()
{
animDie.SetActive(true);
animDeath.SetTrigger("Die");
Time.timeScale = 0;
yield return new WaitForSecondsRealtime(3f);
animDie.SetActive(false);
isDead = true;
deathScreen.SetActive(true);
managerGame.Medal();
}
Thank you!
You could add an event/function to be called at the end of your animation.
Unity lets you do that through the Animation window really easily.
Add an event:
Choose your function from an attached script:
The coroutine is firing off, and Time.timescale is surely breaking things. I'd use it very sparingly if I were you, as this setting also persists between scenes.
I finally found the solution to the problem.
Using the Time.timeScale = 0; code is not a problem. The real problem is that I destroyed my character because it's a death animation. Since my character died, the rest of the code became inoperable.
So instead of killing it, I made it invisible using localScale.
But the solution above is much more useful. Thank you for your answers.
Please change WaitForSecondsRealtime(3f) to WaitForSeconds(3f)
result
yield return new WaitForSeconds(3f);
I am working on a VR speedrun game and I need a timer. The timer doesn't need to be showed in the screen for the player, just on the map I made. It needs to start when the player (VR) passes a specific point and end when it reaches a different point. If anyone has an idea of how to make this work I would really appreciate it.
On the start line you could have an empty gameobject with a trigger collider on it, and in the OnTriggerEnter event you could start a Coroutine that keeps track of the time, and on the finish line you'd have another trigger collider that sets a flag and stops the timer.
Something along the lines of this should work:
using UnityEngine;
using System;
public class Player : MonoBehaviour {
private bool _isTimerStarted = false;
private float _timeElapsed = 0;
private void OnTriggerEnter(Collider other) {
if (other.gameObject.name.Equals("Start Line")) {
_isTimerStarted = true;
StartCoroutine(StartTimer());
} else if (other.gameObject.name.Equals("Finish Line") {
_isTimerStarted = false;
}
}
IEnumerator StartTimer() {
while (_isTimerStarted) {
_elapsedTime += Time.deltaTime;
yield return null;
}
yield break;
}
}
For this to work just make sure your player has a RigidBody attached or else no collision will be detected :)
If you want a "timer" as in "show the elapsed time since some event" you might take a look at Stopwatch
var sw = Stopwatch.StartNew();
...
Console.WriteLine(sw.Elapsed.ToString());
The stopwatch is primarily intended for performance measurements. But it is easy to use, so if it fits your use case you might as well make use of it, even if the resolution and accuracy is much greater than you need.
I got a simple "OnTouch" script on my enemies, which knocks back the player if they come in contact. The player then gets invincible for a short time. Something like this:
void OnTriggerEnter2D(Collider2D collider) {
if (collider.gameObject.CompareTag("Player")) {
if (Time.time > isInvincible) {
isInvincible = Time.time + invincibleTimer;
if (enemy.IsFacingRight) {
player.SetVelocity(knockback * Vector2.right);
} else {
player.SetVelocity(knockback * Vector2.left);
}
}
}
}
(SetVelocity is just a method i use to set.. velocity)
The problem with this is when the player gets invincible after been pushed away. While invincible you can then run on top of an enemy and stay there, even after the invincible timer runs out. Which i guess makes sense since it only triggers on enter.
Using the same code but inside a "OnTriggerStay2D", works as expected. You get pushed away, go invincible, run on top of an enemy, invincible runs out and you then get pushed away out of the enemy.
But having multiple enemies running around with OnTriggerStay colliding with different objects feels like it would be bad performance wise? Is there any more efficient way to do this? Or is TriggerStay the way to go?
The way I found is manually tracking the collisions like this:
List<Collider2D> hitColliders = new List<Collider2D>();
void OnTriggerEnter2D(Collider2D collision) {
if (hitColliders.Contains(collision)) { return; }
hitColliders.Add(collision);
}
void OnTriggerExit2D(Collider2D collision) {
hitColliders.Remove(collision);
}
// Perform operations to the colliders.
void Update() {
foreach (var col in hitColliders) { DoStuff(col); }
}
Although you may not run into performance problems even with the solution you have now, if you do in the future you can try using Physics.IgnoreLayerCollision:
At the start of your invincibleTimer call:
IgnoreLayerCollision(playerLayer, enemyLayer, true);
And at the end of your timer call:
IgnoreLayerCollision(playerLayer, enemyLayer, false);
And acording to the docs:
IgnoreLayerCollision will reset the trigger state of affected
colliders, so you might receive OnTriggerExit and OnTriggerEnter
messages in response to calling this.
This means that when you call IgnoreLayerCollision(false), OnTriggerEnter will be called again, even if you are already on top of an enemy. This is exactly the behaviour you are after.
Here's the code I'm using :
[RequireComponent (typeof(AudioSource))]
public class video : MonoBehaviour {
public MovieTexture movie;
public bool loop;
private AudioSource audio;
// Use this for initialization
void Start () {
GetComponent<RawImage> ().texture = movie as MovieTexture;
audio = GetComponent<AudioSource> ();
audio.clip = movie.audioClip;
movie.Play ();enter code here
audio.Play ();
movie.loop = true ();
}
// Update is called once per frame
void Update () {
}
void onMouseDown (){
if (Input.GetKeyDown(KeyCode.Mouse0)&& !movie.isPlaying)
movie.Play ();
else if (Input.GetKeyDown(KeyCode.mouse) && movie.isPlaying)
movie.Pause ();
}
}
What I want is when I click the video, the video plays, finishes, and if I click the video again, it restarts the video.
movie.loop = true;
Just Google next time: http://docs.unity3d.com/ScriptReference/MovieTexture-loop.html
I think what is needed is a check to see if the movie is finished playing or not.
I've not done any work with movies in Unity, so this is hypothetical, but something like this might work:
if (Input.GetKeyDown(KeyCode.Mouse0) && movie.hasFinishedPlaying)
{
movie.Play ();
}
What this sort of pseudocode is saying is that, if the movie has finished, and we click the mouse down, then we play the movie again.
I've just glanced at your code again. What you seem to be doing is doing a pause method in the OnMouseDown function, and setting the movie.loop to true.
However, setting something to true should be like this:
movie.loop = true;
And not like this:
movie.loop = true();
Unless it is different for using movies in Unity, but I don't know :) Give it a try!