EasyCastleUNITY

드래곤 플라이트 모작 개발일지 13(드래곤들 HP바 구현) 본문

2D 프로젝트 개발 일지(드래곤 플라이트 모작)

드래곤 플라이트 모작 개발일지 13(드래곤들 HP바 구현)

EasyCastleT 2023. 9. 20. 22:28

여태까지는 드래곤이 맞으면, 각 드래곤들의 hp가 얼마나 남았는지 알 수 없었습니다. 

그래서 UI 슬라이더를 통해, HP바를 만들고, 그 HP바들이 드래곤들을 따라다니게 해보겠습니다. 

https://stickode.tistory.com/231

 

[C#][Unity]체력바 만들기!

안녕하세요!! 오늘은!! 캐릭터를 계속 따라다니는 체력바를 구현해 보도록 하겠습니다! 유니티상에서 체력바를 구현하는 방법은 여러가지 방법이 있는데요. 오늘 구현해 볼 방식은 캔버스에 체

stickode.tistory.com

이 블로그를 참고했습니다.

먼저 hp바들을 먼저 만들었습니다. 

UI의 슬라이더를 활용하였고 

일반 HP바
보스 hp바

이 리소스들을 활용하여 만들었습니다.

Hp바 정상동작 확인

그리고 이 다음에

위의 블로그에 있는 스크립트를 참고하여, 테스트 스크립트를 만들고 시험해 보았습니다.

드래곤에 부착
캔버스에 부착
드래곤을 움직이니 HP 바도 같이 움직임

이렇게 테스트를 마쳤습니다. 


테스트를 마치고, 게임씬으로 돌아와 어떻게 구현할지 고민했습니다.

그래서, 드래곤들이 오브젝트 풀링을 하고 있다는 것을 이용하여, 

처음 드래곤들이 만들어지고, 풀에 들어갈때, 미리 캔버스 위에 HP 바들을 만들어두어서

각각의 드래곤들이 자신만의 hp 바를 만들도록 했습니다. 

hp바 스크립트는 각각의 드래곤들에게 부여되어 있어, 드래곤들이 풀에 들어갈때, 해당 스크립트의 Awake도 같이 불리게 됩니다. 

DragonHpBar 스크립트 일부

Awake 함수를 통해, 씬이 시작됨과 동시에, hp바들을 만들고, 

Update에서 this.transform.position, 즉 각각의 드래곤의 위치를 따라가도록 했습니다. 

 

따라가는 HP 바

그런데 문제가 생겼습니다. 바로, 드래곤이 죽었는데도, ui상에서 HP바가 꺼지지 않는 경우가 종종 생겼습니다. 

드래곤이 죽었는데도 남아있는 HP바

여러가지 방법을 시도해봤지만, 안되고 있었는데, 확인 하는 과정에서 희한한 현상을 발견했습니다.

바로, 드래곤들이 자신의 체력 이상으로 총알과 충돌하는 현상이 발견된 것입니다.

예를 들어, 체력이 3인데, 0이되어 풀로 돌아가는 순간, 아직 돌아가지 않은 드래곤에게 총알이 충돌하는 것이었습니다.

즉, 3번을 맞고 돌아가야 하는데, 돌아가기 전에 한번을 더 맞게 된 것입니다. 

onHit가 호출되는 부분과 onHit의 등록된 이벤트

돌아가는 순간, 당연히 충돌이 발생했으므로, 충돌과 연결된 대리자인 onHit가 호출이 되게 됩니다.

그러면 드래곤은 돌아갔지만, onHit가 호출이 되게 됩니다. 

 

HP바는 한번 맞으면 활성화 되도록 드래곤의 대리자 onHit에 등록했습니다. 

즉 oneHit변수가 false 일 경우에만 실행이 됩니다. 

그런데, 이 oneHit 변수가 OnDisable에서 false가 되도록 하고 있었습니다. (즉, 드래곤이 죽어서 오브젝트 풀로 돌아가면 실행되도록)

드래곤은 죽어서 OnDisable이 호출이 됩니다. 그래서 onehit 변수는  false가 됩니다. 

그런데 false가 된 상황에서는 hp_bar가 활성화 되게 됩니다. 

oneHit가 false여서 활성화가 된다.

활성화가 되었지만, 드래곤은 이미 풀로 돌아가서, 드래곤의 마지막 위치인, 죽은 자리에 hp_bar가 남게됩니다. 

이러한 과정으로 인해, 일어나는 문제였습니다. 

그래서 해결 방안으로, 드래곤이 비활성화되면, oneHit를 false로 만드는 것이 아니라, 

활성화되면 oneHit를 false로 바꾸기로 했습니다. (OnEnable)

호출순서 처음 부분
호출순서 마지막 부분
수정한 스크립트

이러면, 드래곤이 죽어서 풀로 돌아갈때도, onehit 변수는 계속 true가 됩니다. 따라서

한 대를 더 맞아서 onHit 대리자가 호출이 되어도, onehit는 여전히 true이기에 hp바는 활성화되지 않습니다. 

 

그리고 다시 풀에서 나와 활성화가 되면, onehit는 false가 되고, 다시 한번 맞으면, hp바가 활성화되게 됩니다. 

잘 동작하는 모습
보스 hp 바 정상작동

사용한 스크립트 DragonHpBar

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

public class DragonHpBar : MonoBehaviour
{
    [SerializeField] private GameObject hpBarPrefab;
    [SerializeField] private float maxHp;
    [SerializeField] private float currentHp;

    private Slider hpBar;

    private GameObject hpBarGo;

    private Dragon dragon;

    private bool onehit=false;

    private void OnDisable()
    {
        this.maxHp = this.GetComponent<Dragon>().MaxHp;
        this.hpBar.value = 1;
        if (this.hpBarGo!=null)hpBarGo.SetActive(false);
    }

    private void OnEnable()
    {
        this.onehit = false;
    }
    // Start is called before the first frame update
    void Awake()
    {
        this.onehit = false;
        var canvas = GameObject.Find("Canvas");
        hpBarGo = Instantiate(hpBarPrefab, canvas.transform);
        this.hpBar = hpBarGo.GetComponent<Slider>();
        hpBarGo.SetActive(false);
        this.maxHp = this.GetComponent<Dragon>().MaxHp;

        this.dragon = this.GetComponent<Dragon>();

        this.dragon.onHit = (hp) => {
            if (onehit == false)
            {
                onehit = true;
                hpBarGo.SetActive(true);
                //Debug.Log("HpBar!");
            }
            this.currentHp = hp;
        };
    }

    // Update is called once per frame
    void Update()
    {
        this.hpBar.value = currentHp / maxHp;
        this.hpBarGo.transform.position = Camera.main.WorldToScreenPoint(
            this.transform.position - new Vector3(0, 0.7f, 0));
    }
}

이렇게 hp바 구현을 마쳤습니다.