공부/인프런 - Rookiss

Part 3-13-5. 미니 RPG : 체력 게이지

셩잇님 2023. 8. 31. 19:13
반응형

 

 

미니 RPG

 

체력 게이지 UI 만들기

 

 

체력 게이지는 몬스터와 플레이어 위에 따라다녀야함. 그러니 원근법 적용이 되야 한다. 3D 오브젝트처럼! 따라서 캔버스 렌더러 모드를 World Space로 바꿔준다.

 

 

UI_HPBar : 캔버스

👉 RenderMode는 WorldSpace. 이땐 이 캔버스를 찍을 카메라도 할당해주어야 하는데, RenderMode, Camera 둘 다 코드로 로드해줄 것이다.

HPBar : 슬라이더

 

이제 캔버스는 게임 월드 기준 좌표를 가지므로 캔버스와 슬라이더의 위치와 크기를 잘 맞춰주고 최종적으로 UI_HPBar 캔버스를 프리팹으로 만들어준다. 게임이 시작되면 몬스터와 플레이어의 산하 자식으로 Instantiate 시켜주어 몬스터와 플레이어를 따라다니게 할 것이다.

 

공격시 체력 깎기

로드하기

 

📜UI_HPBar

public class UI_HPBar : UI_Base
{
    enum GameObjects
    {
        HPBar
    }

    Stat _stat;
    public override void Init()
    {
        Bind<GameObject>(typeof(GameObjects));
        _stat = transform.parent.GetComponent<Stat>();
    }

    void Start()
    {
        Init();
    }

 

이 스크립트는 📜UIManger의 MakeWorldSpace 함수를 통해 UP_HPBar 캔버스에 붙을 예정

Bind를 통해 UP_HPBar의 자식인 HPBar 오브젝트(슬라이더)가 캐싱 된다.

플레이어의 스탯을 슬라이더에 적용시킬 수 있도록 📜Stat 로딩

 

📜UIManager

    public T MakeWorldSpace<T>(Transform parent = null, string name = null) where T : UI_Base
    {
        if (string.IsNullOrEmpty(name))
            name = typeof(T).Name;

        GameObject go = Managers.Resource.Instantiate($"UI/WorldSpace/{name}");
        if (parent != null)
            go.transform.SetParent(parent);

        Canvas canvas = go.GetComponent<Canvas>();
        canvas.renderMode = RenderMode.WorldSpace;
        canvas.worldCamera = Camera.main;

        return Util.GetOrAddComponent<T>(go);
    }

 

MakeWorldSpace

1. 📂UI/WorldSpace 에 있는 캔버스 프리팹을 로드하여 parent 산하에 붙여주는 함수

2. WorldSpace 모드의 캔버스만 붙일 것이다.

3. 캔버스 설정 👉 로드한 캔버스 프리팹의 렌더러 모드는 WorldSpace로, 카메라는 메인 카메라로 설정

4. go에게 T를 붙인다. 즉, 캔버스 프리팹에 원하는 스크립트를 붙일 것.

 

📜PlayerController

    void Start()
    {
		//...
		Managers.UI.MakeWorldSpace<UI_HPBar>(transform);
    }

 

transform(플레이어 본인)의 자식으로 UI_HPBar 프리팹을 로드한다. 그리고 📜UI_HPBar를 붙여준다.

 

게임이 시작되면 자동으로 이렇게 unityChan에 스크립트가 붙고 저렇게 캔버스 설정도 완료될 것이다.

체력 게이지에 깎인 체력 반영한다. (+ 빌보드)

 

📜UI_HPBar

    void Update()
    {
        Transform parent = transform.parent;  
        transform.position = parent.position + Vector3.up * (parent.GetComponent<Collider>().bounds.size.y);
        transform.rotation = Camera.main.transform.rotation;  // 빌보드

        float ratio = _stat.Hp / (float)_stat.MaxHp;
        SetHpRatio(ratio);  // 슬라이더 값 매 프레임마다 갱신
    }

    public void SetHpRatio(float ratio)
    {
        GetObject((int)GameObjects.HPBar).GetComponent<Slider>().value = ratio;
    }

 

1. parent는 이 📜UI_HPBar가 붙는 UI_HPBar의 부모인 플레이어가 된다. transform은 UI_HPBar

2. UI_HPBar의 위치는 부모인 플레이어의 머리 위에 있도록 플레이어의 Collider 경계의 상단에 위시치키도록 한다.

3. UI_HPBar는 회전하면 안된다. UI_HPBar도 WorldSpace로서 3D 오브젝트 취급을 받는 캔버스이므로 플레이어의 머리 위에 있다보면 플레이어 따라 같이 회전할 수 있다. 따라서 카메라의 회전값과 동일하게 해주어 오로지 카메라만 고정적으로 바라보도록 계속해서 회전시켜야 한다. 즉, 부모인 플레이어의 회전값을 따라가는게 아니라, 카메라를 고정적으로 바라보도록 계속 회전시킴. 👉 이게 빌보드의 개념이다.

  • 빌보드란 카메라가 어느 방향을 보고 있던간에 정면이 늘 카메라를 향하도록 하는 기능이다.
transform.rotation = Camera.main.transform.rotation;

 

📜PlayerController

	void OnHitEvent()
	{
		if (_lockTarget != null)
        {
			Stat targetStat = _lockTarget.GetComponent<Stat>();
			PlayerStat myStat = gameObject.GetComponent<PlayerStat>();
			int damage = Mathf.Max(0, myStat.Attack - targetStat.Defense); // 음수되면 0 이 되게끔
			targetStat.Hp -= damage;
		}

		if (_stopSkill)
		{
			State = PlayerState.Idle;
		}
		else
		{
			State = PlayerState.Skill;
		}
	}

 

공격 애니메이션 때리는 타이밍에 OnHitEvent 이벤트가 발생하게 한다. 이 때 공격할 대상인 _lockTarget 오브젝트에서 📜Stat 을 가져와 상대방의 체력을 공격력만큼 깎는다.

 

 

반응형