Making volume slider in Unity - c#

Game starts, the music begins to play, but it's too annoying and want to mute or just make it quieter. Like games, there's setting menu, which I thought it would be good to be in next scene, and there I want to put slider.
But I got errors.
Script:
using UnityEngine;
using System.Collections;
public class Music : MonoBehaviour
{
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
public AudioClip[] soundtrack;
// Use this for initialization
void Start()
{
if (!GetComponent<AudioSource>().playOnAwake)
{
GetComponent<AudioSource>().clip = soundtrack[Random.Range(0, soundtrack.Length)];
GetComponent<AudioSource>().Play();
}
}
// Update is called once per frame
void Update()
{
if (!GetComponent<AudioSource>().isPlaying)
{
GetComponent<AudioSource>().clip = soundtrack[Random.Range(0, soundtrack.Length)];
GetComponent<AudioSource>().Play();
}
}
}

You use AudioSource.volume to change the volume. When you create a Slider, you can get the value of the slider with Slider.value. So, take Slider.value and assign it to AudioSource.volume.
To create s Slider, go to GameObject->UI->Slider. Make sure that Min Value is 0 and Max Value is 1. Also make sure that Whole Numbers check box is NOT checked. Drag the Slider to the volume Slider slot in this script from the Editor.
Note:
If you are going to use a component more than once, cache it to a global variable instead of doing GetComponent<AudioSource>() multiple times or using it in the Update() function.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Music : MonoBehaviour
{
public AudioClip[] soundtrack;
public Slider volumeSlider;
AudioSource audioSource;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
// Use this for initialization
void Start()
{
audioSource = GetComponent<AudioSource>();
if (!audioSource.playOnAwake)
{
audioSource.clip = soundtrack[Random.Range(0, soundtrack.Length)];
audioSource.Play();
}
}
// Update is called once per frame
void Update()
{
if (!audioSource.isPlaying)
{
audioSource.clip = soundtrack[Random.Range(0, soundtrack.Length)];
audioSource.Play();
}
}
void OnEnable()
{
//Register Slider Events
volumeSlider.onValueChanged.AddListener(delegate { changeVolume(volumeSlider.value); });
}
//Called when Slider is moved
void changeVolume(float sliderValue)
{
audioSource.volume = sliderValue;
}
void OnDisable()
{
//Un-Register Slider Events
volumeSlider.onValueChanged.RemoveAllListeners();
}
}
You can learn more about Unity's UI here.

Related

Unity 2D: Making the Player Gameobject Reactivate after being turned off

I can't get the Player Gameobject to reappear. The player deactivates the moment the Timeline starts when they touch the box collider, but the player never reactivates. I have tried using Player.SetActive(true) in the coroutine and even using an Invoke method with no luck. Any ideas on how to fix this? Please help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class TimelineTrigger : MonoBehaviour
{
// calling items for Unity
public PlayableDirector timeline;
public GameObject Player;
public GameObject CutsceneCollider;
public GameObject CutsceneMC;
// Start is called before the first frame update
void Start()
{
// calls the playable director and turns off the MC for the scene
timeline = timeline.GetComponent<PlayableDirector>();
CutsceneMC.SetActive(false);
}
void Update()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
private void EnableAfterTimeline()
{
Player = GameObject.FindGameObjectWithTag("Player");
Player.SetActive(true);
}
public void OnTriggerEnter2D (Collider2D col)
{
if (col.CompareTag("Player"))
{
// plays the cutscene and starts the timer
timeline.Play();
Player.SetActive(false);
Invoke("EnableAfterTimeline", 18);
CutsceneMC.SetActive(true);
StartCoroutine(FinishCut());
}
IEnumerator FinishCut()
{
// once the cutscene is over using the duration, turns off the collider and the MC.
yield return new WaitForSeconds(17);
CutsceneMC.SetActive(false);
CutsceneCollider.SetActive(false);
}
}
}
The issue here is that coroutines in Unity can't be run on inactive GameObjects, so FinishCut never gets executed.
This can be worked around by having a separate MonoBehaviour in the scene to which the responsibility of running a coroutine can be off-loaded. This even makes it possible to start static coroutines from static methods.
using System.Collections;
using UnityEngine;
[AddComponentMenu("")] // Hide in the Add Component menu to avoid cluttering it
public class CoroutineHandler : MonoBehaviour
{
private static MonoBehaviour monoBehaviour;
private static MonoBehaviour MonoBehaviour
{
get
{
var gameObject = new GameObject("CoroutineHandler");
gameObject.hideFlags = HideFlags.HideAndDontSave; // hide in the hierarchy
DontDestroyOnLoad(gameObject); // have the object persist from one scene to the next
monoBehaviour = gameObject.AddComponent<CoroutineHandler>();
return monoBehaviour;
}
}
public static new Coroutine StartCoroutine(IEnumerator coroutine)
{
return MonoBehaviour.StartCoroutine(coroutine);
}
}
Then you just need to tweak your code a little bit to use this CoroutineHandler to run the coroutine instead of your inactive GameObject.
public void OnTriggerEnter2D (Collider2D col)
{
if (col.CompareTag("Player"))
{
// plays the cutscene and starts the timer
timeline.Play();
Player.SetActive(false);
Invoke("EnableAfterTimeline", 18);
CutsceneMC.SetActive(true);
CoroutineHandler.StartCoroutine(FinishCut()); // <- Changed
}
IEnumerator FinishCut()
{
// once the cutscene is over using the duration, turns off the collider and the MC.
yield return new WaitForSeconds(17);
CutsceneMC.SetActive(false);
CutsceneCollider.SetActive(false);
}
}
If you have only one Player instance and it's accessible from the start, you'd better set it once in the Start method.
void Start()
{
// calls the playable director and turns off the MC for the scene
timeline = timeline.GetComponent<PlayableDirector>();
CutsceneMC.SetActive(false);
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
}
private void EnableAfterTimeline()
{
Player.SetActive(true);
}

