I have a fairly large array of 60 tracks. I need them to play one by one. When the scene changes, the track is also interrupted and the next track is played in turn. That is, in one scene can play 0, 1, 2 items. After switching scenes, 3 should play, and so on. On the Internet I found a function that seems to work the way I want. But I do not quite understand how to call function correctly.
public AudioClip[] clipArray;
public AudioSource effectSource;
private int clipIndex;
void PlayRoundRobin() {
if (clipIndex < clipArray.Length)
{
effectSource.PlayOneShot(clipArray[clipIndex]);
clipIndex++;
}
else
{
clipIndex = 0;
effectSource.PlayOneShot(clipArray[clipIndex]);
clipIndex++;
}
Put your method into your scene manager.
If you load the scene, call the method.
After that, call the method whenever you want to play the next track.
Related
I have animation events linked up to my characters that play a random footstep noise when they step. I'm trying to set it up for multiplayer, but I'm having some issues. With one person, the sounds only play once when they're supposed to. However, as tested with 2 people, it plays each footstep twice at the same time when one player steps. Each player has an audiosource component. Both footsteps sounds come from the audiosource of the player running, so it's not a case of both players playing the same sound. Any ideas as to why the sound is duped and played at the same time? The double sound comes from the same client, but only when that client is in multiplayer. And it's not when other people are walking, only the client. I must be setting up something wrong or putting something in the wrong place with my RPC.
1 player with 1 audiosource: sounds plays once
2 players with their own audiosource: sounds duplicates and plays at the same time
2 players with audiosource enabled for only the one walking: sounds still plays twice
From my player code
public void PlayFootstep()
{
int clipPick = Random.Range(0, footstepArray.Length);
GetComponent<AudioSource>().clip = footstepArray[clipPick];
photonView.RPC("PlayFootstepRPC", RpcTarget.All);
}
[PunRPC]
private void PlayFootstepRPC()
{
if (GetComponent<AudioSource>().isActiveAndEnabled && GetComponent<PlayerMovement>().ySpeed > 1.15)
{
GetComponent<AudioSource>().Play();
}
}
If PlayFootstep is called via an animation event, and you have animations synchronized via PhotonAnimatorView, then the PlayFootstepRPC() gets called several times, once per each connected client.
PhotonAnimatorView makes an object to play the same animations on every client. The PlayFootstep function gets called on every client, and every client sends RPC to itself and other clients, and that RPC plays the sound.
I suggest you should either not play footstep sounds via RPC, playing it locally instead (because animation event handles it for you), or add a check of PhotonView.IsMine before calling an RPC.
I have plane(as in air plane) objects in my program, they get destroyed when bullets hit them but they also get destroyed after 5 seconds, when they exit the screen.
I also have a health script that resets the whole thing when it goes down to 0, and I want to remove a point every time the object is destroyed, but only when off screen. So I keep the scripts separate.
I use this in the ships spawn script to destroy them after 5 seconds, simple enough.
Destroy(spawnedPlane, 5f);
It would be perfect if I could just have some code that does "Destroy this object after X seconds AND add this to this value". Because as I understand it, "destroy" only accepts 2 parameters and nothing else.
Surely it is possible but I am at a loss. Still very new to this. Sorry if this is very unclear but I barely know what I'm doing myself.
You can use events to cleanly achieve what you are after. Below is an example of an event you might find useful. Other objects can listen to the event and once it is triggered, they will be notified.
[Serializable]
public class PlaneEvent : UnityEvent<Plane> { }
Once you have defined your event, you can then add it as a field in your Plane. Once your plane has been destroyed, you can fire the event and it will in turn notify anyone who is listening!
public class Plane : MonoBehaviour {
public PlaneEvent OnDestroyed;
public void Destroy () {
Destroy(gameObject);
OnDestroyed.Invoke(this);
OnDestroyed.RemoveAllListeners();
}
}
Now in our score class, we add a method that will be called once the OnDestroyed plane event is triggered.
public class Score : MonoBehaviour {
public void AddPointsFor (Plane plane) {
Debug.Log("A Plane was destroyed!");
//Tick a counter, add points, do whatever you want!
}
}
Once we have these pieces, it is trivial to make them work together. We take the plane and we add the score as a listener to the OnDestroyed event. Then once the plane is destroyed, the event is fired and score is told to add points.
public class Game : MonoBehaviour {
[SerializeField]
private Score _score;
[SerializeField]
private Plane _plane;
public void Start () {
// When you are destroyed let me know so I can add some points.
_plane.OnDestroyed.AddListener(_score.AddPointsFor);
_plane.Destroy();
}
}
Another big advantage in using events is your plane has no idea that a score even exists, it will let anyone who cares know that it has been destroyed. In the same way this event could also be used to trigger particle effects, animations and sound effects when the plane is destroyed and all you need to do is add more listeners.
Just use a coroutine to wait and then subtract a point and destroy the object at the same time.
void Start()
{
// your startup script
StartCoroutine(DestroyAfterSeconds(5f));
}
IEnumerator DestroyAfterSeconds(float seconds)
{
// wait for X amount of seconds before continuing on
yield return new WaitForSeconds(seconds);
/*
* this runs after the wait.
* if the coroutine is on the same gameobject that you are
* destroying, it will stop after you run Destroy(), so subtract
* the point first.
* */
points--;
Destroy(spawnedPlane);
}
If it was me I would surely go with events as suggested by CaTs.
Coroutine are another way to do that, but events are better in general at least in this case. Also using a Coroutine for just one Invoke is a bit an overkill (and unity Coroutines are a bit not performant.) Also the coroutine must be outside of the object you want to destroy because Unity Coroutines die when their MonoBehaviour is destroyed.
If you are still uncomfortable with events you...
well you should overcome it and try them anyway.
You could take a shortcut you can use More Effective Coroutine - Free.
And launch this code:
Timing.CallDelayed(5f, DestroyAndRemoveHP());
Basically this will run your logic with the delay you want to apply.
DestroyAndRemoveHP will be your method to destroy the platform and do anything else you like.
Full method description.
On the plus side you will start using MEC that are better than unity coroutine, but learning events makes you also a better programmer. You might do both.
A made a quiz game using Serializable method. As I call data from there it is always in same sequence. What I want to do is serialize questions and answers. And later I want to call data in random order.
Sorry about my previous question. Actually I'm new here that is why made the mistake. Really SORRY
Thank you guys :)
I am giving a link to the training session in case you need anything not specified here (all codes of the Project given there)
https://unity3d.com/learn/tutorials/topics/scripting/intro-and-setup
Try to be more specific in what you are asking.
You have both 2d and 3d tags for unity up pick the one you are using.
If you are working in one persistent scene, that means you will have to manipulate everything manually to remove it or reset it.
Another option is that you save the data you need from that round in a don't destroy on load object and reload your scene.
I would suggest you make 2 scenes, a menu scene, and a play-scene.
Read up on scenemanager and place a button in the menu scene that lets you move to the play-scene.
make a game object that holds information you want keep from every round.
for example; this object will hold the coins when you leave the scene.
public class GameControl : MonoBehaviour
{
public int coins;
public static GameControl gamecontrol;
void Awake()
{
if (gamecontrol == null)
{
DontDestroyOnLoad(gameObject);
gamecontrol = this;
}
else if (gamecontrol != this)
{
Destroy(gameObject);
}
}
}
After you added the coins to this object at the end of the round.
Leave the scene at end of round and go to the menu scene.
Now you can open new round in menu and you can keep the coins.
I don't really understand this?
What seems to happen is when I enter the trigger zone the flashlight turns off, but when exiting the trigger zone the flashlight doesn't turn on again. If i reverse the effect i.e the flash light is off when the scene starts and then when entering the trigger zone the flashlight doesn't turn? This is the same (minor changes with name) script I used for the main room light (which works)
So with the below code the flashlight is off and i would like to turn it on when entering the trigger zone?
public class TurnFlashLightOn : MonoBehaviour
{
void Start()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(true);
}
}
void OnTriggerEnter()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(false);
}
}
void OnTriggerExit()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(true);
}
}
}
Any ideas why it would switch off but not on?
Thanks
Subtle but important detail: GameObject.FindGameObjectsWithTag only searches through active objects. Once you turn off a flashlight, it won't show up in that search anymore.
You'll need to cache a list of flashlight objects.
If the list is never going to change (you never create or destroy flashlights), then you can populate the list once during Start, then refer to the list any time you need it.
If the list is dynamic, you could start with an empty list, then add any flashlight to the list as it gets deactivated. When it's time to turn lights back on, activate every light in the list and then clear the list.
There are plenty of ways you could do this; the basic issue is just that you need some other way to keep track of those inactive objects.
Based on your code and what you are telling me, You have an event for when an object passes a threshold the lights will turn off. This threshold contains the Event OnTriggerEnter();
The Threshold or Zone() cannot contain two triggers at once and know which one it is supposed to fire. I can only propose you have an If-Else statement which helps define the logic to which trigger should fire. for instance
(This is Pseudo Code)
If (EnteringZoneFromStart() = true)
{OnTriggerEnter()}
Else If (ExitingZone() = true)
{OnTriggerExit()}
Else
{OnTriggerEnter()}
In my game I am creating in unity I am trying to play an audio clip every time that a collision happens on one of my game objects. For some reason the audio will play the first time there is a collisiom, but from then on it no longer plaus the sound.
The game object that is collided with has a component for the AudioSource and I have the audio clip selected in that component.
Here is the code where I start the audio:
if (PlayerPrefs.GetInt ("Sound Playing", 1) == 1)
{
audio = GetComponent <AudioSource>();
audio.Play ();
}
I have also tried using the PlayOneShot () method but it does the same thing.
EDIT
Here is a small representation what of my game is doing here:
public class Ship : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D collider)
{
Laser laser = collider.gameObject.GetComponent<Laser> ();
if (laser)
{
if (!immune)
{
//update healthbar
healthbar.hit();
//reset health boost
forcefield.resetHealthBoost();
health -= laser.getDamage(); //remove health from ship
//create explosion
GameObject explosion = Instantiate(explode, gameObject.transform.position, Quaternion.identity) as GameObject;
explosion.GetComponent<ParticleSystem>().startColor = this.GetComponent<SpriteRenderer>().color;
if (SoundEffects.soundOn && PlayerPrefs.GetInt("Sound Playing", 1) == 1)
{
audio = GetComponent<AudioSource>();
audio.Play();
}
}
laser.hit();//destroy the laser that hit the ship
}
}
}
Here is to show that I have the AudioSource and the AudioClip setup in the inspector (the AudioSource is attached to the ship):
The issue with my game was that I didn't realize that using gameobject.SetActive(false) later in my code was stopping the second audio clip from being able to play. I set it to false when the ship was destroyed and this is what the problem was all along. It works fine now.
It's looks with audio it's all right. May be problem is in collisions or something else. Add code Debug.Log("Play sound."); before code line audio.Play();, and test.
Make sure your audio listener is near the explosion too. It could be far away and may not be heard. Also do a check to see if audio.isPlaying, then play audio. Audio may be still playing and you have to stop it properly.
if (audio.isPlaying) {
audio.Stop();
audio.Play();
}
If all else fails you can always do PlayOneShot(), which will essentially do as it says. audio.PlayOneShot(); This could be problematic though since if you are putting it OnTriggerEnter() it may run more than once in a short duration. You may hear it stutter because it's queued up however many explosions.
Finally, don't use PlayerPrefs for those specific things. You should reserve it honestly for Game Specific data storage. Why can't you simply use isPlaying? PlayerPrefs will only make the task very convoluted. I learned it the hard way when I used to use PlayerPrefs to transfer data from C# to UnityScript. In the end it's almost best to use Static Variables, or create a Singleton class and commit values to various instances. Plus I learned that I can use methods and variables cross languages when I adjust the compilation order(s). A little bit off topic, but still substantially important.