Unity 숙련 주차 - Survival 게임 플레이어 상태 및 UI

Amberjack·2024년 2월 1일
0

Unity

목록 보기
24/44
post-custom-banner

🖥️ 인터페이스

인터페이스에 대해 복습해보자.

인터페이스를 통해 클래스들은 공통적인 동작을 정의하고, 이러한 동작들을 구현하는 클래스들은 해당 인터페이스를 구현(implement)함으로써 공통 규약을 준수할 수 있다.

인터페이스를 설명하는 주요 특징은 다음과 같습니다.

  1. 추상화 : 인터페이스는 추상적인 개념으로, 실제로 구현된 메서드가 없고, 메서드의 시그니처만을 가진다. 따라서 인터페이스는 인스턴스화될 수 없으며, 구현체가 필요하다.

  2. 메서드 시그니처: 인터페이스는 구현 클래스가 반드시 구현해야 하는 메서드들의 시그니처를 정의한다. 메서드의 이름, 매개변수, 반환 타입이 포함된다.

  3. 다중 상속 가능: 클래스는 하나의 클래스만 상속받을 수 있지만, 여러 인터페이스를 동시에 구현할 수 있다. 이를 통해 다중 상속을 흉내내는 것이 가능하다.

  4. 강제적 구현: 클래스가 인터페이스를 구현하면, 인터페이스에서 정의한 모든 메서드를 반드시 구현해야 한다. 이로 인해 클래스는 인터페이스에 정의된 동작을 강제로 구현하게 된다.

  5. 인터페이스 간 확장: 인터페이스는 다른 인터페이스를 확장(extends)할 수 있다. 이를 통해 더 큰 범위의 공통 동작을 정의할 수 있다.

📺 UI 만들기

체력바 만들기

빈 Object를 만들고 _UI로 이름 변경한다. 그 아래에 HUD_Canvas라는 Canvas를 생성하고, 다시 밑에 Image를 생성해준다.

Image를 Health로 이름을 변경해주고, 아래와 같이 수정해준다.

이후, 체력바임을 확인할 수 있도록 심장 모양의 Image를 만들어서 Health 밑에 넣어준다.

그 다음에는 체력바의 체력 부분을 스프라이트로 만들어주기 위해 Package Manager에서 2D Sprite를 설치하자.

이후에 Textures 라는 폴더를 만들어 준다.

그 밑에 Create → 2D → Sprites → Square를 생성해준다.

그 이후에 아까 만든 Health 밑에 Image를 생성하고 넣어준다.

Image Type 변경하기


Image의 Inspector에서 Image Type을 변경할 수 있다. 우리의 경우 Filled를 사용해볼 것이다.


Filled로 변경하면 여러 Fill Method들이 있는데, 우리는 체력바를 표현할 것이기 때문에 Horizontal로 변경해준다.
이제 Fill Amount를 변경하면 체력바처럼 줄었다가 늘었다하는 것을 확인할 수 있다.

Conditions 만들기

상태를 확인할 수 있는 상태창을 만들자.

HUD_Canvas 밑에 Conditions라는 빈 오브젝트를 생성한 뒤, 앵커를 우측 하단으로 변경하고 값들을 아래와 같이 수정한다.

그후, Add Component를 통해 Vertical Layout Group을 붙여준다.

이후, Conditions 밑에 Health를 옮겨보자.

Layout Group에 Health를 추가하니 Health의 좌표값이 Layout Group에 의해 고정되는 것을 확인할 수 있다.

나머지 상태 만들기

이제 Health를 2개를 복사하고 각각 Hunger, Stamina로 변경하자.

Crosshair 만들기

HUD_Canvas 밑에 UI Image를 만들어 크기를 12 × 12로 변경하자.

DamageIndicator 만들기

데미지를 받았을 때 화면이 살짝 빨갛게 점멸하게 만들자.

HUD_Canvas 밑에 Image를 생성하고 DamageIndicator로 이름을 변경한다.
이후, 하이어라키에서 HUD_Canvas의 하위 객체들 중에서 제일 위로 위치를 옮긴다(제일 위에 있는 UI가 맨 뒤에 존재하게 된다).


