유닛 클래스에 정의한것과 동일하게 MonsterStat스크립트를 추상클래스의 부모로 정의하고, 각각의 상속받은 자식클래스들에서 재정의 하거나, 스탯을 다르게 정의한다
참고: https://velog.io/@yangju058/타워디펜스게임-6.-유닛-클래스
몬스터들도 각각의 체력, 공격속도, 이동속도를 가지고 있다.
아직은 공격속도와 이동속도 모두 MonsterController 스크립트에서 모든 몬스터들이 동일하게 적용되고 있어서 MonsterStat 스크립트에서는 체력만 다르게 정의해두었다
기본적으로 몬스터들이 공통적으로 가질 수 있는 함수들이 정의되어있다
추상클래스로 구현
-> 자식들에 override를 사용하여 재정의할 수 있지만, 현재 단계에서는 부모가 정의해둔 함수와 동일한 행동이 필요하기 때문에 그냥 부모함수를 호출한다
HP바를 가져오고 해당 수치를 적용
데미지를 입으면 수치를 적용시키고 HPSilder에도 적용시킨다
죽음 애니메이션 실행
죽음 시 몬스터 카운트 감소
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("몬스터의 공격");
}
}
Die() 함수부모클래스 MonsterStat에 정의해둔 기본 Die()함수

Monster1Stat 자식 클래스에서 Die()함수에 새로운 기능을 넣어 재정의 할 수 있다
예를 들자면, 모든 몬스터들은 죽으면 몬스터 카운트가 감소하고, 게임오브젝트가 파괴된다. 근데 Monster1은 죽고 추가적인 행동을 한다면 자식 클래스에서 로직을 추가하면 된다
현재 Die()함수에는 자식별로 다 같은 동작밖에 수행하지 않으니까, base를 사용하여 부모함수를 호출한다

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

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

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외의 다른 몬스터들의 자식 클래스들은 멤버 변수 이외에 동일한 동작으로 구현되어있다