Unity Chapter 7-5. C# 프로그래밍 [중급] (2/2) : 인터페이스

Date:     Updated:

카테고리:

태그:

인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀
🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!


Chapter 7. C# 프로그래밍 : 중급 (2/2)


🔔 인터페이스

모든 아이템의 공통적인 기능, 모든 직업의 공통적인 특징인터페이스 안에 구현함.

Interface : 인터페이스를 상속받는 자식 클래스들은 인터페이스의 함수나 프로퍼티를 반드시 모두 재정의 해야 한다.

다형성을 통해 부모클래스인 Interface여러 자식들을 한번에 관리할 수 있다.


인터페이스를 쓰지 않은 경우

  • Player 가 아이템을 먹으면 Hp 혹은 Gold가 증가하게 하려 한다.
  • 아이템들은 충돌 처리를 위해 Collider 컴포넌트에서 Is Trigger 체크를 해준다.

📜 GoldItem.cs

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

public class GoldItem : MonoBehaviour
{
    public int goldAmount = 100;

    public void Use()
    {
        Debug.Log("골드를 얻었다!");

        Player player = FindObjectOfType<Player>(); // 플레이어를 찾아
        player.gold += goldAmount; // 플레이어의 골드를 100만큼 증가시킨다.

        gameObject.SetActive(false); // 골드 아이템을 획득했으니 꺼준다.
    }
}

📜 HealthKitItem.cs

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

public class HealthKitItem : MonoBehaviour
{
    public int restoreHealth = 100;

    public void Use()
    {
        Debug.Log("체력을 회복했다!");

        Player player = FindObjectOfType<Player>(); // 플레이어를 찾아
        player.hp += restoreHealth; // 플레이어의 hp를 100만큼 증가시킨다.

        gameObject.SetActive(false); // 헬스킷을 획득했으니 꺼준다.
    }
}

📜Player.cs

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

public class Player : MonoBehaviour
{
    public float hp = 50;
    public int gold = 1000;

    private Rigidbody2D m_rigidbody;
    private float speed = 3f;
    private float jumpSpeed = 5f;

    void Start()
    {
        m_rigidbody = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        Vector2 currentVelocity = m_rigidbody.velocity;
        float horizontal = Input.GetAxis("Horizontal");
        currentVelocity.x = horizontal * speed;

        if(Input.GetButtonDown("jump"))
        {
            currentVelocity.y = jumpSpeed;
        }

        m_rigidbody.velocity = currentVelocity;
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        GoldItem goldItem = other.GetComponent<GoldItem>();
        if(goldItem != null)
        {
            goldItem.Use();
        }

        HealthKitItem healthKitItem = other.GetComponent<HealthKitItem>();
        if(healthKitItem != null)
        {
            healthKitItem.Use();
        }
    }
}

인터페이스를 사용하는 이유

    void OnTriggerEnter2D(Collider2D other)
    {
        GoldItem goldItem = other.GetComponent<GoldItem>();
        if(goldItem != null)
        {
            goldItem.Use();
        }

        HealthKitItem healthKitItem = other.GetComponent<HealthKitItem>();
        if(healthKitItem != null)
        {
            healthKitItem.Use();
        }

        // 아아템이 늘어날 수록 이 if문을 계속해서 추가해야한다.
    }
  • 문제는 실제 게임상에선 아이템 종류가 한 두개가 아니라는 것.
    • 아이템이 수십개, 수백개일 경우 아이템마다 GetComponent 해 와서 if문 처리를 하면 코드가 길어지고 복잡해질 것이다.
    • 한마디로 노가다다.
  • Use()함수는 모든 아이템들이 가지는 공통된 기능이므로 아이템 용 인터페이스 를 만들어 이를 상속받는 모든 자식들이 Use() 함수를 구현하게 한다면
    • 다형성을 사용하여 자식의 타입과 상관없이 부모(인터페이스) 타입 하나로 공통된 Use() 함수를 사용할 수 있다.


인터페이스를 사용한 경우

  • 인터페이스 C# 스크립트의 이름은 무조건 앞에 대문자 I를 붙여주어야 한다.
    • 인터페이스 스크립트 📜IItem.cs 를 만들어 주었다.

