Mute button does not work when I switch the scenes - unity3d

AudioManager and sound effects are working just fine at the beginning of scene, however it does not work when i switch the scenes. Or even with the same scene.
I would be grateful if you could help with that and PlayerPrefs issue. I have been searching all around the forum about PlayerPrefs but i could not be sure about what to type.
Thank you very much.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using System;
public class AudioManager : MonoBehaviour {
bool mutebutton = false;
public Sound[] sounds;
public static AudioManager instance;
// Use this for initialization
void Awake () {
if (instance == null)
instance = this;
else
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
foreach (Sound s in sounds)
{
s.source = gameObject.AddComponent<AudioSource>();
s.source.clip = s.clip;
s.source.volume = s.volume;
}
}
void Start()
{
Play("Theme");
PlayerPrefs.SetFloat("volume", AudioListener.volume);
PlayerPrefs.Save();
}
// Update is called once per frame
public void Play (string name)
{
Sound s = Array.Find(sounds, sound => sound.name == name);
s.source.Play();
}
public void Mute()
{
if (!mutebutton)
{
mutebutton = true;
AudioListener.volume = 0;
}
else
{
mutebutton = false;
AudioListener.volume = 1;
}
}
}

If you only miss "Theme" sound on scene load:
Start() method won't be called again on scene load.
You have to actively call Play("Theme") after loading a scene.

Related

Change text from instantiate script object

I am instantiating a object (Prefab) when I press a button and I want to change a text like a Score from its instantiating object script but when I try to add the text to prefab in the inspector I can't.
this is the script prefab object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BulletScript : MonoBehaviour
{
public float speed;
public Text points;
private Rigidbody2D rigidBody2D;
// Start is called before the first frame update
void Start()
{
rigidBody2D = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
rigidBody2D.velocity = Vector2.left * speed;
}
private void OnTriggerEnter2D(Collider2D collision)
{
Player player = collision.GetComponent<Player>();
BlueShieldScript blueShieldScript = collision.GetComponent<BlueShieldScript>();
RedShieldScript redShieldScript = collision.GetComponent<RedShieldScript>();
if (player != null && gameObject.name != "bullet(Clone)")
{
player.Hit();
Destroy(gameObject);
}
if(blueShieldScript != null && gameObject.name == "bulletBlue(Clone)")
{
blueShieldScript.Hit();
points.text = "1";
Destroy(gameObject);
}
if(redShieldScript != null && gameObject.name == "bulletRed(Clone)")
{
redShieldScript.Hit();
Destroy(gameObject);
}
Destroy(gameObject, 5);
}
}

Unity speech recogniser, how to use in conjunction with an if statement

I am creating a voice controlled game. One game I'm creating is a "shoot the targets" cannon game which will fire a cannon ball when the word "shoot" is said.
I am trying to use Unity's speech recogniser in conjunction with an if statement in order to move the Slider UI's fill area with my voice.
However, my initial method is drawing a few errors such as "Cannot convert Method group 'Up' to non-delegate type bool. Did you intent to invoke the method?"
P.S This is my first time using StackOverflow, please be nice.
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Windows.Speech;
using UnityEngine;
using UnityEngine.UI;
public class SliderControls : MonoBehaviour
{
//Voice Controls Setup
private KeywordRecognizer keywordRecognizer;
private Dictionary<string, Action> actions = new Dictionary<string, Action>();
float sliderValue;
// Start is called before the first frame update
void Start()
{
actions.Add("Up", Up);
actions.Add("Down", Down);
keywordRecognizer = new KeywordRecognizer(actions.Keys.ToArray());
keywordRecognizer.OnPhraseRecognized += Recognization;
keywordRecognizer.Start();
}
private void Recognization(PhraseRecognizedEventArgs speech)
{
Debug.Log(speech.text);
actions[speech.text].Invoke();
}
private void Up()
{
ControlGUI();
}
private void Down()
{
ControlGUI();
}
public void ControlGUI ()
{
if (Up)
{
sliderValue = sliderValue + 0.1F;
}
else if(Down)
{
sliderValue = sliderValue - 0.1F;
}
sliderValue = GUI.HorizontalSlider(new Rect(25F, 25F, 600F, 30F), sliderValue, 0.0F, 10.0F);
return;
}
}
As the error says, you trying to use method as a bool. You can't do that. Moreover, your logic in ControlGUI method is strange - where these Up and Down should come from?
I think you need to pass and argument to ControlGUI method, so your code will look like:
private void Up()
{
ControlGUI("Up");
}
private void Down()
{
ControlGUI("Down");
}
// You can also define enum Direction { Up, Down } or use int or any other approach
public void ControlGUI (string direction)
{
if (direction == "Up")
{
sliderValue = sliderValue + 0.1F;
}
else if(direction == "Down")
{
sliderValue = sliderValue - 0.1F;
}
sliderValue = GUI.HorizontalSlider(new Rect(25F, 25F, 600F, 30F), sliderValue, 0.0F, 10.0F);
return; // this return statement is redundant
}

