ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #2 유니티 엔진 동작 원리 (클래스,메서드,상속,컴포넌트, 브로드캐스팅, MonoBehavior)
    유니티/유니티 공부 2025. 2. 28. 16:49

    이번글에서는 유니티에서 엔진이 동작하는, 정확히는 게임 속 모든 오브젝트들이 움직이는

    원리에 대해서 알아보려고 한다

     

    그전에, 이미 다른글에도 정리되어 있지만 가장 기본이며 가장 많이 쓰이게 될 

    클래스와 메서드에 대해 간단하게 설명하고 넘어가겠다

     

    클래스 : "객체(Object)를 만들기 위한 설계도"
    클래스는 변수(속성)와 메서드(기능)를 하나로 묶어 정의하는 개념

     

    메서드 : "클래스 안에서 특정 기능을 수행하는 함수"
    클래스 내부에서 행동(기능)을 정의하는 부분

     

    한번 가볍게 예시를 들어보겠다. 

    class Character 
    {
        public string name;
        public int health = 100;
    
        public Character(string _name) {
            name = _name;
        }
    
        // 메서드 (캐릭터가 이동하는 기능)
        public void Move() {
            Console.WriteLine(name + "이(가) 이동합니다!");
        }
    
        // 메서드 (데미지를 받는 기능)
        public void TakeDamage(int damage) {
            health -= damage;
            Console.WriteLine(name + "이(가) " + damage + " 데미지를 입었습니다! 현재 체력: " + health);
        }
    }
    
    
    
    --------------------------
    
    클래스와 메서드 사용하기
    
    Character player = new Character("Hero"); // 캐릭터 생성
    player.Move();       // "Hero이(가) 이동합니다!" 출력
    player.TakeDamage(20); // "Hero이(가) 20 데미지를 입었습니다! 현재 체력: 80" 출력

     

    지금 보면 Chrarcter라는 클래스안에 Move, TakeDamage 두 메서드가 들어간것을 확인할 수 있다

     

    그럼 클래스안에 무조건 메서드가 포함되어있어야 하냐? 당연하다

     

    • C#은 객체지향 언어라서 모든 기능(메서드)은 클래스 내부에 포함되어야 한다.
    • C++ 같은 일부 언어는 클래스 바깥에서도 함수(메서드)를 만들 수 있지만, C#에서는 불가능하.

     

    -----------------------------------------------

     

    1. 상속 & 상속의 한계

    2. 컴포넌트 & 컴포넌트가 상속을 대체할 수 있는 이유

    3. 유니티 안에서 컴포넌트

    4. 브로드캐스팅

     

    의 순서로 글을 정리해 진행해보겠다

     

    사실 유니티에서 정말 많이 사용되는건 컴포넌트. 하지만 그 컴포넌트에 대해 알아보기 전에

    상속이라는 개념에 대해 알아봐야지만, 왜 컴포넌트 패턴을 사용하는지 알게 될 것이다

     

    --------------------------------------------------------

    1. 상속 & 상속의 한계

     

    자 그럼 개임게발에서 쓰이는 상속의 정의를 알아보자

    더보기

    게임 개발에서 "상속"(Inheritance)은 객체지향 프로그래밍(OOP, Object-Oriented Programming) 개념 중 하나로, 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스 또는 서브 클래스)가 물려받아 사용할 수 있게 하는 기능을 의미한다.

    📌 상속의 주요 특징

    1. 코드 재사용성 – 부모 클래스의 기능을 자식 클래스가 그대로 사용하거나 확장할 수 있음.
    2. 유지보수 용이성 – 공통 기능을 부모 클래스에 정의해두면 수정이 쉬움.
    3. 확장성 – 자식 클래스에서 부모 클래스의 기능을 변경(오버라이딩)하거나 추가 가능.

    게임 개발에서는 상속을 활용하여 캐릭터, 적, 아이템, 무기 등 여러 개체를 효율적으로 관리할 수 있고,
    부모 클래스를 활용하면 중복 코드를 줄이고, 유지보수도 쉽게 할 수 있다는 장점이 있다

     

    이렇게 말하면 조금 난해할 수 있는데 예를들어 게임 개발을 하며 오크와 오크 대장을 만들어본다고 치자

     

    우선 오크는 사람도, npc도 아닌 몬스터(Enemy)로 분류되기 때문에

    몬스터에 관한 메서드와 변수들을 만들어준다 (이동하기, 상호작용, 공격하기...등)

     

    그리고 수많은 몬스터 들 중 만들어야하는건 오크기 때문에 오크들만이 가질수 있는 메서드와 변수들을 만들어준다

    (오크가 내는 소리, 오크 전용 공격, 오크의 걸음걸이....등)

     

    그리고 여기서 오크 대장을 만들고 싶다면 또 오크 대장들만이 가질수 있는 메서드와 변수들을 만들어줘야한다

    (오크 대장만 내는 소리, 오크 대장 전용 스킬 등)

     

    카테고리라고 생각하면 편하다 (몬스터 > 오크 > 오크 대장) 순으로 진행되고 그 중 근본이 되는것은 몬스터기 때문에

     

    이들을 효율적으로 구현하기 위해 Monster라는 클래스(Class)를 만들어준뒤 

     

    class Monster

    class Orc : Monster

    class OrcChieftan : Orc

     

    * 세미콜론(:) 을 기준으로 왼쪽이 자식, 오른쪽이 부모 클래스

     

    이런 식으로 몬스터를 상속받을수 있게 해주는것이다

    이렇게 할 경우 이제 오크가 아니라 트롤, 고블린 등

    몬스터라는 근본에서 파생되는 어떠한 몬스터를 만든다 하더라도 각각 그에 맞는 코드를 짜줄게 아니라

     

    그냥 근본이 되는 Monster 클래스를 상속받아 확장하면 되니 굉장히 작업이 편해지고 효율적으로 된다는 장점이 있다

     

    여기서 기초를 제공하는 근본이 되는 클래스를 부모 클래스

    부모클래스를 상속받아 기능을 확장하는 클래스를 자식 클래스라고 한다

     

    굉장히 전통적인 방법이나 이 방법은 한계가 있다..

     

    예를들어 직접 조종하는 플레이어와 상점지기 NPC는 같은 사람이지만

    외형만 같을뿐 전혀 다른 기능을 가지고 있다

     

    그렇기에 플레이어와 상점NPC의 근본이 될 Human 클래스에 가장 기본 기능이 될 이동기능조차 넣어줄 수 없게된다

    이게 상속의 한계이다. 게임의 규모가 커지고 점점 배치되는 오브젝트들이 다양해질수록

    상속은 힘들어질수 밖에 없다

     

    -------------------------------------------------------

     

    2. 컴포넌트

     

    그래서 채택한 방식이 바로 컴포넌트 패턴이다. 

    쉽게 말해 미리 만들어진 부품을 조립하여 하나의 완성된 오브젝트를 만드는 형식이다

     

    예를들어 동물 오브젝트 중 금붕어를 만든다 했을때 상속이었다면

     

    Animal 클래스를 상속받는 Fish 클래스를 상속받는 GoldFish 클래스 였겠지만

     

    컴포넌트의 경우

     

    폐, 아가미, 지느러미, 잠자기, 탯줄, 달리기, 뿔, 다리, 날개, 알낳기, 식사....등

     

    수많은 부품들을 만들어놓고 그 중 금붕어에 해당하는 부품들만 부착하여 조립하는 방식이다

    딱봐도 컴포넌트 패턴 방식이 훨~씬 손쉬워 보이고 유지보수도 간단해보인다

     

    실제로 컴포넌트 방식은

     

    1. 유연한 재사용 : 원하는 기능을 가진 컴포넌트만 선택적으로 골라쓰기 가능

    2. 기획자의 프로그래머 의존도 낮아짐 : 기획자가 미리 만들어진 컴포넌트로 잘 조립만 하면 됨

    3. 독립성 덕분에 기능 추가&삭제 쉬움 : 기능을 추가 혹은 삭제에도 코드 전체에 지장이 가질 않아 부담감 줄어듬

     

    의 장점들이 있다

     

    즉 금붕어를 만들고 싶다면 이름이 "금붕어"인 텅 빈 오브젝트를 하나 만든뒤

    그 속을 금붕어 기능에 관한 컴포넌트들로 채워넣으면 되는것이다

     

    --------------------------------------------------

     

    3. 유니티 안에서 컴포넌트

     

    자 그럼 컴포넌트에 대해서 알았으니 유니티에서는 어떻게 컴포넌트가 쓰이는지 확인해보자

     

    아주 간단하다. 오브젝트를 선택한뒤 Inspector 창에서 확인할 수 있다

    현재 Mesh Filter, Mesh Renderer, Box Collider 총 3가지의 컴포넌트가 부착되어 있는것을 볼 수 있다

     

    물론 각각의 고유 기능이 있고, 만약 Box Collier 컴포넌트를 제거한다 하더라도

    Box Collider에 관한 기능만 Cube에서 사라지는것일뿐 Cube라는 오브젝트 자체는 여전히 존재한다

     

    -------------------------------

     

    4. 브로드캐스팅

     

    컴포넌트 구조에서는 '전체 방송'이라는 통해 컴포넌트 안에 있는 특정 기능을 간접적으로 실행시킬 수 있다

    이것을 브로드 캐스팅이라고 한다

     

    그전에 MonoBehavior를 먼저 알고 가겠다

     

    유니티에서 코드만 짜면 보이는 MonoBehavior....부끄럽지만 난 지금까지 저게 뭔지 몰랐다...ㅋㅋ

    그냥 클래스가 무조건 상속하는 부모 클래스인것 정도만 알았지만 정확히 저게 뭔가 싶었다

     

    저것의 정체는 바로 유니티에서 미리 만들어 제공하는 클래스이며 컴포넌트에 필요한 기본 기능을 제공한다

    그럼 저걸 상속받는 이유가 도대체 무엇이냐! 

     

    첫번째! 유니티에서 컴포넌트를 추가할때, 유니티에서 자체적으로 만든 컴포넌트들을 추가할수도 있지만

    내가 내 입맛대로 만든 스크립트를 하나의 조립부품으로 처리해 컴포넌트로 추가할 수 있다

     

    검색해서 새로 만든 New Script를 컴포넌트로 추가해 줄 수 있다

     

     

    추가로 코드 맨 윗줄에 볼 수 있는 유니티 엔진들도 사용하여 코드를 짤 수 있다.

    사실상 코드 자체를 아예 유니티의 제어를 받게 해주는것이다

     

     

    두번째! MonoBehavior를 상속받으면 유니티의 제어를 받기 때문에 브로드캐스팅이라는 기능을 사용할 수 있게 해준다

    예를 들어보겠다

     

    <1번 오브젝트>

    첫번째 컴포넌트 : Eat(), Play(), Dance()

    두번째 컴포넌트 : Work(), Walk()

     

    <2번 오브젝트>

    첫번째 컴포넌트 : Eat(), Play(), Fly()

    두번째 컴포넌트 : Work(), Dance()

     

    <3번 오브젝트>

    첫번째 컴포넌트 : Eat(), Play(), Die()

    두번째 컴포넌트 : Work(), Walk()

    세번째 컴포넌트 : Dance()

     

    이렇게 3개의 오브젝트가 있다고 치자. 그럼 브로드캐스팅으로 말한다

     

    브로드캐스팅 : 자자! 지금부터 컴포넌트안에 Dance 메서드 있는 분들은 모두 실행해주세요~

     

    이 메세지는 게임 세상에 있는 모든 오브젝트들에게 전부 전달된다. 100개면 100개 모두

    그럼 게임 세상에 있는 모든 오브젝트들이 자신의 부품안에 Dance() 메서드가 있는지 찾는다

     

    오브젝트들은 메세지가 어디서 왔는지 따지지 않는다. 브로드캐스트 역시 누가 이 메세지를 받을지 따지지 않는다

    그리고 오브젝트들은 만약 본인에게 Dance 메서드가 없다면 이 메세지를 무시해버린다

    당연히 Dance() 메서드가 있다면 실행한다

     

    이렇듯 일일이 내가 가서 오브젝트들에게 Dance() 메서드를 실행해줄 필요없이

    단 한번의 브로드캐이팅으로 Dance() 메서드를 가진 모든 컴포넌트가 Dance() 메서드를 실행하게 해준다

     

    한줄 정리 : 브로드캐스팅은 특정 오브젝트를 직접 가르키지 않고 원하는 기능을 수행하게 한다

    이는 컴포넌트가 다른 컴포넌트에게 의존하지 않고 독립적으로 동작하는 구조이기에 가능한 것.

     

     

     

    '유니티 > 유니티 공부' 카테고리의 다른 글

    #1 유니티 인터페이스 (Edit bounding volume, Flythrough)  (1) 2025.02.26
    충돌판정  (1) 2024.03.04
    가까운 적 찾기  (2) 2024.02.28
    직렬화를 이용하여 저장 객체 저장  (1) 2024.02.15
    json 응용  (0) 2024.02.14
Designed by Tistory.