본문 바로가기
게임 개발/유니티 게임 개발 일지

#11 적 HpBarUI 구현하기

by FlowTree 2020. 4. 11.
반응형

1.구현 의도(Simple is best. 너무 복잡하게 생각하지말자)

  • 쿼터뷰 시점에서 플레이어에게 한 눈에 파악 + 직관적이게 적의 Hp 정보 제공하기

 

1.1.적 HpBarUI 위치

1.HpBar 없음

적 HpBar가 없으면 감에 의존해서 처리해야한다. 경험이 쌓이면 빠르게 적을 처치할 수 있으나 다수의 적과의 전투에서는 어느 적이 체력이 감소된 적인이 판단이 불가능하고, 신속하게 적의 수를 줄여야하는데(체력이 적은 적을 식별)판단 근거를 찾을 수 없다. 따라서 HpBar 필요

   

2.적 캐릭터 바닥

쿼터뷰 시점이여서 바닥의 원형 HpBar이면 식별하기 좋으나 기존의 타겟팅UI와 겹치고, 여러 적이 뭉쳐있으면 HpBar 겹쳐지는 문제가 발생한다.

 

3.적 캐릭터 머리 위

대다수의 게임에서 볼 수 있는 가장 익숙한 HpBar 위치이다. 각 적 머리위에 직사각형의 HpBar를 출력하면 쿼터뷰 시점에서도 직관성 좋고, 적의 남은 Hp정보도 한 눈에 알 수 있어서 전투 시 플레이어의 판단의 근거(전략)가 된다. 다만 3D 적 캐릭터 머리위에 어떻게 2D 형태의 HpBar를 구현할지 구현 방법을 모른다.(미구현 가능성)

 

결론

친숙하고 전투 편의성에도 좋은 3번을 선택했다. 현재로써는 구현할 방법을 모르나 가장 대중적인 방법이기 때문에 인터넷+유튜브 검색을 하면 있을 거라 판단하여 선택했다. 

 

 

2.구현된 영상

https://youtu.be/8OdhlSELTdU

 

3.구현할 기능

  • 적 캐릭터 위치(3D좌표)마다 적 HpBarUI(게임 화면 = 스크린 좌표, 2D좌표)를 출력하기
  • 적 오브젝트의 데미지 받는 기능
  • 적 HpBarUI의 체력 갱신 기능
  • UI 우선 순위 정하기(캐릭터 UI와 적 HpBarUI의 출력 우선순위를 정하여 겹치는 현상 해결)

 

4.구현 과정

4.1.참고 링크

https://youtu.be/MO_XEHGzDLM

 

https://lesslate.github.io/unity/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%B2%B4%EB%A0%A5%EB%B0%94-%ED%91%9C%EC%8B%9C/

 

위의 참고 영상과 다른 점

1.시네머신 사용 - ui Camera 사용X, 테스트해봤는데 없어도 구현됐음

2.UI Canvas 세팅이 다름 - 영상에서는 UI Canvas에 카메라를 할당했는데(Screen Space - Camera), 나는 Screen Space - Overlay로 게임 화면에 직접 HpBarUI를 출력했다. 두 개의 Canvas를 겹쳤고, Canvas 우선순위를 통해 UI 우선 순위를 정했다.

 

 

4.2.3D 좌표의 HpBarUI를 스크린 좌표로 변환하기

 

Camera.main.WorldToScreenPoint

월드좌표(3D)를 스크린좌표(2D)로 변경, offset은 오브젝트 머리 위치

 

RectTransformUtility.ScreenPointToLocalPointInRectangle

스크린좌표에서 캔버스에서 사용할 수 있는 좌표로 변경

 

EnemyHpBar 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyHpBar : MonoBehaviour
{
    private Camera uiCamera; //UI 카메라를 담을 변수
    private Canvas canvas; //캔버스를 담을 변수
    private RectTransform rectParent; //부모의 rectTransform 변수를 저장할 변수
    private RectTransform rectHp; //자신의 rectTransform 저장할 변수

    //HideInInspector는 해당 변수 숨기기, 굳이 보여줄 필요가 없을 때 
    public Vector3 offset = Vector3.zero; //HpBar 위치 조절용, offset은 어디에 HpBar를 위치 출력할지
    public Transform enemyTr; //적 캐릭터의 위치


    void Start()
    {
        canvas = GetComponentInParent<Canvas>(); //부모가 가지고있는 canvas 가져오기, Enemy HpBar canvas임
        uiCamera = canvas.worldCamera;
        rectParent = canvas.GetComponent<RectTransform>();
        rectHp = this.gameObject.GetComponent<RectTransform>();
    }

    //LateUpdate는 update 이후 실행함, 적의 움직임은 Update에서 실행되니 움직임 이후에 HpBar를 출력함
    private void LateUpdate()
    {
        var screenPos = Camera.main.WorldToScreenPoint(enemyTr.position + offset); //월드좌표(3D)를 스크린좌표(2D)로 변경, offset은 오브젝트 머리 위치
        /*
        if(screenPos.z < 0.0f)
        {
            screenPos *= -1.0f;
            //x, y, (z) 메인카메라에서 XY평면까지의 거리
        }
        백뷰시점에서는 뒤돌 경우 HpBar가 보이는 문제가 있어서 위의 코드로 안보이게 했지만, 나는 쿼터뷰 시점이라서 필요없음
        */

        var localPos = Vector2.zero;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectParent, screenPos, uiCamera, out localPos); //스크린좌표에서 캔버스에서 사용할 수 있는 좌표로 변경?
    
        rectHp.localPosition = localPos; //그 좌표를 localPos에 저장, 거기에 hpbar를 출력
    }

}

