드디어 드디어 Monster 코드를 정리했다
지금 몬스터가 Golem, Skeleton 이렇게 두 가지 종류가 있는데
코드가 비슷 비슷하지만 애니메이션이나 Hp 등등 다른 부분이 존재하기는 해서
하나의 코드로 합칠 수는 없는 그런 구조였다
그래서 Mob_Skeleton, Mob_Golem 이렇게 따로 스크립트를 작성했더니,
Player 코드에서 몬스터의 종류를 layer로 일일히 구분해야했다
대표적으로 이런 느낌..
public void Attack(GameObject mob)
{
if (mob.layer == Layer.GOLEM)
{
mob.GetComponent<Mob_Golem>().AddHPVal(-1);
}
else if (mob.layer == Layer.SKELETON)
{
mob.GetComponent<Mob_Skeleton>().AddHPVal(-1);
}
else if (mob.layer == Layer.CROWN_SKELETON)
{
mob.GetComponent<Mob_Skeleton>().AddHPVal(-1);
}
}
근데 앞으로 여러 종류의 몬스터가 추가될 거 생각하니까, 이전 코드는 확장성이 없어서 정리를 해야했다
저런 식으로 되어있는 부분이 꽤 많았는데,
부모 클래스를 만들어서 상속시키는 방식으로 정리했더니 더 코드가 깔끔해졌다
public void Attack(GameObject mob)
{
mob.GetComponent<Monster>().AddHpVal(-1);
}
그리고 아래 코드처럼 foreach문 두 번 쓸 걸 한 번으로 줄일 수 있었다
public void Attack(GameObject mob)
{
// BEFORE
foreach (Mob_Skeleton obj in curComboMonSet.GetComponentsInChildren<Mob_Skeleton>())
{
obj.StartMobInAirLogic(patternNum);
}
foreach (Mob_Golem obj in curComboMonSet.GetComponentsInChildren<Mob_Golem>())
{
obj.StartMobInAirLogic(patternNum);
}
// AFTER
foreach (Monster obj in curComboMonSet.GetComponentsInChildren<Monster>())
{
obj.StartMobInAirLogic(patternNum);
}
}
사실 Unity C#으로 딱히 상속 개념을 사용해본 적이 없고, 객체지향을 배운지 오래되서 처음에는 조금 막막했다
근데 클래스 상속을 할 줄 모르는 개발자는 말이 안되니까 이번 기회에 한 번 도전해보았다..!
처음에는 먼저 두 종류의 몬스터 스크립트에서 공통적으로 쓰이는 변수를 정리했고,
내용이 100% 똑같은 함수들을 구분해두었다
Monster 라는 부모 클래스를 만들고 Skeleton, Golem라는 자식 클래스를 만들었다
public abstract class Monster : MonoBehaviour
{
// 같은 이름의 함수지만 내용이 많이 다른 경우,
// 상속받은 클래스에서 아예 새로 정의하도록 'abstract'로 정의
public abstract void Move();
// 같은 이름의 함수이면서 겹치는 내용이 있는 경우,
// 상속받은 클래스에서 override 해서 다른 부분만 재정의할 수 있도록 'virtual'로 정의
public virtual void Attack()
{
}
}
위 두 경우 모두 ovrride 키워드를 사용하여 재정의하면 된다
차이점은 abstract으로 선언된 경우 자식 클래스에서 정의하지 않으면 다음과 같은 경고문이 뜬다
그러나 virtual로 선언한 건 재정의해도 되고 안해도 된다
public class Golem : Monster
{
public override void Move() // abstract
{
}
public override void Attack() // virtual
{
// 공통 코드는 부모 함수가 실행되도록 함
base.Attack();
}
}
그리고 부모 클래스에서 public으로 선언했는데
자식 클래스에서 같은 함수를 private으로 선언하려고 하면 다음과 같은 경고문이 뜬다
그리고 게임오브젝트에 컴포넌트로 추가할 때
부모 클래스를 추가하려고 하면 다음과 같은 경고가 뜬다
게임오브젝트에는 자식 클래스를 추가하면 된다
부모 클래스이든, 자식 클래스이든 public으로 선언된 프로퍼티가 인스펙터에 노출된다
이렇게 하고 나니 위에서 적었던 이 코드가 동작할지 의문이었다
게임오브젝트에 명시적으로 들어가있는 컴포넌트는 'Golem'이지 'Monster'가 아니기 때문이다
foreach (Monster obj in curComboMonSet.GetComponentsInChildren<Monster>())
{
obj.StartMobInAirLogic(patternNum);
}
근데 잘 동작한다
GetComponent로 부모클래스든 자식클래스든 하나만 가져와도 둘 다 불러와진다
이렇게 빈 게임 오브젝트에 'Golem' 넣어놓고 다음 테스트 코드를 실행해보았다
void Start()
{
if(GameObject.FindObjectOfType<Golem>() != null)
Debug.Log("자식 클래스 존재");
if(GameObject.FindObjectOfType<Monster>() != null)
Debug.Log("부모 클래스 존재");
}
그럼 이와 같이 두 개의 로그가 모두 출력되는 것을 확인할 수 있다
마지막으로는 원래 클래스 위에 명시된 참조가 0이 될 때까지 찾아다니면서 코드를 수정했다
다른 코드와 많이 얽혀있는 스크립트들이어서 이게 정리가 될 수 있을까 싶었는데
하루만에 잘 정리된 것 같아 다행이다..!
상속 개념도 실제 활용해볼 수 있었고, 겁 먹었던 것도 없어져서 기쁜 하루당