목차
1. 개요
2. 프로토타입 게임
3. 핵심 소스코드 및 설명
4. 유니티 세팅 방법
1. 개요
게임 중에 음성을 인식하여 진행하는 방식의 하이퍼 캐주얼 게임이 있다.
주목할만한 점은 게임성만을 놓고 봤을때 그렇게 중독성이 있거나 하지는 않지만 유튜버들이 이목을 끌기 좋은 콘텐츠라서 유튜버들이 올리면 사람들이 많이 본다.
인플루언서들(influncer) 마케팅을 통하여 해당 게임이 성장하였다고 추측된다.
이번 글에서는 음성인식 게임의 핵심 부분을 다뤄보고자 한다.
2. 프로토타입 게임
캐릭터는 계속해서 이동하고 소리를 내면(어디 아픈 사람 같지만 아니다.) 내 공의 색이 바뀐다. 공의 색이 바뀐동안 상대방 공을 때린다고 생각하면 된다.
소리를 내서 펀치나 발차기를 하는 게임이라고 상상하자
엄마는 게임기를 숨겼다. 느낌의 게임이라고 생각하면 된다.
소리를 내서 불량배들을 쫓아내는 게임이다.
3. 핵심 소스코드 및 설명
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
public class MicrophoneListener : MonoBehaviour
{
[SerializeField] private Image _imageSound;
[SerializeField] private Text TextVol;
public float sensitivity = 100;
public float loudness = 0;
public float pitch = 0;
AudioSource _audio;
public float RmsValue;
public float DbValue;
public float PitchValue;
private const int QSamples = 1024;
private const float RefValue = 0.1f;
private const float Threshold = 0.02f;
float[] _samples;
private float[] _spectrum;
private float _fSample;
//Written in part by Benjamin Outram
//option to toggle the microphone listenter on startup or not
public bool startMicOnStartup = true;
//allows start and stop of listener at run time within the unity editor
public bool stopMicrophoneListener = false;
public bool startMicrophoneListener = false;
private bool microphoneListenerOn = false;
//public to allow temporary listening over the speakers if you want of the mic output
//but internally it toggles the output sound to the speakers of the audiosource depending
//on if the microphone listener is on or off
public bool disableOutputSound = false;
//an audio source also attached to the same object as this script is
AudioSource src;
//make an audio mixer from the "create" menu, then drag it into the public field on this script.
//double click the audio mixer and next to the "groups" section, click the "+" icon to add a
//child to the master group, rename it to "microphone". Then in the audio source, in the "output" option,
//select this child of the master you have just created.
//go back to the audiomixer inspector window, and click the "microphone" you just created, then in the
//inspector window, right click "Volume" and select "Expose Volume (of Microphone)" to script,
//then back in the audiomixer window, in the corner click "Exposed Parameters", click on the "MyExposedParameter"
//and rename it to "Volume"
public AudioMixer masterMixer;
float timeSinceRestart = 0;
void Start() {
//start the microphone listener
if (startMicOnStartup) {
RestartMicrophoneListener ();
StartMicrophoneListener ();
_audio = GetComponent<AudioSource> ();
_audio.clip = Microphone.Start (null, true, 10, 44100);
_audio.loop = true;
while (!(Microphone.GetPosition(null) > 0)) {}
_audio.Play();
_samples = new float[QSamples];
_spectrum = new float[QSamples];
_fSample = AudioSettings.outputSampleRate;
//유니티 5.x 부터는 audio source에서 mute를 하면 정상적으로 음성이 안나온다.
//audio mixer에서 master volume의 db를 -80으로 하여 소리 출력만 안되도록 하면 된다.
//_audio.mute = true;
}
}
void Update(){
//can use these variables that appear in the inspector, or can call the public functions directly from other scripts
if (stopMicrophoneListener) {
StopMicrophoneListener ();
}
if (startMicrophoneListener) {
StartMicrophoneListener ();
}
//reset paramters to false because only want to execute once
stopMicrophoneListener = false;
startMicrophoneListener = false;
//must run in update otherwise it doesnt seem to work
MicrophoneIntoAudioSource (microphoneListenerOn);
//can choose to unmute sound from inspector if desired
DisableSound (!disableOutputSound);
loudness = GetAveragedVolume() * sensitivity;
GetPitch();
//아래는 커스텀 한 소스
//소리가
if (loudness > 5f)
_imageSound.fillAmount = 1f;
else
{
_imageSound.fillAmount = 0.65f;
}
FindObjectOfType<GameManager>().currentLoud = loudness;
//TextVol.text = "vol:" + loudness;
}
float GetAveragedVolume() {
float[] data = new float[256];
float a = 0;
_audio.GetOutputData (data, 0);
foreach(float s in data)
{
a+=Mathf.Abs(s);
}
return a/256;
}
void GetPitch() {
GetComponent<AudioSource>().GetOutputData(_samples, 0); // fill array with samples
int i;
float sum = 0;
for (i = 0; i < QSamples; i++)
{
sum += _samples[i] * _samples[i]; // sum squared samples
}
RmsValue = Mathf.Sqrt(sum / QSamples); // rms = square root of average
DbValue = 20 * Mathf.Log10(RmsValue / RefValue); // calculate dB
if (DbValue < -160) DbValue = -160; // clamp it to -160dB min
// get sound spectrum
GetComponent<AudioSource>().GetSpectrumData(_spectrum, 0, FFTWindow.BlackmanHarris);
float maxV = 0;
var maxN = 0;
for (i = 0; i < QSamples; i++)
{ // find max
if (!(_spectrum[i] > maxV) || !(_spectrum[i] > Threshold))
continue;
maxV = _spectrum[i];
maxN = i; // maxN is the index of max
}
float freqN = maxN; // pass the index to a float variable
if (maxN > 0 && maxN < QSamples - 1)
{ // interpolate index using neighbours
var dL = _spectrum[maxN - 1] / _spectrum[maxN];
var dR = _spectrum[maxN + 1] / _spectrum[maxN];
freqN += 0.5f * (dR * dR - dL * dL);
}
PitchValue = freqN * (_fSample / 2) / QSamples; // convert index to frequency
}
//stops everything and returns audioclip to null
public void StopMicrophoneListener(){
//stop the microphone listener
microphoneListenerOn = false;
//reenable the master sound in mixer
disableOutputSound = false;
//remove mic from audiosource clip
src.Stop ();
src.clip = null;
Microphone.End (null);
}
public void StartMicrophoneListener(){
//start the microphone listener
microphoneListenerOn = true;
//disable sound output (dont want to hear mic input on the output!)
disableOutputSound = true;
//reset the audiosource
RestartMicrophoneListener ();
}
//controls whether the volume is on or off, use "off" for mic input (dont want to hear your own voice input!)
//and "on" for music input
public void DisableSound(bool SoundOn){
float volume = 0;
if (SoundOn) {
volume = 0.0f;
} else {
volume = -80.0f;
}
masterMixer.SetFloat ("MasterVolume", volume);
}
// restart microphone removes the clip from the audiosource
public void RestartMicrophoneListener(){
src = GetComponent<AudioSource>();
//remove any soundfile in the audiosource
src.clip = null;
timeSinceRestart = Time.time;
}
//puts the mic into the audiosource
void MicrophoneIntoAudioSource (bool MicrophoneListenerOn){
if(MicrophoneListenerOn){
//pause a little before setting clip to avoid lag and bugginess
if (Time.time - timeSinceRestart > 0.5f && !Microphone.IsRecording (null)) {
src.clip = Microphone.Start (null, true, 10, 44100);
//wait until microphone position is found (?)
while (!(Microphone.GetPosition (null) > 0)) {
}
src.Play (); // Play the audio source
}
}
}}
여기 업데이트 부분을 보면 loudness가 소리 크기를 받아오는 부분이고 GetPitch 함수를 통해 PitchValue에 소리의 높낮이 값을 저장한다.
4. 유니티 세팅 방법
위의 소스코드만 넣는다고 해서 바로 적용이 되지는 않는다.
인터넷에 돌아다니는 소스 코드를 적용해보았더니 내가 내는 소리가 출력이 되어야지 작동을 했었다.
(audio source에 mute를 넣으면 작동을 안함)
프로젝트 우클릭 > Create > Audio Mixer 생성
생성된 Audio Mixer 더블클릭 > Groups 새로 생성
새로 생성한 그룹의 이름을 microphone이라고 지정
새로 생성한 그룹 클릭 > 우측에 Volume이 보이는데 우클릭
첫 번째 메뉴 선택
우측 상단에 Exposed Parameters 생성됨 > 클릭
이미 이름이 지정되어 있는데 Volume으로 이름 변경
Master 그룹의 dB를 -80으로 변경
유니티 인스펙터에서 MicrophoneListener 컴포넌트에 다음과 같이 등록
'Unity > 강좌' 카테고리의 다른 글
유니티 ragdoll 발사하기 - 1.목차 (0) | 2019.08.16 |
---|---|
유니티 게임 개발 따라하기 JJTAN - 2. 공 발사하는 캐논 설정 (0) | 2019.06.22 |
유니티 게임 개발 따라하기 JJTAN - 1.프로토타입 수준의 오브젝트 및 환경 설정 (0) | 2019.06.20 |
유니티 로컬라이제이션 (4) | 2019.06.13 |
유니티 게임 개발 따라하기 JJTAN (0) | 2019.05.24 |