[타워디펜스게임] #11. 몬스터 클래스

치치·2025년 2월 15일
0

타워디펜스게임

목록 보기
11/18
post-thumbnail

오늘의 목표

유닛 클래스에 정의한것과 동일하게 MonsterStat스크립트를 추상클래스의 부모로 정의하고, 각각의 상속받은 자식클래스들에서 재정의 하거나, 스탯을 다르게 정의한다

참고: https://velog.io/@yangju058/타워디펜스게임-6.-유닛-클래스

몬스터들도 각각의 체력, 공격속도, 이동속도를 가지고 있다.

아직은 공격속도와 이동속도 모두 MonsterController 스크립트에서 모든 몬스터들이 동일하게 적용되고 있어서 MonsterStat 스크립트에서는 체력만 다르게 정의해두었다



MonsterStat 스크립트 전체 코드

기본적으로 몬스터들이 공통적으로 가질 수 있는 함수들이 정의되어있다
추상클래스로 구현
-> 자식들에 override를 사용하여 재정의할 수 있지만, 현재 단계에서는 부모가 정의해둔 함수와 동일한 행동이 필요하기 때문에 그냥 부모함수를 호출한다

< 모든 몬스터들이 공통적으로 이용되는 동작 >

  1. HP바를 가져오고 해당 수치를 적용

  2. 데미지를 입으면 수치를 적용시키고 HPSilder에도 적용시킨다

  3. 죽음 애니메이션 실행

  4. 죽음 시 몬스터 카운트 감소

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.Antlr3.Runtime.Tree;
using UnityEngine;
using UnityEngine.UI;


public abstract class MonsterStat : MonoBehaviour
{
    [SerializeField] protected int maxHealth;       // 최대 체력

    [SerializeField] protected int currentHealth;   // 현재 체력

    protected Slider HPslider;                      // 체력 슬라이더

    protected Animator animator;                   // 애니메이터 추가
    private bool isDying = false;                  // 죽음 상태 플래그

    protected virtual void Start()
    {
        currentHealth = maxHealth;
        animator = GetComponent<Animator>();       // Animator 컴포넌트 가져오기

        if (HPslider != null)
        {
            HPslider.maxValue = maxHealth;
            HPslider.value = currentHealth;
        }
    }

    public void SetHPBar(Slider slider)
    {
        //Debug.Log("SetHPBar 호출됨");
        HPslider = slider;

        if (HPslider != null)
        {
            HPslider.maxValue = maxHealth;
            HPslider.value = currentHealth;
        }
        else
        {
            //Debug.LogError("슬라이더가 null입니다!");
        }
    }


    public void TakeDamage(int damage)
    {
        if (isDying) return; // 죽음 중일 때 추가 데미지 방지

        currentHealth -= damage;
        currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth);

        if (HPslider != null)
        {
            HPslider.value = currentHealth;
        }

        if (currentHealth <= 0)
        {
            PlayDeathAnimation();
        }
    }

    // 죽음 애니메이션 실행
    protected virtual void PlayDeathAnimation()
    {
        if (animator != null)
        {
            isDying = true;
            animator.SetTrigger("Die"); // Die 트리거 설정
            StartCoroutine(WaitForDeathAnimation());
        }
        else
        {
            Die(); // 애니메이터가 없으면 바로 Die 호출
        }
    }

    protected virtual void Die()
    {
        MonsterCount.Instance.DecreaseCount(); // 몬스터 카운트 감소
        Debug.Log($"{gameObject.name} 사망!");
        Destroy(gameObject);
        HPslider.gameObject.SetActive( false );
    }

    private IEnumerator WaitForDeathAnimation()
    {
        yield return new WaitForSeconds(1.5f); // 애니메이션 지속 시간
        Die();
    }


    protected abstract int Defense 
    { get; set; }
    
    protected abstract int Damage
    { get; set; }

    protected abstract float AttackSpeed
    { get; set; }

    protected abstract float MoveSpeed
    { get; set; }

    protected virtual void Attack()
    {
        Debug.Log("몬스터의 공격");
    }
}

ex) Die() 함수

  • 부모클래스 MonsterStat에 정의해둔 기본 Die()함수

  • Monster1Stat 자식 클래스에서 Die()함수에 새로운 기능을 넣어 재정의 할 수 있다

  • 예를 들자면, 모든 몬스터들은 죽으면 몬스터 카운트가 감소하고, 게임오브젝트가 파괴된다. 근데 Monster1은 죽고 추가적인 행동을 한다면 자식 클래스에서 로직을 추가하면 된다

  • 현재 Die()함수에는 자식별로 다 같은 동작밖에 수행하지 않으니까, base를 사용하여 부모함수를 호출한다


하지만 현재 자식 클래스들인 Monster1Stat, Monster2Stat, Monster3Stat 등등
부모에 정의된 로직외에 추가적인 로직은 필요없다. 현재로써는 Start()함수에서 각자의 체력으로 초기화만 시켜두자

base : 부모(Base) 클래스의 멤버(필드, 메서드, 속성 등)에 접근할 때 사용하는 키워드
-> 자식 클래스에서 부모 클래스의 기능을 호출하거나 사용할 때 사용



Monster1Stat 스크립트

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


// 쿠션더미(일반형)
public class Monster1Stat : MonsterStat
{
    
    private int defense;

    private int damage;

    private float attackspeed;

    private float movespeed;

    protected override void Start()
    {
        maxHealth = 50;
        base.Start(); // 부모 클래스의 Start 호출

    }
    // 애니메이션 이벤트에서 호출
    protected override void Die()
    {
        base.Die(); // 기본 Die 동작 실행
    }

    // get : 데이터를 반환해서 보여줌


    protected override int Defense
    {
        get { return defense; }
        set { defense = value; }
    }
    protected override int Damage
    {
        get { return damage; }
        set { damage = value; }
    }
    protected override float AttackSpeed
    {
        get { return attackspeed; }
        set { attackspeed = value; }
    }
    protected override float MoveSpeed
    {
        get { return movespeed; }
        set { movespeed = value; }
    }


    protected override void Attack()
    {
        Debug.Log("몬스터1의 공격");
    }


    public Monster1Stat()
    {
        //maxhealth = 50;
        defense = 0;
        damage = 1;
        attackspeed = 3.0f;
        movespeed = 0.5f;
    }
}
    

Monster1외의 다른 몬스터들의 자식 클래스들은 멤버 변수 이외에 동일한 동작으로 구현되어있다

profile
뉴비 개발자

0개의 댓글