//uiCamera가 없는데 딱히 문제는 없다...

4.3.EnemyHpBarUI prefab 생성하기

영상에서는 Image 타입으로 EnemyHpBarUI를 생성했지만 유니티 책에서 배운 Slider가 익숙해서 Slider로 생성했다.

Slider 명령어를 알고있기 때문에 간단하게 Hp 갱신을 구현할 수 있다. 다만 영상의 방식과 다르기 때문에 이해하는데 시간이 좀 걸렸다.

 

1.하이어라키창 > UI > Slider를 생성한다.

2.Slider의 이름을 Enemy HpBar Slider로 변경한다.

3.Slider의 Handle Slide Area는 사용하지 않기 때문에 삭제한다.

4.Slider 오브젝트만 선택하고(자식 오브젝트 선택 X) width 50, height 6으로 변경한다.

5.Slider의 자식 오브젝트를 모두 선택하고(Background, fill area, fill오브젝트) 앵커 프리셋+Alt를 눌러서 모든 방향 Stretch를 선택한다.

6.Background 오브젝트의 Source Image를 미리 만들어 둔 HPbar 리소스로 변경한다.

7.Color를 연한 빨간색으로 변경한다.(검은색으로 했더니 게임 화면에서 잘 안보임)

8.Fill Area의 Fill 오브젝트 > 인스펙터 > Image Type을 Filled로 변경

9..Fill method를 Horizontal로 변경

10.Source Image를 미리 만들어둔 HpBar 파일로 변경한다.

11.Color는 빨간색으로 변경한다.

12.Slider 오브젝트에 EnemyHpBar 스크립트를 할당한다.

13.완성된 Slider 오브젝트를 프로젝트창의 Assets에 넣어서 프리팹화한다.

14.하이어라키창에 있는 Slider를 삭제한다.

 

4.4.적 캐릭터 머리 위에 EnemyHpBarUI 생성 + 데미지 받는 기능 구현하기

영상에서는 HpBarUI  생성 및 제어하기 위해서 새로운 스크립트를 생성했지만 내 경우 Slider 명령어 사용, 데미지 받는 기능은 적 AI 스크립트에서 구현이 가능해서 적 AI 스크립트에 EnemyHpBarUI 생성 + 데미지 받는 기능을 추가했다.

 

Enemy스크립트

using UnityEngine.UI; //Slider 제어하기 위해서 필요

public class Enemy : LivingEntity
{
    //HpBarUI 추가한 변수
    public GameObject hpBarPrefab; //Instantiate 메서드로 복제할 프리펩을 담을 변수
    public Vector3 hpBarOffset = new Vector3(-0.5f, 2.4f, 0);

    public Canvas enemyHpBarCanvas;
    public Slider enemyHpBarSlider; //Slider의 초기 세팅, Hp 갱신에 사용할 Slider를 담을 변수
    
    void Start()
    {
        SetHpBar();
    }
  
    //데미지를 입었을 때 실행할 처리
    public override void OnDamage(float damage)
    {
        //피격 애니메이션 재생
        enemyAnimator.SetTrigger("Hit");
        
        //LivingEntity의 OnDamage()를 실행하여 데미지 적용
        base.OnDamage(damage);

        //체력 갱신
        enemyHpBarSlider.value = health;
    }
    
    //적 위치 + offset에 HpBarPrefab 생성하기
    void SetHpBar()
    {
        enemyHpBarCanvas = GameObject.Find("Enemy HpBar Canvas").GetComponent<Canvas>();
        GameObject hpBar = Instantiate<GameObject>(hpBarPrefab, enemyHpBarCanvas.transform);

        var _hpbar = hpBar.GetComponent<EnemyHpBar>();
        _hpbar.enemyTr = this.gameObject.transform;
        _hpbar.offset = hpBarOffset;
    }
    
    
    //enemyHpBarSlider 활성화
    protected override void OnEnable()
    {

        //LivingEntity의 OnEnable() 실행(상태초기화)
        base.OnEnable();

        //체력 슬라이더 활성화
        enemyHpBarSlider.gameObject.SetActive(true);
        //체력 슬라이더의 최댓값을 기본 체력값으로 변경
        enemyHpBarSlider.maxValue = startingHealth;
        //체력 슬라이더의 값을 현재 체력값으로 변경
        enemyHpBarSlider.value = health;
    }
}

 

4.5.Enemy HpBar Canvas 생성 + UI 우선 순위 정하기

1.하이어라키창 > UI > Canvas 생성

2.Canvas 이름을 Enemy HpBar Canvas로 변경

3.Canvas의 인스펙터창에서 Render Mode를 Screen Space - Overlay로 변경

4.기존 HUD Canvas보다 먼저 출력시키기 위해서 Sort Order를 0으로 설정
  #Sort Order의 숫자가 높을수록 나중에 출력한다.

5.HUD Canvas의 Sort Order를 1로 변경한다.

 

4.6.Enemy  스크립트 설정하기

적의 인스펙터창 > Enemy 컴포넌트 > Hp Bar Prefab, Enemy Hp Slider에 각각 EnemyHpSlider Prefab을 할당한다.

 

다음 구현 목표

1.드디어! 플레이어 캐릭터 스킬 구현하기(+ 데미지 적용하기)

  • 파이어볼
  • 썬더
  • 텔레포트

2.모든 스킬 가상 버튼에 할당하기(매직 미사일, 파이어볼, 썬더, 텔레포트)

반응형

댓글