Use a slider to set the time of an AudioSource in Unity

I need to use a Unity slider to change the time of an AudioSource. As now the slider is capable to display the time position the AudioSource is on, but I also need it to edit the position. Here's my code:
public Slider time;
public AudioSource audio;
// Start is called before the first frame update
void Start()
{
audio = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
time.maxValue = audio.clip.length;
time.value = audio.time;
audio.time = time.value;
}
How can I do that?
public Slider slider;
private AudioSource audioS;
private void Awake()
{
audioS = GetComponent<AudioSource>();
}
void Update()
{
slider.maxValue = audioS.clip.length;
}
public void OnSliderValueChanged()
{
audioS.time = slider.value;
}
private void FixedUpdate()
{
slider.value = audioS.time;
}
Once you have this code in your file, simply go to your slider. All the way down in the properties panel, you will find "OnValueChanged" put your object with your script attached to it and simply choose your function. Your function will now be called everytime you change the value of the slider.

Show Time as highest score when game over Unity script

I need help with my script. I really can't understand how to make it. I have a script that counts time but I don't know how to make it so that when the game is over the time appears in my Game Over scene as the highest score. I only need to save this high score for one time. After the game is closed the score can be removed. In the game, I have a countdown timer, when it reaches 0 the game is over.
This is my TimeCounter script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TimeCounter: MonoBehaviour
{
public Text timerText;
private float startTime;
bool finishCountTime = false;
public string minutes, seconds;
// Use this for initialization
void Start()
{
}
public void startTheTimer()
{
Invoke("startTime", 10);
startTime = Time.time;
}
public void stopTheTimer()
{
finishCountTime = true;
}
// Update is called once per frame
void Update()
{
float t = Time.time - startTime;
minutes = ((int)t / 60).ToString();
seconds = (t % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
}
and this is GameManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Threading;
public class GameManager: MonoBehaviour
{
[SerializeField] private float timer = 30;
private void Awake()
{
pop.onClicked += PopClicked;
}
private void OnDestroy()
{
pop.onClicked -= PopClicked;
}
private void PopClicked()
{
if (pop.Unclicked.Count == 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
private void Update()
{
if (timer <= 0)
{
SceneManager.LoadScene("GameOver");
}
}
}
Here is an example snippet of how to use DontDestroyOnLoad along with the SceneLoaded delegates.
using UnityEngine;
using UnityEngine.SceneManagement;
public class ExampleScript : MonoBehaviour
{
private float score;
private void Awake()
{
var objs = FindObjectsOfType(typeof(ExampleScript));
if (objs.Length > 1)
{
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if(scene.name == "gameOver")
{
// display the time here as we are showing the score
Debug.Log(score);
}
else
{
// we loaded into another scene - presumably your game scene, so reset the score
score = 0;
}
}
}
As it is DontDestroyOnLoad, you will need to check if the current scene contains the object already and destroy it. As you have two scripts running your logic, you might need to slightly tweak it so that one of the managers is able to communicate to one another to pull your score or move it to the same script. I have greatly over-generalized your issue as I was not sure which part you did not understand.
Edit: Here is the more in-depth answer on how to achieve what you would like to do.
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class TestScript : MonoBehaviour
{
private float score; // our current score
private bool updateScore = false; // whether or not we should update our score UI every frame
private Text ScoreText = null; // our text object that updates our score
private void Awake()
{
// as the object is DontDestroyOnLoad, we need to check if another instance exists
// if one does, we need to delete it as if multiple exist in one scene, there could be issues
// if a player continually replays your scene where this object starts, then multiple will exist
var objs = FindObjectsOfType(typeof(TestScript));
if (objs.Length > 1)
{
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
private void OnEnable()
{
// add the callback for when a scene is loaded
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
// remove the callback from when a scene is loaded
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// grab the new reference to out score UI
ScoreText = GameObject.Find("Score").GetComponent<Text>();
// when we have the gameover scene, display our final score
if (scene.name == "gameover")
{
// display the time here as we are showing the score
ScoreText.text = "Final Score: " + score.ToString("#");
updateScore = false;
}
else
{
// we loaded into another scene - presumably your game scene, so reset the score
score = 0;
updateScore = true;
}
}
private void Update()
{
// if we are in the game scene and we should update score, update the score however you like
if(updateScore)
{
score += Time.deltaTime;
ScoreText.text = "Current Score: " + score.ToString("#");
}
// this is here solely for testing - instead of a real game just hit space to end the game and restart it
if(Input.GetKeyDown(KeyCode.Space))
{
if(SceneManager.GetActiveScene().name == "gameover")
{
SceneManager.LoadScene(0);
}
else
{
SceneManager.LoadScene("gameover");
}
}
}
}
Here is an example of the script working as well as the two scene hierarchies. For this to work exactly as I have it, you will need two scenes. In your build settings, the first scene will be your game scene, and then there needs to be some other scene in the build settings with the name gameover. As well, you will need to have some sort of UnityEngine.UI.Text component that is called Score in both scenes.
All of this can be changed, but this is what you need to do to get it to work as I have it set up.

W, A,S, D movement in Unity, don't know how to use new funtions

Hello i have a problem with animation controller script used to play animations depending on which key is pressed
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationController : MonoBehaviour
{
function UpdateAnimations()
{
if (Input.GetKeyDown(KeyCode.W))
{
animation.CrossFade("goup");
}
else if (Input.GetKeyDown(KeyCode.A))
{
animation.CrossFade("goleft");
}
else if (Input.GetKeyDown(KeyCode.D))
{
animation.CrossFade("goright");
}
else if (Input.GetKeyDown(KeyCode.S))
{
animation.CrossFade("godown");
}
}
void Start()
{
}
// Update is called once per frame
void Update()
{
UpdateAnimations();
}
It says that "Component.animation" is too old, and i should use GetComponent but i don't know how to
First of all you most probably mean void instead of function as your code is in c# not unityscript (which is also long deprecated by now)
And then Yes, how old is that code you got there? The direct accesses to things like Component.animation, Component.renderer, Component.camera were deprecated years ago ^^
As the error already tells you rather use e.g. Component.GetComponent like e.g.
public class AnimationController : MonoBehaviour
{
// Reference this via the Inspector in Unity
// via drag and drop. Then you don't need GetComponent at all
[SerializeField] private Animation _animation;
private void Awake()
{
// or as fallback get it on runtime
if(!_animation) _animation = GetCompoenent<Animation>();
}
// Update is called once per frame
private void Update()
{
UpdateAnimations();
}
private void UpdateAnimations()
{
if (Input.GetKeyDown(KeyCode.W))
{
_animation.CrossFade("goup");
}
else if (Input.GetKeyDown(KeyCode.A))
{
_animation.CrossFade("goleft");
}
else if (Input.GetKeyDown(KeyCode.D))
{
_animation.CrossFade("goright");
}
else if (Input.GetKeyDown(KeyCode.S))
{
_animation.CrossFade("godown");
}
}
}
How have you defined "animation" in your code?
you could try adding animation reference in the top of the code:
private Animation animation;
and in your Start() or Awake() method, add:
// will add reference to the animation to be the Animation component
// in this GameObject
animation = GetComponent<Animation>();

Unity on trigger enter can't play animation

I'm a noob at c# in unity. I've been trying to trigger an animation "hit" when a rigid body enters a box collider set to Is Trigger. I have the animation clip, and the console shows me that I have "Entered Trigger". I can't seem to get my animation clip to play once this happens. By the way this is regarding 3D models. Can anyone help?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class newAttack : MonoBehaviour {
public GameObject tiger;
public AnimationClip attack;
private Animation myAnimation;
/* IEnumerator Wait()
{
myAnimation = GetComponent<Animation>();
myAnimation.Play(attack.name);
yield return new WaitForSeconds(3);
}
*/
void OnTriggerEnter(Collider other)
{
Debug.Log("Entered Trigger");
myAnimation = GetComponent<Animation>();
myAnimation.Play(attack.name);
// StartCoroutine(Wait());
}
// Use this for initialization
// Update is called once per frame
void Update () {
}
}
You can try to use the Animator and play the name of the animation (present in the animator).
The code would like:
myAnimation = GetComponent<Animator>();
myAnimation.Play(attack.name);
Ref: https://docs.unity3d.com/ScriptReference/Animator.Play.html

Categories