Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(22일차) - Interface(인터페이스)를 활용한 스크립트 작성

by 독기품은토끼 2025. 6. 16.
✅ 오늘의 학습 목표
1. Interface (인터페이스) 활용하면서 상속&Override 복습

 

1. 인터페이스

클래스가 반드시 구현해야 할 기능(메서드)들의 집합으로 실제 기능 구현은 클래스에서 하고 형태(규약)만을 정의하는 방법

  • 인터페이스는 class가 아닌 interface 키워드로 정의
  • 'public class 클래스명 : 인터페이스명' 형태로 구현됨
  • C#에서는 다중 상속의 개념이 없어 다중 인터페이스를 구현함

 

1.  NPC 예제

일반 NPC는 대화를 할 수 있고,

경비병 NPC는 공격 기능이 있지만 대화 기능은 없는 시스템을 구현해 보자

public interface IMove { void Move(); }
public interface IAttack { void Attack(); }
public interface ITalk { void Talk(); }

 

우선 모든 NPC는 걸어 다닐 수 있으니 중복되는 부분은 인터페이스로 구현해 주면 관리가 수월하다.

오늘은 인터페이스 실습이니까 Attack과 Talk도 같이 만들어주었다.

 

 

1.1. 마을 사람 (이동 + 대화 가능)

public class TownPerson : MonoBehaviour, IMove, ITalk
{
    public float hp;
    public float speed;
    
    public void Move()
    {
        Debug.Log("Move");
    }

    public void Talk()
    {
        Debug.Log("Talk");
    }
}

 

1.2. 경비병 (이동 + 공격 가능)

public class TownGuard : MonoBehaviour, IMove, IAttack
{
    public void Move()
    {
        Debug.Log("Move");
    }

    public void Attack()
    {
        Debug.Log("Attack");
    }
}

 

두 코드를 보면 NPC의 기능마다 불러오는 인터페이스가 다르다.

이렇게 인터페이스를 활용하면 오브젝트별로 행동 조합이 가능하다.

 

2. Damage 예제

디테일이 높은 게임들을 보면 플레이어의 힘에 따라 문이 부서지는 게임을 몇 본 적이 있을 거다.

이 부분을 구현해 주기 위해 문과 벽 오브젝트를 만들고 벽은 부서지지 않도록 구현해 보자.

public interface IDamageable
{
    void TakeDamage(float damage);
    void Death();
}

 

2.1. Door & Wall

public class Wall : MonoBehaviour { } // 그냥 벽

public class Door : MonoBehaviour, IDamageable
{
    public float hp = 100f;

    public void TakeDamage(float damage)
    {
        Debug.Log($"{damage}만큼의 피해를 입었습니다.");
        hp -= damage;
        if (hp <= 0f) Death();
    }

    public void Death()
    {
        Debug.Log("문이 파괴되었습니다.");
    }
}

 

인터페이스로 공격 데미지와 죽음 기능을 만들고, door의 hp를 설정하여 hp가 0이 되었을 때의 이벤트를 만들어주었다.

 

public class Sword : MonoBehaviour
{
    public float damage = 10f;

    private void OnTriggerEnter(Collider other)
    {
        if (other.GetComponent<IDamageable>() != null)
        {
            other.GetComponent<IDamageable>().TakeDamage(damage);
        }
    }
}

 

공격 데미지를 입힐 Sword도 생성해주고 Trigger 감지를 통해서 데미지를 입히도록 설정해 주었다.

 

3. Monster (가상화 & 추상화 활용)

public abstract class Monster : MonoBehaviour, IDamageable
{
    public float hp;

    public abstract void SetHealth();

    void Start() => SetHealth();

    public virtual void Move()
    {
        Debug.Log("몬스터가 천천히 이동한다.");
    }

    public void TakeDamage(float damage)
    {
        hp -= damage;
        if (hp <= 0f) Death();
    }

    public void Death()
    {
        Debug.Log("몬스터 죽음");
    }
}

 

SetHealth()는 몬스터마다 체력이 다르니까 강제로 구현하도록 abstract로 만들고,

Move()는 기본 행동을 만들어두고 필요하면 바꿔치기할 수 있도록 virtual을 사용해 주었다.

 

3.1. Ocr

public class Orc : Monster
{
    public override void SetHealth()
    {
        hp = 100f;
    }

    public override void Move()
    {
        base.Move(); // 몬스터 기본 움직임도 실행하고
        Debug.Log("오크가 쿵쾅쿵쾅 달려온다!");
    }
}

 

오크의 체력을 100으로 해주었고 부모 클래스의 Move 메서드를 그대로 실행하는 base 명령어를 사용해 주었다.

 

3.2. Goblin

public class Goblin : Monster
{
    public override void SetHealth()
    {
        hp = 30f;
    }
}

 

이렇게 Override와 Base의 조합으로 기본 동작 + 커스텀 동작 둘 다 사용 가능함을 확인할 수 있었다.

 

4. Item

아이템에 닿으면 아이템이 주워지고, 사용하고, 버릴 수 있는 기능을 구현해 보자.

 

public interface IDropItem
{
    void Grab();   // 줍기
    void Use();    // 사용
    void Drop();   // 버리기
}

 

우선 아이템별로 중복된 메서드가 있으니 인터페이스로 구현해 주었다.

 

4.1. 손전등

public class FlashLight : MonoBehaviour, IDropItem
{
    public GameObject lightObj;
    public bool isLight;

    public void Grab() { Debug.Log("손전등을 주웠다."); }

    public void Use()
    {
        isLight = !isLight;
        lightObj.SetActive(isLight);
        Debug.Log("라이트를 켠다.");
    }

    public void Drop() { Debug.Log("손전등을 버렸다."); }
}

 

4.2. 총

public class Gun : MonoBehaviour, IDropItem
{
    public void Grab() { Debug.Log("총을 주웠다."); }
    public void Use() { Debug.Log("총을 발사한다."); }
    public void Drop() { Debug.Log("총을 버렸다."); }
}

 

4.3. 캐릭터

public class Character : MonoBehaviour
{
    public IDropItem currentItem;

    void Update()
    {
        if (Input.GetMouseButtonDown(0)) currentItem.Use();
        if (Input.GetKeyDown(KeyCode.B)) currentItem.Drop();
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.GetComponent<IDropItem>() != null)
        {
            IDropItem item = other.GetComponent<IDropItem>();
            item.Grab();
            currentItem = item;
        }
    }
}

 

이렇게 어떤 아이템이든 IDropItem 인터페이스를 상속받았다면

캐릭터가 똑같은 방식으로 획득/사용/버리기가 가능하다.

 

 

 


 

 

오늘은 하루 종일 인터페이스 관련된 수업을 진행했다.

기능은 똑같이 사용하는데 스크립트는 계속 바뀌다 보니 좀 정신이 없었고 계속 똑같은 작업이다 보니 살짝 지루해졌다..

그래도 내용 놓치지 않으려고 열심히 집중했음!!

내일은 유니티 활용해서 인터페이스를 구현해 보겠다 하셨으니 내일 수업은 재미있을 것 같담

암튼 오늘 기록 끝!