인터페이스를 상속받는 자식클래스들은 모든 함수 혹은 프로퍼티를 반드시 재정의 하여야한다.

인터페이스 작성하기

📜IItem.cs
public interface IItem
{
    void Use();
}
  • 스크립트 생성시 기본으로 적혀있는 using UnityEngine, 클래스 등등 전부 다 지워준 후
  • public interface 인터페이스이름 을 작성해준다.
  • void Use();
    • 이 인터페이스를 상속받을 자식클래스에서 전부 재정의 하도록 함수는 껍데기(프로토타입)만 작성한다.
      • 인터페이스는 자식 클래스들이 이를 어떻게 재정의할지는 신경쓰지 않지만 반드시 재정의 하여 이 함수를 가지도록 강제한다.

인터페이스 상속받고 재정의하기

📜 GoldItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GoldItem : MonoBehaviour, IItem
{
    public int goldAmount = 100;

    public void Use()   // 오버라이딩
    {
        Debug.Log("골드를 얻었다!");

        Player player = FindObjectOfType<Player>();
        player.gold += goldAmount;

        gameObject.SetActive(false);
    }
}
  • public class GoldItem : MonoBehaviour , IItem
    • 📜GoldItem 클래스는 부모클래스인 📜IItem 인터페이스도 상속받고 MonoBehaviour도 상속받는다. (다중상속)
    • 📜IItem 인터페이스의 함수 Use()반드시 재구현 해야한다.
      • 함수 Use()을 오버라이딩 하지 않으면 에러가 난다.
📜 HealthKitItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HealthKitItem : MonoBehaviour, IItem
{
    public int restoreHealth = 100;

    public void Use()
    {
        Debug.Log("체력을 회복했다!");

        Player player = FindObjectOfType<Player>();
        player.hp += restoreHealth;

        gameObject.SetActive(false);
    }
}
  • public class HealthKitItem : MonoBehaviour , IItem
    • 📜HealthKitItem 클래스는 부모클래스인 📜IItem 인터페이스도 상속받고 MonoBehaviour도 상속받는다. (다중상속)
    • 📜IItem 인터페이스의 함수 Use()반드시 재구현 해야한다.
      • 함수 Use()을 오버라이딩 하지 않으면 에러가 난다.


정리

📜Player.cs
void OnTriggerEnter2D(Collider2D other)  // 코드가 훨씬 깔끔해졌다!.
{
    IItem item = other.GetComponent<IItem>();

    if(item != null)
    {
        item.Use();
    }
}
  • 모든 아이템들은 📜IItem 인터페이스를 상속받기 때문에 Use() 함수를 가지고 있는 것이 보장되어 있다.
    • 모든 아이템들은 공통적으로 Use()함수를 가지고 있다.
  • 따라서 다형성에 의하여 부모 타입 IItem 하나로 한방에 모든 아이템들의 Use()함수를 실행시킬 수 있다.
    • IItem item = other.GetComponent<IItem>();
      • 어떤 종류의 아이템이든 IItem 타입 하나로 받을 수 있다.
      • 인터페이스를 사용하니 아이템들을 각각 구별하여 if-else문 혹은 switch문을 사용하여 처리할 필요가 없어졌다.
    • 코드가 훨씬 간결해짐
    • 다만, 📜GoldItem 과 📜HealthKitItem 의 각자의 고유한 기능은 IItem으로 접근할 수 없음.

모든 자식 클래스들이 1️⃣ 기본적으로 가지고 있어야 하며 2️⃣ 각자 다양한 방식으로 기능해야 하는 함수라면 인터페이스에 이 함수를 구현하여 상속 받아 사용하자.


인터페이스만의 특징, 주의사항

  1. 인터페이스 스크립트는 컴포넌트로서 오브젝트에 붙일 수 없다.
    • 그저 자식들이 꼭 구현해야할 함수 목록만 만들어 놓은 껍데기이기 때문이다.
    • 찍어낼 수 없다.
  2. 멤버가 구현되어 있으면 안된다.
    • 멤버 변수를 가질 수 없으며
    • 함수 또한 전부 프로토타입만 있어야 한다. 구현된 함수를 가질 수 없음.


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Unity Lesson 1 카테고리 내 다른 글 보러가기

댓글 남기기