이거 만들자.
캔버스와 이미지(백그라운드) 를 생성
그리고 이미지를 450 X 450 으로 하고 색을 변경합니다.
bgm은 무조건 한개씩 재생하기 때문에. 싱글턴 패턴을 사용하는것이 유리하지만
객체지향 프로그래밍에 어긋나고 사용하기만하면 무조건 커플링이 발생하기 때문에 아직까지도 논쟁이 많은 패턴이다.
하지만 일단 사용은 해보자.
Singleton Pattern
1. 객체가 무조건 하나 일 것
2. 어디서나 접근이 가능할 것
3. 객체 생성이 불가능 할 것
(링크)
오디오 파일은
기본적으로 반응이 빨라야하고 바로바로 재생이 되는 .wav 형식을 사용하고
bgm 같은 지속적으로 재생이 되는오디오는 주로 .ogg 를 사용한다.
하이라키
UITimelineGroup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UITimelineGroup : MonoBehaviour
{
private enum EType { Backward, Forward}
public delegate void OnClickDelegate(float _time);
private OnClickDelegate onClickSkipCallback = null;
public OnClickDelegate OnClickSkipCallback { set { onClickSkipCallback = value; } }
private UITimeline timeline = null;
private Button[] skipBtns = null;
private void Awake()
{
timeline = GetComponentInChildren<UITimeline>();
skipBtns = GetComponentsInChildren<Button>();
skipBtns[(int)EType.Backward].onClick.AddListener(()=>
{
onClickSkipCallback?.Invoke(-10f);
});
skipBtns[(int)EType.Forward].onClick.AddListener(() =>
{
onClickSkipCallback?.Invoke(10f);
});
}
public void UpdateTimeline(float _ratio)
{
timeline.UpdateTimeline(_ratio);
}
}
UITimeline.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UITimeline : MonoBehaviour
{
[SerializeField] private RectTransform imgFrontTr = null;
/*[SerializeField, Range(0f,1f)] private float ratio = 0f;*/
private float maxWidth = 0f;
private void Start()
{
maxWidth = imgFrontTr.sizeDelta.x;
}
/* private void Update()
{
UpdateTimeLine(ratio);
}*/
public void UpdateTimeline(float _ratio)
{
Vector2 newSize = imgFrontTr.sizeDelta;
newSize.x = maxWidth * _ratio;
imgFrontTr.sizeDelta = newSize;
}
}
UIVolumeGroup.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class UIVolumeGroup : MonoBehaviour
{
public delegate void ChangedVolume(float _vol);
private ChangedVolume changedVolumeCallback = null;
[SerializeField] Slider sliderVolume = null;
[SerializeField] private TextMeshProUGUI textVolume = null;
private void Awake()
{
sliderVolume = GetComponentInChildren<Slider>();
textVolume = GetComponentInChildren<TextMeshProUGUI>();
}
private void Start()
{
UpdateVolumeText();
}
public void SetChangeVolumecallback(ChangedVolume _callback)
{
changedVolumeCallback = _callback;
}
public void OnChangedVolume(float _vol)
{
UpdateVolumeText();
changedVolumeCallback?.Invoke(_vol);
}
private void UpdateVolumeText()
{
textVolume.text = sliderVolume.value.ToString("F1");
}
public float GetVolume()
{
return sliderVolume.value;
}
}
UIimgBackGround.cs
using UnityEngine;
using UnityEngine.UI;
public class RainbowColor : MonoBehaviour
{
private Image image = null;
private float hue = 0f;
private float saturation = 1f;
private float value = 1f;
private float alpha = 0.59f; // 투명도를 150으로 고정
private float rainbowSpeed = 0.1f; // 무지개 색상 전환 속도 조절
private void Awake()
{
image = GetComponent<Image>();
}
private void Update()
{
// hue 값 증가하여 무지개 색상 생성
hue += rainbowSpeed * Time.deltaTime;
if (hue >= 1f)
hue -= 1f;
// HSV (Hue, Saturation, Value) 값을 RGB 색상으로 변환
Color color = Color.HSVToRGB(hue, saturation, value);
color.a = alpha; // 투명도 적용
// 이미지에 색상 적용
image.color = color;
}
}
UIControllerGroup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class UIControllerGroup : MonoBehaviour
{
public enum EType { Play, Pause, Stop }
private Button[] btns = null;
private void Awake()
{
btns = GetComponentsInChildren<Button>();
}
public void AddOnClickEvent(EType _type, UnityAction _action)
{
btns[(int)_type].onClick.AddListener(_action);
}
}
UIAudioPlayer.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
// 컴포넌트를 추가할때 요청이 됨
[RequireComponent(typeof(AudioSource))]
public class UIAudioPlayer : MonoBehaviour
{
private AudioSource audioSource = null;
private UIFileLoadGroup fileLoadGroup = null;
private UIFileNameGroup fileNameGroup = null;
private UIControllerGroup controllerGroup = null;
private UIVolumeGroup volumeGroup = null;
private UITimelineGroup timelineGroup = null;
private void Awake()
{
audioSource = GetComponent<AudioSource>();
if (!audioSource)
{
audioSource = gameObject.AddComponent<AudioSource>();
}
fileLoadGroup = GetComponentInChildren<UIFileLoadGroup>();
fileNameGroup = GetComponentInChildren<UIFileNameGroup>();
controllerGroup = GetComponentInChildren<UIControllerGroup>();
volumeGroup = GetComponentInChildren<UIVolumeGroup>();
timelineGroup = GetComponentInChildren<UITimelineGroup>();
}
private void Start()
{
//
// File Load
//
fileLoadGroup.OnClickFileLoadCallback = OnClickFileLoadCallback;
controllerGroup.AddOnClickEvent(UIControllerGroup.EType.Play, () =>
{
Debug.Log("Play");
audioSource?.Play();
});
//
// Controller
//
controllerGroup.AddOnClickEvent(UIControllerGroup.EType.Pause, () =>
{
Debug.Log("Pause");
if (audioSource.isPlaying)
{
audioSource.Pause();
}
else
{
audioSource.UnPause();
}
});
controllerGroup.AddOnClickEvent(UIControllerGroup.EType.Stop, () =>
{
Debug.Log("Stop");
audioSource?.Stop();
timelineGroup.UpdateTimeline(0f);
});
//
// Volume
//
audioSource.volume = volumeGroup.GetVolume();
volumeGroup.SetChangeVolumecallback((float _vol) =>
{
audioSource.volume = _vol;
});
//
// Timeline
//
timelineGroup.UpdateTimeline(0f);
timelineGroup.OnClickSkipCallback = OnClickSkipCallback;
}
private void Update()
{
if (audioSource.isPlaying)
{
UpdateTimeline();
}
}
private void OnClickFileLoadCallback(AudioClip _clip)
{
fileNameGroup.SetFileName(_clip.name);
audioSource.clip = _clip;
}
private void UpdateTimeline()
{
float clipLength = audioSource.clip.length;
float time = audioSource.time;
// audioSource.timeSamples라는게 있는데 time보다 정교하다 리듬게임 만들때 사용
float ratio = time / clipLength;
timelineGroup.UpdateTimeline(ratio);
}
private void OnClickSkipCallback(float _time)
{
float skipTime = audioSource.time + _time;
skipTime = Mathf.Clamp(skipTime, 0f, audioSource.clip.length - 0.001f);
audioSource.time = skipTime;
timelineGroup.UpdateTimeline(skipTime);
}
}
UIFileNameGroup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class UIFileNameGroup : MonoBehaviour
{
private TextMeshProUGUI textFileName = null;
private void Awake()
{
textFileName = GetComponentInChildren<TextMeshProUGUI>();
}
public void SetFileName(string _fileName)
{
textFileName.text = _fileName;
}
}
ResourceManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Singleton Pattern
//1. 객체가 무조건 하나 일 것
//2. 어디서나 접근이 가능할 것
//3. 객체 생성이 불가능 할 것
public class ResourceManager
{
private static ResourceManager instance = null;
public static ResourceManager Instance
{
get
{
if(instance == null)
{
instance = new ResourceManager();
}
return instance;
}
}
//이렇게하면 객체 생성이 불가능하다.
private ResourceManager(){}
private const string audioPath = "Audios\\";
private Dictionary<string, AudioClip> dicAudioClips = new Dictionary<string, AudioClip>();
public AudioClip LoadAudioClip(string _fileName)
{
//실제 파일이 있는지 예외처리
if (dicAudioClips.ContainsKey(_fileName))
{
Debug.Log("Contains : " + _fileName);
return dicAudioClips[_fileName];
}
AudioClip clip = Resources.Load<AudioClip>(audioPath + _fileName);
/*AudioClip audio = Resources.Load(_path) as AudioClip;
AudioClip ac = (AudioClip)Resources.Load(_path);*/
Debug.Log("Add : " + _fileName);
dicAudioClips.Add(_fileName, clip);
return clip;
}
}