2 분 소요

Intro

이번 포스팅에서는 플레이어의 공격을 조금 더 생동감있게 만들어줄 공격 효과와

몬스터를 공격했을 때 몬스터가 받는 데미지를 표시하는것을 구현해보았습니다.

image

공격효과

공격효과는 Trail Renderer 컴포넌트로 구현하였습니다.

image

무기 프리팹의 자식 오브젝트에 빈오브젝트를 만들어 Effect라고 이름을 짓고, Trail Renderer 컴포넌트를 추가합니다.

적당한 색깔과 너비, 모양등을 설정해주었습니다.

이펙트의 On/Off 를 위해 Weapon 클래스에 다음 코드를 추가했습니다.

 public abstract class Weapon : MonoBehaviour
{
    // ...

    // 이펙트 On/Off
    public abstract void SetEffect(bool isEnabled);
}

  • Weapon 클래스를 상속받는 모든 자식클래스들에 SetEffect 함수를 구현해주어야합니다.

먼저, 검 무기클래스인 Sword 클래스를 수정하였습니다.

public class Sword : Weapon
{
    private TrailRenderer effect;               // 공격 이펙트

    private void Awake()
    {
        // ...
        effect = GetComponentInChildren<TrailRenderer>();
    }

    // ...

    public override void SetEffect(bool isEnabled)
    {
        effect.enabled = isEnabled;
    }
}

  • 공격 판정과 마찬가지로, Player의 애니메이션에 맞춰 애니메이션 이벤트로 호출하여 사용하도록 했습니다.
public class PlayerController : MonoBehaviour
{
    private void EnableEffect() => WeaponManager.Instance.currentWeapon.SetEffect(true);

    private void DisableEffect() => WeaponManager.Instance.currentWeapon.SetEffect(false);
}
  • 공격할 때 EnableEffect() 호출을 통해 이펙트를 활성화하고, 공격이 끝날 때 DisableEffect() 호출을 통해 이펙트를 비활성화하여 공격효과를 구현했습니다.

데미지 표시

데미지 표시를 담당하는 DamageTextManager 를 만들어, 모든 데미지 표시를 관리하도록 했습니다.

데미지 텍스트는 매우 자주 사용되고, 한번에 많은 텍스트 오브젝트가 필요할 수 있습니다.

따라서 매번 데미지 텍스트를 생성/파괴하는것이 아닌, 오브젝트 풀링을 통해 데미지 텍스트를 구현하였습니다.

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

public class DamageTextManager : Singleton<DamageTextManager>
{
    [SerializeField] private GameObject damageTextPrefab;               // 데미지 텍스트 프리팹

    private int poolSize = 10;

    private Queue<TextMeshPro> pool = new Queue<TextMeshPro>();
    
    protected override void Awake()
    {
        base.Awake();
        Init();
    }

    // 풀 초기화
    private void Init()
    {
        for(int i = 0;i<poolSize; i++)
        {
            // 데미지 텍스트 생성 및 비활성화
            GameObject obj = Instantiate(damageTextPrefab, transform);
            obj.SetActive(false);
            pool.Enqueue(obj.GetComponent<TextMeshPro>());
        }
    }

    // 위치에 데미지 표시
    public void ShowDamage(Vector3 position, int damage)
    {
        TextMeshPro damageText = GetDamageText();

        // 위치 설정
        damageText.transform.position = position;

        // 데미지 텍스트 설정
        damageText.text = damage.ToString();

        // Fade-out 효과
        StartCoroutine(FadeOut(damageText));
    }

    // 풀에서 데미지 텍스트 오브젝트 가져오기
    private TextMeshPro GetDamageText()
    {
        if(pool.Count > 0)
        {
            TextMeshPro text = pool.Dequeue();
            text.gameObject.SetActive(true);
            return text;
        }
        // 남는 오브젝트가 없을 때 새로 생성
        else
        {
            GameObject obj = Instantiate(damageTextPrefab, transform);
            return obj.GetComponent<TextMeshPro>();
        }
    }

    // 데미지 텍스트 떠오르는 효과
    private IEnumerator FadeOut(TextMeshPro text)
    {
        float duration = 1f;                // fade-out 까지 걸리는 시간
        float elapsedTime = 0;
        Vector3 startPos = text.transform.position;
        Color startColor = text.color;

        while(elapsedTime < duration)
        {
            elapsedTime += Time.deltaTime;
            text.transform.position = startPos + new Vector3(0, elapsedTime * 1.5f, 0);
            // 알파값 조절로 fade-out 구현
            text.color = new Color(startColor.r, startColor.g, startColor.b, 1 - (elapsedTime / duration));
            yield return null;
        }

        // fade-out 후처리
        text.gameObject.SetActive(false);
        pool.Enqueue(text);
    }
}
  • DamageTextMangager 클래스는 Queue를 통해 오브젝트 풀을 구현하였습니다.
    • 초기 풀 사이즈는 10으로, 이후 요청에따라 증가할 수 있도록 동적으로 증가할 수 있습니다.
  • 데미지 표시가 필요한 곳에서 ShowDamage() 함수를 호출합니다.
    • 매개변수로 데미지 표시가 필요한 위치와, 데미지값을 받습니다.
  • 풀에서 사용가능한 텍스트 오브젝트를 가져와 활성화하고, FadeOut 효과를 적용합니다.
    • FadeOut 효과가 끝난 뒤, 다시 풀에 넣어 재사용할 수 있도록 합니다.
  • FadeOut 효과는 코루틴으로 구현하였으며, 데미지 텍스트가 떠오르다 사라지는 효과도 추가하였습니다.

댓글남기기