저번에 작성한 코드를 한 번씩 더 써가면서 다른 UI를 자동화 해보았다.
구현한 UI는 게임에서 흔히 사용하는 HP, MP를 표시하는 상태창(씬), 인벤토리(팝업), 게임오버(씬)이다.
팝업 UI는 화면에 나타났다가 없어질 수 있는 UI 이며, 씬 UI는 화면에 고정되어 있는 UI이다.
사실 게임오버 UI는 팝업으로 처리해도 되지만, 다시 재시작 하지 않고 그대로 끝내야 하는 게임의 경우 씬 UI로 관리해도 문제 없을 것 같다고 생각 했다.
아래는 저번에 작성한 코드를 포스팅 하였다.
[UNITY] UI 자동화(1) - 인벤토리 구현
일단 결론부터 말하자면 Scene을 관리하는 Scene 객체에 붙여서, Scene이 로드되면 SceneUI를 불러오는 코드이다. 자동화를 해놓았기 때문에, 코드 한 줄만 작성하면 된다. GameScene.cs using System.Collections;
mainsdev.tistory.com
[UNITY] UI 자동화(2) - 인벤토리 구현
[UNITY] UI 자동화(1) - 인벤토리 구현 일단 결론부터 말하자면 Scene을 관리하는 Scene 객체에 붙여서, Scene이 로드되면 SceneUI를 불러오는 코드이다. 자동화를 해놓았기 때문에, 코드 한 줄만 작성하면
mainsdev.tistory.com
먼저 상태창 UI 이다.
빈 오브젝트 아래에 Canvas를 만들고, Panel을 추가하고 그 아래에 Slider를 이용하여 Bar를 표현하였다
간단하게 만든 후 코드로 넘어가 보겠다.
Slider의 Value 값을 조정하여 Bar에서 표시되는 정도를 조절할 수 있는데, 이것을 UI_Status라는 코드로 관리를 하려고 한다.
UI_Status.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UI_Status : UI_Scene
{
public static float _hp;
float _mp;
GameObject _hpBar;
GameObject _mpBar;
enum GameObjects
{
statusPanel,
}
enum StatusBar
{
HpText,
MpText,
HpBar,
MpBar
}
public override void Init()
{
Bind<GameObject>(typeof(StatusBar));
Get<GameObject>((int)StatusBar.HpText).GetComponent<Text>().text = "HP";
Get<GameObject>((int)StatusBar.MpText).GetComponent<Text>().text = "MP";
_hpBar = Get<GameObject>((int)StatusBar.HpBar);
_mpBar = Get<GameObject>((int)StatusBar.MpBar);
SetHP(1);
SetMP(1);
_hpBar.GetComponent<Slider>().value = _hp;
_mpBar.GetComponent<Slider>().value = _mp;
}
private void Start()
{
Init();
}
private void Update()
{
UpdateStatusBar();
}
public static void SetHP(float hp)
{
_hp = hp;
}
public void SetMP(float mp)
{
_mp = mp;
}
public void UpdateStatusBar()
{
_hpBar.GetComponent<Slider>().value = _hp;
_mpBar.GetComponent<Slider>().value = _mp;
}
}
먼저, 프리팹을 불러와서 Bind를 한다. 프리팹에 있는 statusPanel을 이용하여 객체를 찾고, StatusBar enum에 작성해 둔 각각의 컴포넌트들을 불러와서 UI를 설정한다.
UpdateStatusBar 함수를 계속 실행시켜 HP와 MP가 바뀔때마다 Slider의 Value를 바꾸어준다.
또한 SetHP와 SetMP 라는 함수를 만들어 UI의 Slider Value 값이 바뀌는 것을 테스트 하였다.
PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlayerController : MonoBehaviour
{
enum PlayerState
{
Idle,
Moving,
Dead
}
[SerializeField]
float _speed = 10;
PlayerState _state = PlayerState.Idle;
Vector3 _destPos;
float _hp;
UI_Gameover _gameover = null;
GameObject obj;
void Start()
{
_hp = 1.0f;
Managers.Input.KeyAction -= OnKeyBoard;
Managers.Input.KeyAction += OnKeyBoard;
Managers.Input.KeyAction -= OnInven;
Managers.Input.KeyAction += OnInven;
//Managers.Input.MouseAction -= OnMouseClicked;
//Managers.Input.MouseAction += OnMouseClicked;
Managers.UI.ShowSceneUI<UI_Status>();
}
private void Update()
{
switch (_state)
{
case PlayerState.Idle:
UpdateIdle();
break;
case PlayerState.Moving:
UpdateMoving();
break;
case PlayerState.Dead:
UpdateDead();
break;
}
}
void UpdateDead()
{
if (_gameover != null)
return;
_gameover = Managers.UI.ShowSceneUI<UI_Gameover>();
Managers.Input.KeyAction -= OnKeyBoard;
Managers.Input.KeyAction -= OnInven;
Managers.Input.KeyAction += AfterDead;
}
void UpdateIdle()
{
Managers.Input.KeyAction -= AfterDead;
}
void UpdateMoving()
{
Vector3 dir = _destPos - transform.position;
if (dir.magnitude < 0.01f)
{
_state = PlayerState.Idle;
}
else
{
float moveDist = Mathf.Clamp(_speed * Time.deltaTime, 0, dir.magnitude);
transform.position += dir.normalized * moveDist;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 0.2f);
}
}
void OnKeyBoard()
{
if (Input.GetKey(KeyCode.W))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);
transform.position += Vector3.forward * Time.deltaTime * _speed;
}
if (Input.GetKey(KeyCode.A))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);
transform.position += Vector3.left * Time.deltaTime * _speed;
}
if (Input.GetKey(KeyCode.S))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);
transform.position += Vector3.back * Time.deltaTime * _speed;
}
if (Input.GetKey(KeyCode.D))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);
transform.position += Vector3.right * Time.deltaTime * _speed;
}
}
void OnInven()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
if (Managers.UI.isPopupOpen())
{
Managers.UI.ClosePopupUI();
}
else
{
Managers.UI.ShowPopupUI<UI_Inven>();
}
}
}
void AfterDead()
{
if (Input.GetKeyDown(KeyCode.Space))
{
UI_Status.SetHP(1.0f);
_hp = 1.0f;
Managers.Input.KeyAction += OnKeyBoard;
Managers.Input.KeyAction += OnInven;
obj = Managers.UI.GetSceneUI<UI_Gameover>("UI_Gameover");
Destroy(obj);
this.transform.position = new Vector3(0, 0, 0);
_state = PlayerState.Idle;
}
}
void OnMouseClicked()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.yellow, 1.0f);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f))
{
if (EventSystem.current.IsPointerOverGameObject() == false)
{
_destPos = hit.point;
_state = PlayerState.Moving;
Debug.Log(hit.collider);
}
}
}
private void OnTriggerEnter(Collider other)
{
if (other.name == "Capsule")
{
if (_hp <= 0.0f)
{
_state = PlayerState.Dead;
}
_hp -= 0.1f;
UI_Status.SetHP(_hp);
}
if (other.name == "Heal")
{
if (_hp >= 1.0f)
{
_hp = 1.0f;
return;
}
_hp += 0.1f;
UI_Status.SetHP(_hp);
}
}
}
오브젝트를 만들어 Collider의 Is Trigger 옵션을 이용하였다. 캡슐에 닿을 때마다 Hp를 10%씩 감소하여, MP가 0 이하가 될 시, PlayerState.Dead 상태로 만들어 UpdateDead 함수를 실행 시킨다.
만약 게임오버 UI가 없을 시, UI를 만들어서 보여주고 InputManager에 다른 입력들은 제거하여 아무 행동을 할 수 없게 만든 뒤, AfterDead 함수를 추가하여 Space를 눌렀을 때 재시작하는 함수를 만들어서 붙여 주었다.
위의 GetSceneUI 함수는 Destroy하기 위해 임시로 추가한 코드이다.
GetSceneUI
public GameObject GetSceneUI<T>(string name) where T : UI_Scene
{
GameObject go = GameObject.Find("@Root_UI");
GameObject obj = Util.FindChild(go, name, true);
return obj;
}
'UNITY' 카테고리의 다른 글
UNITY - Object Pooling (1) | 2024.01.23 |
---|---|
UNITY - SoundManager (0) | 2024.01.22 |
UNITY - Scene (1) | 2024.01.12 |
UNITY - Animation - Animator Controller를 활용한 애니메이션 전환 (3) | 2024.01.12 |
UNITY - Camera - 마우스 클릭으로 이동하기 (0) | 2024.01.12 |