Reload GameScene without reloading UIScene in Unity3d

I have 2 scenes "GamePlay" and "GameUI".
I load GameUI additively with GamePlay
void Awake () {
if (!instance) {
instance = this;
} else {
Destroy(this.gameObject) ;
}
SceneManager.LoadScene ("GameUI", LoadSceneMode.Additive);
DontDestroyOnLoad(this.gameObject);
}
Now when I reload the "GamePlay" scene using
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
How can I prevent reloading "GameUI" scene?
You could add an MonoBehaviour that is attached to the GameUI which contains a static bool that indicates if the object exists. Make your whole UI Scene a child of one object with the following script.
public class UIExistance : MonoBehaviour
{
public static bool Exists { get; private set; }
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
UIExistance.Exists = true;
}
void OnDestroy()
{
UIExistance.Exists = false;
}
}
When you are in your posted Awake method you can check with if(!UIExistance.Exists) whether the UI is already in the scene.

Drag and Drop In ScrollRect (ScrollView) in Unity3D

I want to implement drag and drop on contents of scroll view.
The problem is when you try drag items in scroll view you can't scroll the view.
First, I've tried to implement drag and drop by IDragHandler, IBeginDragHandler, IEndDragHandle and IDropHandler interfaces. In a first sight, It worked pretty good but the problem was you can't scroll the ScrollRect.
I think the problem is because of overriding, When I use event triggers that the same as scroll rect like drag, the parent one don't work properly.
So after that, I've thought by myself and implement it by IPointerDown, IPointerUp interfaces and specific time for holding drag-gable UI in ScrollRect and if you don't hold it in specific time the scrolling work well.
But the problem is by enabling DragHandler script that I wrote before the OnDrag, OnBeginDrag and OnEndDrag functions doesn't work when time of holding ended.
First I want to know there is any way to call these functions ?
Second is there any way to implement drag and drop UI without using drag interfaces ?
DragHandler :
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
public static GameObject itemBeingDragged;
private Vector3 startPos;
private Transform startParent;
DragHandler dragHandler;
public void Awake()
{
dragHandler = GetComponent<DragHandler>();
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("Begin");
itemBeingDragged = gameObject;
startPos = transform.position;
startParent = transform.parent;
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("Drag");
transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("End");
itemBeingDragged = null;
if (transform.parent == startParent)
{
dragHandler.enabled = false;
transform.SetParent(startParent);
transform.position = startPos;
}
}
}
ScrollRectController:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ScrollRectController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public float holdTime;
public float maxVelocity;
private Transform scrollRectParent;
private DragHandler dragHandler;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
void Awake()
{
scrollRectParent = GameObject.FindGameObjectWithTag("rec_dlg").transform;
dragHandler = GetComponent<DragHandler>();
dragHandler.enabled = false;
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Down");
scrollRect = scrollRectParent.GetComponent<ScrollRect>();
isHolding = true;
StartCoroutine(Holding());
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Up");
isHolding = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
//if (scrollRect.velocity.x >= maxVelocity)
//{
// isHolding = false;
//}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
Debug.Log(timer);
yield return null;
}
dragHandler.enabled = true;
//dragHandler.OnBeginDrag();
}
}
Slot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
DragHandler.itemBeingDragged.transform.SetParent(transform);
}
}
Answer:
I wrote some codes that handle drag and drop in scrollRect(scrollView) without using DragHandler interfaces.
DragHandler:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragHandler : MonoBehaviour, IPointerExitHandler
{
public static GameObject itemBeingDragged;
public static bool isCustomerDragged;
public Transform customerScrollRect;
public Transform dragParent;
public float holdTime;
public float maxScrollVelocityInDrag;
private Transform startParent;
private ScrollRect scrollRect;
private float timer;
private bool isHolding;
private bool canDrag;
private bool isPointerOverGameObject;
private CanvasGroup canvasGroup;
private Vector3 startPos;
public Transform StartParent
{
get { return startParent; }
}
public Vector3 StartPos
{
get { return startPos; }
}
void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
}
// Use this for initialization
void Start()
{
timer = holdTime;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Down");
scrollRect = customerScrollRect.GetComponent<ScrollRect>();
isPointerOverGameObject = true;
isHolding = true;
StartCoroutine(Holding());
}
}
if (Input.GetMouseButtonUp(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
//Debug.Log("Mouse Button Up");
isHolding = false;
if (canDrag)
{
itemBeingDragged = null;
isCustomerDragged = false;
if (transform.parent == dragParent)
{
canvasGroup.blocksRaycasts = true;
transform.SetParent(startParent);
transform.localPosition = startPos;
}
canDrag = false;
timer = holdTime;
}
}
}
if (Input.GetMouseButton(0))
{
if (EventSystem.current.currentSelectedGameObject == gameObject)
{
if (canDrag)
{
//Debug.Log("Mouse Button");
transform.position = Input.mousePosition;
}
else
{
if (!isPointerOverGameObject)
{
isHolding = false;
}
}
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
isPointerOverGameObject = false;
}
IEnumerator Holding()
{
while (timer > 0)
{
if (scrollRect.velocity.x >= maxScrollVelocityInDrag)
{
isHolding = false;
}
if (!isHolding)
{
timer = holdTime;
yield break;
}
timer -= Time.deltaTime;
//Debug.Log("Time : " + timer);
yield return null;
}
isCustomerDragged = true;
itemBeingDragged = gameObject;
startPos = transform.localPosition;
startParent = transform.parent;
canDrag = true;
canvasGroup.blocksRaycasts = false;
transform.SetParent(dragParent);
}
public void Reset()
{
isHolding = false;
canDrag = false;
isPointerOverGameObject = false;
}
}
Some explanation for this piece of code :
Your draggable UI element need intractable option, for me, I used button.
You need to attach this script to your draggable item.
Also you need add Canvas Group component.
customerScrollRect is a ScrollRect parent of your items.
dragParent can be a empty GameObject which is used because of mask of view port.
Slot:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
bool isEntered;
public void OnPointerEnter(PointerEventData eventData)
{
isEntered = true;
}
public void OnPointerExit(PointerEventData eventData)
{
isEntered = false;
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
if (isEntered)
{
if (DragHandler.itemBeingDragged)
{
GameObject draggedItem = DragHandler.itemBeingDragged;
DragHandler dragHandler = draggedItem.GetComponent<DragHandler>();
Vector3 childPos = draggedItem.transform.position;
//Debug.Log("On Pointer Enter");
draggedItem.transform.SetParent(dragHandler.StartParent);
draggedItem.transform.localPosition = dragHandler.StartPos;
draggedItem.transform.parent.SetParent(transform);
draggedItem.transform.parent.position = childPos;
isEntered = false;
}
}
}
}
}
Some explanation for this script:
1.Attach the script to the dropped item.
The easiest solution for this problem is actually to manually call the ScrollRect's events IF the user hasn't pressed long enough using ExecuteEvents.Execute. This solution has the least amount of additional code.
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragAndDropHandler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IDragHandler, IBeginDragHandler, IEndDragHandler
{
// Don't forget to set this to TRUE or expose it to the Inspector else it will always be false and the script will not work
public bool Draggable { get; set; }
private bool draggingSlot;
[SerializeField] private ScrollRect scrollRect;
public void OnPointerDown(PointerEventData eventData)
{
if (!Draggable)
{
return;
}
StartCoroutine(StartTimer());
}
public void OnPointerExit(PointerEventData eventData)
{
StopAllCoroutines();
}
public void OnPointerUp(PointerEventData eventData)
{
StopAllCoroutines();
}
private IEnumerator StartTimer()
{
yield return new WaitForSeconds(0.5f);
draggingSlot = true;
}
public void OnBeginDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.beginDragHandler);
}
public void OnDrag(PointerEventData eventData)
{
if (draggingSlot)
{
//DO YOUR DRAGGING HERE
} else
{
//OR DO THE SCROLLRECT'S
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.dragHandler);
}
}
public void OnEndDrag(PointerEventData eventData)
{
ExecuteEvents.Execute(scrollRect.gameObject, eventData, ExecuteEvents.endDragHandler);
if (draggingSlot)
{
//END YOUR DRAGGING HERE
draggingSlot = false;
}
}
}
I've managed to find an easier solution.
Maybe it must be customized by special needs, but if you put this script on your items and make the setup, it should work.
It's not easy from a prefab, but I let a controller make this.
I find all UIElementDragger inside a specified GameObject and add the needed GO instances programmatically.
But can use this code out of the box if you don't use prefabs.
using UnityEngine;
using UnityEngine.EventSystems;
public class UIElementDragger : MonoBehaviour, IPointerUpHandler, IPointerDownHandler
{
/// <summary>
/// Offset in pixels horizontally (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetX = 40;
/// <summary>
/// Offset in pixels vertically (positive to right, negative to left)
/// </summary>
[Range(40, 100)]
public float offsetY = 40;
/// <summary>
/// The Panel where the item will set as Child to during drag
/// </summary>
public Transform parentRect;
/// <summary>
/// The GameObject where the item is at start
/// </summary>
public Transform homeWrapper;
/// <summary>
/// The Object where the mouse must be when pointer is up, to put it in this panel
/// </summary>
public Transform targetRect;
/// <summary>
/// The GameObject where the item should live after dropping
/// </summary>
public Transform targetWrapper;
private int siblingIndex;
private bool dragging;
private void Start()
{
siblingIndex = transform.GetSiblingIndex();
}
private void Update()
{
if (dragging)
{
transform.position = new Vector2(Input.mousePosition.x + offsetX, Input.mousePosition.y + offsetY);
}
}
public void OnPointerDown(PointerEventData eventData)
{
transform.parent = parentRect;
dragging = true;
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.pointerCurrentRaycast.gameObject.transform.IsChildOf(targetRect))
{
transform.parent = targetWrapper;
}
else
{
transform.parent = homeWrapper;
transform.SetSiblingIndex(siblingIndex);
}
dragging = false;
}
}
Here my solution, thank all.
I have to use a fake instance to keep the object over even if you move it down the list. I post a vertical and a horizontal solution. I hope it help
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragController : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
private RectTransform currentTransform;
private GameObject instancePrefab;
private GameObject mainContent;
private Vector3 initialePosition;
private int totalChild;
void Awake()
{
currentTransform = this.GetComponent<RectTransform>();
mainContent = currentTransform.parent.gameObject;
}
public void OnPointerDown(PointerEventData eventData)
{
initialePosition = currentTransform.position;
totalChild = mainContent.transform.childCount;
if (instancePrefab == null)
{
instancePrefab = Instantiate(this.gameObject, mainContent.transform.parent.transform);
instancePrefab.GetComponent<Image>().enabled = false;
}
}
public void OnDrag(PointerEventData eventData)
{
currentTransform.position = new Vector3(eventData.position.x, currentTransform.position.y, currentTransform.position.z);
if (instancePrefab != null)
{
instancePrefab.GetComponent<Image>().enabled = true;
currentTransform.GetComponent<Image>().enabled = false;
instancePrefab.transform.position = currentTransform.position;
}
for (int i = 0; i < totalChild; i++)
{
if (i != currentTransform.GetSiblingIndex())
{
Transform otherTransform = mainContent.transform.GetChild(i);
int distance = (int)Vector3.Distance(currentTransform.position, otherTransform.position);
if (distance <= 20)
{
Vector3 otherTransformOldPosition = otherTransform.position;
// Vertical
/*otherTransform.position = new Vector3(otherTransform.position.x, initialePosition.y,
otherTransform.position.z);
currentTransform.position = new Vector3(currentTransform.position.x, otherTransformOldPosition.y,
currentTransform.position.z);*/
// Horizontal
otherTransform.position = new Vector3(initialePosition.x, otherTransform.position.y,
otherTransform.position.z);
currentTransform.position = new Vector3(otherTransformOldPosition.x, currentTransform.position.y,
currentTransform.position.z);
currentTransform.SetSiblingIndex(otherTransform.GetSiblingIndex());
initialePosition = currentTransform.position;
}
}
}
}
public void OnPointerUp(PointerEventData eventData)
{
currentTransform.position = initialePosition;
instancePrefab.GetComponent<Image>().enabled = false;
currentTransform.GetComponent<Image>().enabled = true;
Destroy(instancePrefab);
instancePrefab = null;
}
}
You can just manually call ScrollRect events, because they are public. Smthing like this:
public void OnDrag(PointerEventData eventData)
{
_scrollRect.OnDrag(eventData);
}

