이후 내가 맡은 역할인 타이머 구현 단계에 돌입하였다.
<문제>
타이머가 시작된 시점이 Countdown이 완료된 후에 타이머가 시작되어야한다. 하지만 기존의 Countdown 코드에서는 게임의 시작을 알리는 코드가 없다.
<해결>
보다 더 효율적으로 게임을 관리하기 위해 게임의 상태를 관리하는 상태관리Manager를 만들었다.
1. PlayStateManager를 만들어서 게임 상태를 get하거나 set한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Play State
public enum Play_State
{
Ready,
Start,
Playing,
GameOver,
End,
}
public class PlayStateManager
{
private Play_State state;
public void Init()
{
GameObject root = GameObject.Find("@PlayState");
if (root == null)
{
root = new GameObject { name = "@PlayState" };
Object.DontDestroyOnLoad(root);
root.AddComponent<PlayState>();
}
}
// 현재 상태 바꿈
public void Set_State(Play_State state)
{
this.state = state;
}
public Play_State Get_State()
{
return this.state;
}
public void Clear_state()
{
this.state = Play_State.Ready;
}
}
2. PlayState를 Scene에 놓아서 게임하는 동안에 게임 안의 플레이어의 상태를 관리한다.
아래와 같이 처음 게임을 시작할때 Counddown이 시작되기 때문에 Start함수에서 게임의 상태를 Ready 상태로 해준다.
이후 Update로 매 프레임마다 게임의 상태를 점검하여 게임의 상태가 Start가 되면 onPlayStart.Invoke()로 Start시 실행해야하는 함수 이벤트가 발생한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class PlayState: MonoBehaviour
{
private Play_State current_state;
public UnityEvent onPlayReady;
public UnityEvent onPlayStart;
public UnityEvent onPlaying;
public UnityEvent onPlayEnd;
private void End()
{
Debug.Log("Play Stop");
onPlayEnd.Invoke();
}
void Start()
{
// 시작 할 때의
Managers.State.Set_State(Play_State.Ready);
}
void Update()
{
current_state = Managers.State.Get_State();
Debug.Log($"현재 상태: { current_state }");
switch (current_state)
{
case Play_State.Ready:
// countdown 시작
// 자동차 멈춤
// 자동차 감점 감지
break;
case Play_State.Start:
Debug.Log("Play Start");
onPlayStart.Invoke();
Managers.State.Set_State(Play_State.Playing);
break;
case Play_State.Playing:
break;
}
}
}
3. Timer에서는 타이머를 동작한다.
TimerisRunning은 타이머가 동작하는지에 대한 boolean값으로 게임 시작 전 Awake 함수에서 TimerisRunning을 false로 설정한다.
추가로 Awake에서는 타이머의 OnPlayStart 함수 이벤트를 PlayState의 OnPlayStart에 이벤트로 한다.
public void OnPlayStart()
{
TimerisRunning = true;
}
private void Awake()
{
TimerisRunning = false;
// Text assignment
ClockText = Util.FindChild<Text>(GameObject.Find("TimerUI"), "TimeText", true);
GameObject.Find("@PlayState").GetComponent<PlayState>().onPlayStart.AddListener(OnPlayStart);
}
4. Countdown 코드에서 카운트다운을 한 후 게임의 상태를 Start로 바꿔주는 코드를 추가한다.
IEnumerator CountStart()
{
Managers.Sound.Play("Car/startup", Define.Sound.PlayStart);
Managers.Sound.Play("Car/idle", Define.Sound.Idle);
yield return new WaitForSeconds(0.5f);
countdown.GetComponent<Text>().text = "5";
Managers.Sound.Play("Car/readyup", Define.Sound.Ready, 0.5f);
countdown.SetActive(true);
yield return new WaitForSeconds(1);
countdown.SetActive(false);
countdown.GetComponent<Text>().text = "4";
Managers.Sound.Play("Car/readyup", Define.Sound.Ready, 0.5f);
countdown.SetActive(true);
yield return new WaitForSeconds(1);
countdown.SetActive(false);
countdown.GetComponent<Text>().text = "3";
Managers.Sound.Play("Car/readyup", Define.Sound.Ready, 0.5f);
countdown.SetActive(true);
yield return new WaitForSeconds(1);
countdown.SetActive(false);
countdown.GetComponent<Text>().text = "2";
Managers.Sound.Play("Car/readyup", Define.Sound.Ready, 0.5f);
countdown.SetActive(true);
yield return new WaitForSeconds(1);
countdown.SetActive(false);
countdown.GetComponent<Text>().text = "1";
Managers.Sound.Play("Car/readyup", Define.Sound.Ready, 0.5f);
countdown.SetActive(true);
yield return new WaitForSeconds(1);
countdown.SetActive(false);
//LapTimer.SetActive(true);
carController.wheelColliders[0].brakeTorque = 0;
carController.wheelColliders[1].brakeTorque = 0;
// Play State & Background music start
Managers.State.Set_State(Play_State.Start);
Managers.Sound.Play("Car/Zephyr", Define.Sound.Background); // Idle 하고 Background 음악 두 가지 동시에 수정 요망!
}
5. 게임의 상태를 Start로 바꾸면 PlayState의 OnPlayStart.Invoke로 이벤트로 등록된 함수가 실행된다.
Timer의 OnPlayStart 함수가 실행되어 TimerisRunning값이 true로 바뀌고 타이머가 시작된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text ClockText;
float time;
bool TimerisRunning = false;
public float timeRemaining = 10;
public void OnPlayStart()
{
TimerisRunning = true;
}
private void Awake()
{
TimerisRunning = false;
// Text assignment
ClockText = Util.FindChild<Text>(GameObject.Find("TimerUI"), "TimeText", true);
GameObject.Find("@PlayState").GetComponent<PlayState>().onPlayStart.AddListener(OnPlayStart);
}
void Start()
{
// 한 Frame 기다리기
StartCoroutine(WaitFrame());
}
IEnumerator WaitFrame()
{
yield return new WaitForSeconds(1.0f);
}
// Update is called once per frame
void Update()
{
if (TimerisRunning)
{
if (timeRemaining > 0)
{
timeRemaining -= Time.deltaTime;
DisPlayTime(timeRemaining);
}
else
{
Debug.Log("Time is over!!");
Managers.Score.ScoreOut(Define.ScoreOut.TimerOut);
TimerisRunning = false;
}
}
}
void DisPlayTime(float time)
{
time += 1;
float minutes = Mathf.FloorToInt(time / 60);
float seconds = Mathf.FloorToInt(time % 60);
ClockText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
<결과>
위와 같이 유니티 이벤트를 사용하여 스파게티 코드를 줄여 효율적으로 코딩하였다. 다만, 게임 개발을 처음 해봐서 이러한 유니티 이벤트 기술을 게임의 전반에서 효율적으로 사용하지 못한 거 같아 아쉬움이 남는다.
ref)
[Unity3D] 타이머를 설정하는 방법
유니티를 개발할때 일정 시간 이후 이벤트를 걸어야 할 경우가 많습니다! 이럴때 어떻게 타이머를 설정해야 할까요? 그 방법에 대해서 빠르게 알아보겠습니다. 오늘 설명할 방법은 3가지입니다.
studio108.tistory.com
유니티 이벤트 완벽하게 이해하기 1
유니티 이벤트에 대해 정리해 보았습니다. Unity 이벤트 C#의 이벤트와 델리게이트를 유니티가 사용하기 편하도록 랩핑 해놓은 것입니다. 이벤트를 발동시키는 측도 그 이벤트에 기능을 등록시켜
daebalstudio.tistory.com
https://ansohxxn.github.io/unity%20lesson%201/chapter8-1/
Unity Chapter 8-1. C# 프로그래밍 [고급] : 유니티 이벤트
인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀 🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!
ansohxxn.github.io
https://chameleonstudio.tistory.com/37
유니티 인보크 Invoke 사용법의 모든 것
해당 티스토리 페이지는 필자가 유니티 C# 개발을 하면서 학습한 내용들을 기록하고 공유하는 페이지입니다 ! - 틀린 부분이 있거나, 수정된 부분이 있다면 댓글로 알려주세요 ! - 해당 내용을 공
chameleonstudio.tistory.com
'Project > VR 기반 운전 시뮬레이션: 안전 "안전 운전만해" 프로젝트' 카테고리의 다른 글
[Part 12] 주차 성공에 대한 추가 코드 (0) | 2022.05.15 |
---|---|
[Part 11] 채점 알고리즘 & Trigger, Collsion (0) | 2022.05.14 |
[Part 9] 사용자 게임 Scene에 놓기 (0) | 2022.05.14 |
[Part 8] 주차장 맵 제작 및 이벤트 구현: Waypoint System (0) | 2022.05.14 |
[Part 7] 하드웨어 장비 구매, 역할 설정, 일정 정리 및 공부 (0) | 2022.05.14 |