생성을 완료하면 이미지 컴포넌트의 SetActive를 false로 변경해주자.

👨‍💻 PlayerConditions.cs 작성하기

PlayerConditions.cs를 생성해서 Player에게 붙인 뒤 코드 작성을 해보자.

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[Serializable]
public class Condition
{
    [HideInInspector]
    public float curValue;
    public float maxValue;
    public float startValue;
    public float regenRate;
    public float decayRate;
    public Image uiBar;

    public void Add(float amount)
    {
        // Condition의 값이 추가가 될 때 추가된 현재 값이 최대값이 넘지 않도록, 최대값보다 클 경우 최댓값을 현재 Value로 변경해준다.
        curValue = Mathf.Min(curValue+amount, maxValue);    
    }

    public void Subtract(float amount)
    {
        // Condtion의 값이 차감이 될 때 현재 값이 최소값을 넘지 않도록, 최소값보다 작을 경우 최소값을 현재 Value로 변경해준다.
        curValue = Mathf.Max(curValue - amount, 0.0f);
    }

    // UI에서 Fill Amount를 사용할 때, 0 ~ 1사이의 Percentage를 사용한다. 
    public float GetPercentage()
    {
        // 현재 값을 최대 값으로 나눠서 0 ~ 1 사이의 Percentage를 return 해준다.
        return curValue / maxValue;
    }
}

public class PlayerConditions : MonoBehaviour
{
    public Condition health;
    public Condition hunger;
    public Condition stamina;

    public float noHungerHealthDecay;   // 배고픔이 다 달았을 때 Health가 닳도록 해주기 위한 변수.

    public UnityEvent onTakeDamage;     // 데미지를 받았을 때 처리할 이벤트를 받기 위한 Unity Event

    // Start is called before the first frame update
    void Start()
    {
        health.curValue = health.startValue;
        hunger.curValue = hunger.startValue;
        stamina.curValue = stamina.startValue;
    }

    // Update is called once per frame
    void Update()
    {
        // 1초마다 따라 배고픔 닳게 하기
        hunger.Subtract(hunger.decayRate * Time.deltaTime);
        // 1초마다 스테미나 차게 만들기
        stamina.Add(stamina.regenRate * Time.deltaTime);

        // 배고픔이 다 닳면 체력을 닳게 만들기
        if (hunger.curValue == 0.0f)
        {
            health.Subtract(noHungerHealthDecay *  Time.deltaTime);
        }

        // 체력이 다 닳으면 캐릭터 죽음
        if (health.curValue == 0.0f)
        {
            Die();
        }

        // Bar 변경하기
        health.uiBar.fillAmount = health.GetPercentage();
        hunger.uiBar.fillAmount = hunger.GetPercentage();
        stamina.uiBar.fillAmount = stamina.GetPercentage();
    }

    public void Heal(float amount)
    {
        health.Add(amount);
    }

    public void Eat(float amount)
    {
        hunger.Add(amount);
    }

    public bool UseStamina(float amount)
    {
        // 스테미나가 없을 경우 스테미나를 사용하지 못하도록
        if (stamina.curValue - amount < 0) return false;

        stamina.Subtract(amount);
        return true;
    }

    public void Die()
    {
        Debug.Log("Player Die!");
    }
}

Player에서 값 추가해주기.

Player의 Inspector에서 Player Conditions의 값들을 추가해주자.

확인해보기!

Hunger의 Decay Rate를 임의로 수정해서 확인해보자.
Hunger가 계속 차감되고 Hunger가 0이 되면 체력까지 닳는 것을 확인할 수 있다.

👨‍💻 데미지 처리 준비하기

데미지 처리를 위해 Interface를 사용해보자!

// PlayerConditions.cs
...

public interface IDamagable
{
	void TakePhysicalDamage(int damageAmount);
}

...

public class PlayerConditions : MonoBehaviour, IDamagable
{

...

	public void TakePhysicalDamage(int damageAmount)
	{
    	health.Subtract(damageAmount);
    	onTakeDamage?.Invoke();
	}
}
post-custom-banner

0개의 댓글