MovieTexture Never Plays In Build

I have written a script to play OGG files as a MovieTexture, i've tried both embedded asset files and also from the web. The problem I'm having is that the videos play in debug move (When I hit the play button and test in the "Game" tab) but they never work when I build to an executable..
using UnityEngine;
namespace Assets.Scripts
{
[RequireComponent(typeof(AudioSource))]
public class VideoScreen : MonoBehaviour
{
public string videoUrl;
public bool autoPlay = true;
public bool loop = true;
public bool playAudio = true;
public float opacity = 1.0f;
private bool hasLoaded;
private MovieTexture movieTexture;
public void Start ()
{
if (string.IsNullOrEmpty(videoUrl))
{
return;
}
var data = new WWW(videoUrl);
movieTexture = data.movie as MovieTexture;
}
public void Update()
{
if (movieTexture.isReadyToPlay && !hasLoaded)
{
renderer.material = new Material(Shader.Find("Custom/Unlit Transparent Color")) { mainTexture = movieTexture };
audio.clip = movieTexture.audioClip;
SetLoop(loop);
if (autoPlay)
{
Play();
}
hasLoaded = true;
}
var textureColor = renderer.material.color;
textureColor.a = opacity;
renderer.material.color = textureColor;
}
private void Play()
{
movieTexture.Stop();
movieTexture.Play();
if (playAudio)
{
audio.Stop();
audio.Play();
}
}
private void Pause()
{
movieTexture.Pause();
if (playAudio)
{
audio.Pause();
}
}
private void Stop()
{
movieTexture.Stop();
if (playAudio)
{
audio.Stop();
}
}
private void SetLoop(bool loopStatus)
{
movieTexture.loop = loopStatus;
if (playAudio)
{
audio.loop = loopStatus;
}
}
}
}
Can anyone shed any light on this behaviour?
Thanks
Turns out the custom Transparent Diffuse shader I was using was causing the issue! Doh!!
renderer.material = new Material(Shader.Find("Custom/Unlit Transparent Color")) { mainTexture = movieTexture };
now becomes
renderer.material.mainTexture = movieTexture;