주제
- 본 강의의 핵심 주제는 GameObject를 구성하는 다양한 기능들을 Component(컴포넌트) 라는 독립된 부품 단위로 설계하고 구현하는 것이다.
- 유니티(Unity)의 GameObject + Component 구조를 모방하여, 조합 기반(Composition-based) 구조를 갖는 확장성 높은 게임 오브젝트 시스템을 구축한다.
개념
1. Component란?
- Component는 GameObject에 부착되어 기능을 제공하는 부품 단위 클래스이다.
- 예를 들어 위치를 담당하는 Transform, 렌더링을 담당하는MeshRenderer, 시점을 담당하는Camera, 사용자 정의 로직을 담당하는Script가 있다.
- 상속 기반의 Unreal 방식과 달리 Unity 방식은 빈 GameObject에 필요한 기능을 조립해서 완성하는 구조이며, 이는 유연성과 재사용성이 뛰어나다.
2. 구조 설계 원칙
- 고정형 컴포넌트(Fixed): Transform, MeshRenderer, Camera, Animator는 하나만 존재 가능.
- 동적 컴포넌트(Script 계열): Script(MonoBehaviour)는 여러 개 부착 가능.
- Component는 Awake, Start, Update, LateUpdate, FixedUpdate 같은 생명 주기 함수를 통해 시점 기반 동작을 처리한다.
용어정리
| 용어 | 설명 | 
|---|
| GameObject | 게임 월드 내 존재하는 모든 객체 | 
| Component | GameObject에 부착되어 기능을 수행하는 부품 | 
| MonoBehaviour | 사용자 정의 Script 컴포넌트의 기본 클래스 | 
| ComponentType | enum으로 컴포넌트 종류를 구분 | 
| Awake | 오브젝트 생성 시점에 초기화하는 함수 | 
| Start | 게임 실행 직후 한 번만 호출되는 초기 함수 | 
| Update | 매 프레임마다 호출되는 일반 갱신 함수 | 
| LateUpdate | Update 이후 호출되는 후처리용 함수 | 
| FixedUpdate | 일정 간격으로 호출되는 물리 갱신용 함수 | 
| shared_from_this | 클래스 내부에서 자신을 shared_ptr로 안전하게 반환 | 
| weak_ptr | 참조용 스마트 포인터, 소유권 없음 | 
코드 분석
1. ComponentType 정의 및 고정형 컴포넌트 갯수
enum class ComponentType : uint8
{
    Transform,
    MeshRenderer,
    Camera,
    Animator,
    Script,      
    End
};
enum
{
    FIXED_COMPONENT_COUNT = static_cast<uint8>(ComponentType::End) - 1
};
- 고정형 컴포넌트는 총 4개이며, Script는 유일하게 여러 개 부착 가능한 컴포넌트로 FIXED_COMPONENT_COUNT이후부터 관리된다.
2. Component 클래스 설계
class Component
{
public:
    Component(ComponentType type);
    virtual ~Component() {}
    virtual void Awake() {}
    virtual void Start() {}
    virtual void Update() {}
    virtual void LateUpdate() {}
    virtual void FixedUpdate() {}
    ComponentType GetType() { return _type; }
    void SetGameObject(shared_ptr<GameObject> gameObject) { _gameObject = gameObject; }
    shared_ptr<GameObject> GetGameObject();
    shared_ptr<Transform> GetTransform();
protected:
    ComponentType _type;
    weak_ptr<GameObject> _gameObject;
};
- Awake~FixedUpdate: 생명 주기 메서드. 게임 흐름에 따라 자동 호출됨.
- SetGameObject: 소유 GameObject를 설정한다.
- GetTransform: 연결된 GameObject의 Transform을 간접적으로 반환한다.
3. MonoBehaviour 클래스 구현
class MonoBehaviour : public Component
{
public:
    MonoBehaviour() : Component(ComponentType::Script) {}
    virtual void Awake() override {}
    virtual void Update() override {}
};
- Script 전용 컴포넌트로, 사용자 정의 스크립트 로직을 구현할 기본 클래스이다.
- 직접 GameObject에 붙여서 사용할 수 있으며, Update()등을 재정의하여 동작시킨다.
4. GameObject 클래스와 컴포넌트 배열
class GameObject : public enable_shared_from_this<GameObject>
{
protected:
    std::array<shared_ptr<Component>, FIXED_COMPONENT_COUNT> _components;
    std::vector<shared_ptr<MonoBehaviour>> _scripts;
public:
    void AddComponent(shared_ptr<Component> component);
    shared_ptr<Component> GetFixedComponent(ComponentType type);
    shared_ptr<Transform> GetTransform();
    shared_ptr<Transform> GetOrAddTransform();
    void Awake();
    void Start();
    void Update();
    void LateUpdate();
    void FixedUpdate();
};
- _components: 고정형 컴포넌트들 저장 (Transform, Camera 등)
- _scripts: MonoBehaviour를 여러 개 저장하는 리스트
5. AddComponent 구현
void GameObject::AddComponent(shared_ptr<Component> component)
{
    component->SetGameObject(shared_from_this());
    uint8 index = static_cast<uint8>(component->GetType());
    if (index < FIXED_COMPONENT_COUNT)
        _components[index] = component;
    else
        _scripts.push_back(dynamic_pointer_cast<MonoBehaviour>(component));
}
- 반드시 enable_shared_from_this를 상속해야shared_from_this()사용 가능
- ComponentType에 따라 _components혹은_scripts에 분류하여 삽입
shared_ptr<Transform> GameObject::GetTransform()
{
    return static_pointer_cast<Transform>(GetFixedComponent(ComponentType::Transform));
}
shared_ptr<Transform> GameObject::GetOrAddTransform()
{
    if (!GetTransform())
        AddComponent(make_shared<Transform>());
    return GetTransform();
}
- Transform은 GameObject에 반드시 존재해야 함
- 없을 경우 자동으로 생성해서 부착
7. 컴포넌트 생명 주기 실행
void GameObject::Update()
{
    for (auto& comp : _components)
        if (comp) comp->Update();
    for (auto& script : _scripts)
        script->Update();
    _transformData.matWorld = GetOrAddTransform()->GetWorldMatrix();
    _constantBuffer->CopyData(_transformData);
}
- 모든 컴포넌트들을 순회하면서 생명 주기 메서드를 호출한다.
- Awake,- Start,- LateUpdate,- FixedUpdate역시 동일한 방식으로 구현
class Transform : public Component
{
public:
    Transform() : Component(ComponentType::Transform) {}
    Vec3 GetRight() { return _matWorld.Right(); }
    Vec3 GetUp()    { return _matWorld.Up(); }
    Vec3 GetLook()  { return _matWorld.Backward(); }
};
- _right,- _up,- _look은 캐싱하지 않고 행렬에서 실시간 계산
- 좌표계 방향에 따라 Right,Up,Backward를 선택함
| 함수 | 설명 | 
|---|
| TransformNormal | 방향 벡터 변환 ( w=0), 위치 무시 | 
| TransformCoord | 좌표 변환 ( w=1), 위치까지 포함 | 
- 방향(look, up, right) 계산 시에는 반드시 TransformNormal을 사용해야 한다.
핵심
- Component는 GameObject의 기능을 수행하는 독립된 부품 클래스이다.
- GameObject는 실제 게임 엔티티이며, 모든 기능은 Component 조합을 통해 구현된다.
- 고정형 컴포넌트와 동적 컴포넌트로 구조를 나누어 효율적 관리가 가능하다.
- Unity 스타일의 생명주기 함수(Awake, Start, Update 등)를 지원하여 시간 기반의 흐름을 통합할 수 있다.
- shared_from_this()와- weak_ptr기반 연결로 스마트 포인터의 안전성 확보.
- Transform, Camera, MonoBehaviour 등 모든 기능은 Component로 확장 가능하며, 재사용성과 유지보수성을 극대화할 수 있다.