Component는 Object를 생성하기 위해 필요한 여러가지(Transform, Mesh, Collider, Light...등등)를 부품(Component)처럼 필요한 것을 Object에 추가하고 제거하는 방식으로 사용하는 것을 의미한다.
유니티
언리얼
Component.h
#pragma once
enum class COMPONENT_TYPE : uint8
{
TRANSFORM,
MESH_RENDERER,
// ...
MONO_BEHAVIOUR, // 마지막 순서로 등장해야함, 여러개를 넣어줄 수 있기 때문에 따로 관리하여야하기 때문
END,
};
enum
{
// MONO_BEHAVIOUR을 제외한 Component개수를 저장
FIXED_COMPONENT_COUNT = static_cast<uint8>(COMPONENT_TYPE::END) - 1
};
class GameObject;
class Transform;
class Component
{
public:
Component(COMPONENT_TYPE type);
virtual ~Component(); // 부모 클래스로 사용되기 때문에 virtual 필수
public:
// 4총사
virtual void Awake() { } // 가장 먼저
virtual void Start() { } // Awake 다음에
virtual void Update() { } // 매 틱마다 실행
virtual void LateUpdate() { } // Update 이후 실행
public:
COMPONENT_TYPE GetType() { return _type; }
bool IsValid() { return _gameObject.expired() == false; } // 소멸 체크
shared_ptr<GameObject> GetGameObject();
shared_ptr<Transform> GetTransform();
private:
friend class GameObject; // GameObject에게만 접근 권한을 설정
void SetGameObject(shared_ptr<GameObject> gameObject) { _gameObject = gameObject; }
protected:
COMPONENT_TYPE _type;
weak_ptr<GameObject> _gameObject; // gameObject와 Component는 서로 누구와 연결되어 있는지
// 알고 있어야 하기 때문에 Shared_ptr을 사용하면 순환구조 발생
// 따라서 Weak_ptr로 선언
};
GameObject.h
#pragma once
#include "Component.h"
class Transform;
class MeshRenderer;
class MonoBehaviour;
class GameObject : public enable_shared_from_this<GameObject> // 자기 자신의 shared_pointer을 건네주고자 할 때 사용
{
public:
GameObject();
virtual ~GameObject();
void Init();
void Awake();
void Start();
void Update();
void LateUpdate();
shared_ptr<Transform> GetTransform();
void AddComponent(shared_ptr<Component> component);
private:
array<shared_ptr<Component>, FIXED_COMPONENT_COUNT> _components; // 고정된 번호, 타입당 1개만 존재
vector<shared_ptr<MonoBehaviour>> _scripts; // scripts는 따로 관리
};
Component로 TRANSFORM, MESH_RENDERER, MONO_BEHAVIOUR 를 가지고 있고, 추후에 다른 Component를 추가할 경우 꼭 enum class 의 MonoBehviour보다 앞 순서에 배치해야한다.
각각의 Component는 Awake, Start, Update, LateUpdate를 갖는데 초반 초기화나 갱신에 사용된다. Component를 갖는 GameObject에도 똑같은 멤버함수가 있는데 이는 각각의 Component의 초기화 갱신 함수를 호출한다.
인게임 - 로비 - 로그인과 같이 서로 겹치지 않는 Object를 사용하는 경우 Scene을 통해 구분하여 관리한다.
Scene에 포함된 Object들의 초기화와 갱신은 Scene에서 관리한다.
싱글톤 패턴을 사용하여 SceneManager을 호출해 어디서든 사용이 가능하도록 설계한다.
Scene.h
#pragma once
class GameObject;
class Scene
{
public:
void Awake();
void Start();
void Update();
void LateUpdate();
void AddGameObject(shared_ptr<GameObject> gameObject);
void RemoveGameObject(shared_ptr<GameObject> gameObject);
private:
vector<shared_ptr<GameObject>> _gameObjects;
// vector로 관리할 경우 특정 Object를 찾을 때 불편함
// 따라서 상용엔진의 경우 Vector를 번호를 매겨서(Layer) 벡터의 배열로 나누어 저장함
// Layer
// [0] wall
// [1] Monster
};
SceneManager.h
#pragma once
class Scene;
class SceneManager
{
DECLARE_SINGLE(SceneManager);
public:
void Update();
void LoadScene(wstring sceneName);
shared_ptr<Scene> GetActiveScene() { return _activeScene; }
private:
shared_ptr<Scene> LoadTestScene();
private:
shared_ptr<Scene> _activeScene;
};