본문 바로가기

유니티

[유니티] 상속을 통해서 몬스터 구현해보기

유니티와 C#에 익숙하지 않았을 때, 굉장히 비효율적으로 코드를 짠 경험이 있다.

어떠한 점이냐면 몬스터의 패턴을 분리하기 위해서 여러 스크립트를 만들고 피격, 죽음 등의 함수를 각각 모든 스크립트에 넣었다.

이는 상속의 기능을 공부한 이후로 정말 비효율적인 구현이라고 느끼게 되었다.


상속이란?

C#의 특징인 객체지향언어의 속성중 하나로, 객체가 다른 객체를 상속받아서 상속받은 부모 객체의 모든 특성을(변수,함수 등) 사용하는 것을 의미한다.

사실 유니티를 처음 하는 사람들도 상속의 기능을 쓰게 되는데, 바로 유니티 내에서 스크립트 생성시 Monobehaviour을 자동으로 상속받게 되기 떄문이다.

우리가 처음 유니티를 입문할떄도 사실 상속 기능은 항상 사용하고 있었다.

자 이제 , 어떠한 경우에 상속이 유용하게 쓰일지 예시를 들어보자면,

아주 간단하게 3종류의 몬스터가 있다고 가정을 해보자.

첫번쨰로, 모든 몬스터에게 상속 시켜줄 몬스터 클래스를 만들어준다

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

public class Monster : MonoBehaviour
{
    protected void Start()
    {
        Debug.Log("몬스터가 등장하였습니다.");
    }

    public void OnHit()
    {
        Debug.Log("몬스터가 공격받았습니다.");
    }

    protected void Die()
    {
        Debug.Log("몬스터가 사망하였습니다.");
    }
}

이 상태로 3가지 형태의 함수를 만들어 줄 것이다.

만약에 위의 사진에서 언급한 3가지 몬스터의 기능을 구현하게 된다면,

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

public class Monster : MonoBehaviour
{
    protected virtual void Start()
    {
        Debug.Log("몬스터가 등장하였습니다.");
    }

    public virtual  void OnHit()
    {
        Debug.Log("몬스터가 아파합니다.");
    }

    protected virtual void Die()
    {
        Debug.Log("몬스터가 사망하였습니다.");
    }
}
class BombMonster : Monster
{
    protected override void Die()
    {
        base.Die(); //26번째 줄이 없으면 19번째 줄의 로그는 나타나지 않게된다.
        Debug.Log("몬스터가 폭발하였습니다.");
    }
}
class BerserkerMonster : Monster
{
    public override void OnHit() //OnHit함수는 public형태로 정의되었기 때문에 여기서도 같은 접근제한자를 따라야 합니다.
    {
        Debug.Log("몬스터가 분노합니다."); //base.OnHit()함수가 없으므로 몬스터는 아파하지 않는다.
    }
}
class SummonMonster : Monster
{
    protected override void Start() //함수의 상속 기능은 Awake,Start,Update등의 함수에도 사용이 가능하다.
    {
        base.Start();
        Debug.Log("몬스터가 다른 몬스터를 소환합니다.");
    }
}

이런식으로 구현이 될 것이다.

기존 몬스터 클래스의 함수들은 virtual을 붙여줘야 하고, 상속받는 함수들은 override를 붙여줘야 한다.

또한 접근제한자가 동일해야 상속이 가능하다.

base.함수명 을 통해서 기존 함수의 동작을 시킬수도 있고, 해당 부분이 없다면 기존 함수는 동작하지 않게된다.

 

함수 뿐 아니라 변수또한 자식 클래스가 이용 가능하다.

사망시, 부활하는 몬스터를 만든다면

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

public class Monster : MonoBehaviour
{
    protected int Hp;
    protected virtual void Start()
    {
        Debug.Log("몬스터가 등장하였습니다.");
    }

    public virtual  void OnHit()
    {
        Debug.Log("몬스터가 아파합니다.");
    }

    protected virtual void Die()
    {
        Debug.Log("몬스터가 사망하였습니다.");
    }
}
class ReviveMonster : Monster
{
    protected override void Die()
    {
        Debug.Log("몬스터가 부활하였습니다.");
        Hp = 100;
    }
}

위와같이 부모 클래스의 Hp변수의 값을 자유롭게 이용할 수 있게 된다.