인터페이스"님" 과 상속"님" 에 대해서

네,가능합니다 ㅣ 2024. 11. 8. 21:37

인터페이스씨와 상속씨는 나랑 별로 친하지 않은것같다.

 

다들 좋다는데 왜 나랑 안친한지 모르겠다

 

그래서 친해져보려고 두분에 대해서 알아보기로 했다

 

항상 그렇게 하듯 예제를 통해서 앞으로 이런 개발과정이 있을 때

 

인터페이스씨 혹은 상속씨가 생각이라도 나도록 게임개발에 쓰일만한 예제들을 찾아서 작성해봐야겠다.

 

인터페이스(님)

인터페이스는 공통된 기능을 구현할때 사용하면 좋다.

강의에서 사용했던 것 처럼 상호작용, 공격, 데미지 처리 이런곳에 좋은 인터페이스(님) 이다.

이렇게 적고나니 조금은 친한거같기도 하다. 친해질 기회가 별로 없었나보다.

 

첫번째 인터페이스 예제는 상호작용이다.

// IInteractable 인터페이스를 구현해주고
// 상호작용을 원하는 녀석들에게 달아주자
// 여긴 없지만 인터렉트뿐이 아니라 프롬프트 등으로 텍스트 출력하는것도 매우 좋다
public interface IInteractable
{
    void Interact();
}

// 문에 달아주기
public class Door : MonoBehaviour, IInteractable
{
    public void Interact()
    {
        // 문이 열리는 로직
    }
}

// 창문에 달아주기
public class Window : MonoBehaviour, IInteractable
{
    public void Interact()
    {
        // 창문이 열리는 로직
    }
}

// 플레이어에서 인터페이스를 이용하여 쉽게 상호작용을 구현하자
public class Player : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.E)) // 예제라서 이렇게 구현한것 인풋시스템 애용하길
        {
            RaycastHit hit;
            // 레이캐스트에 감지되면
            if (Physics.Raycast(transform.position, transform.forward, out hit, 3f))
            {	// IInteractable을 TryGetComponent로 예외처리 및 가져오기 시도
                if (hit.collider.TryGetComponent<IInteractable>(out IInteractable interactable))
                {
                    interactable.Interact(); // 상호작용 가능한 객체라면 Interact() 호출
                }
            }
        }
    }
}

 

 

다음은 데미지 처리도 한번 해보자 오늘은 친해지기로 약속했기때문에 고봉밥이다.

 

 

// IDamageable 인터페이스 정의
public interface IDamageable
{
    void TakeDamage(int amount);
}

// 플레이어
public class Player : MonoBehaviour, IDamageable
{
    public int health = 100;

    public void TakeDamage(int amount)
    {
        health -= amount;

        if (health <= 0)
        {
            // 죽었습니다.
        }
    }
}

// 적
public class Enemy : MonoBehaviour, IDamageable
{
    public int health = 100;

    public void TakeDamage(int amount)
    {
        health -= amount;

        if (health <= 0)
        {
            Destroy(gameObject);
        }
    }
}

// 총알 (무기류) IDamageable이 구현되어있으면 구분없이 각자에게 구현된 TakeDamage를 호출한다
// 너무 좋지 않은가 벌써 심장이 두근거린다
// 나는 이런 재밌는걸 배울때마다 도파민이 분비된다 변태인가보다
public class Bullet : MonoBehaviour
{
    public int damage = 10;

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.TryGetComponent<IDamageable>(out IDamageable damageable))
        {
            damageable.TakeDamage(damage);
        }
        else
        {
            Destroy(collision.gameObject);
        }
    }
}

 

상속씨에대해서는 아이템을 예로 들어서 한번 보겠다.

 

아이템은 공통적으로 이름이 있고, 사용할 수 있다.

 

포션과 무기에 아이템 클래스를 상속시켜보겠다.

 

// 아이템
public abstract class Item
{
    public string itemName;
    public abstract void Use(Character character);
}

// 포션에 아이템을 상속시킴
public class HealthPotion : Item
{
    public int healAmount = 10;

    public HealthPotion()
    {
        itemName = "체력 포션";
    }

    public override void Use(Character character)
    {
    	// 사용시 체력회복 로직을 적용시킴
        character.Heal(healAmount);
    }
}

// 무기에도 아이템을 상속시킴
public class Weapon : Item
{
    public int damage = 10;

    public Weapon()
    {
        itemName = "기본 무기";
    }

    public override void Use(Character character)
    {
    	// 사용 시 공격을 함
        character.AttackWithWeapon(damage);
    }
}

 

이런식으로도 사용이 가능하다. 이거는 사실 좀 잘못된 예제인것같다 미안하다

 

쓰고나니 이럴거면 인터페이스를 쓰는게 맞나 이렇게 하는게 아니라

 

음.. 이전에 배웠던 상태패턴을 사용한것처럼 상태패턴에 적용하는게 더 친해지기 쉬울것같다.

코드로 얘기하자

 

// 기본 상태 클래스
public abstract class CharacterState
{
    public abstract void EnterState(Character character);
    public abstract void UpdateState(Character character);
    public abstract void ExitState(Character character);
}

// 대기 상태 클래스
public class IdleState : CharacterState
{
    public override void EnterState(Character character)
    {
        // 아이들 전처리
    }

    public override void UpdateState(Character character)
    {
        // 아이들 상태에서 진행할 행동
    }

    public override void ExitState(Character character)
    {
        // 후처리
    }
}

// 이동 상태 클래스
public class MoveState : CharacterState
{
    public override void EnterState(Character character)
    {
    	// 전처리 ex) 애니메이션켜기
    }

    public override void UpdateState(Character character)
    {
        // 움직이기 로직 ?
    }

    public override void ExitState(Character character)
    {
        // 후처리
    }
}

// 공격 상태 클래스
public class AttackState : CharacterState
{
    public override void EnterState(Character character)
    {
        // 전처리
    }

    public override void UpdateState(Character character)
    {
        // 공격 로직 ?
    }

    public override void ExitState(Character character)
    {
        // 딜레이 끝나면 다른 상태로 전환 ?
    }
}

// 캐릭터 클래스
public class Character : MonoBehaviour
{
    public CharacterState IdleState = new IdleState();
    public CharacterState MoveState = new MoveState();
    public CharacterState AttackState = new AttackState();

    private void Start()
    {
        TransitionToState(IdleState); // 초기설정 대기로
    }

    private void Update()
    {
        currentState.UpdateState(this); // 현재 상태를 지속적으로 업데이트
    }
    
}

 

아 나는 상속이랑도 조금은 친했었구나 !