Component와 Scene

이승덱·2021년 7월 30일
0

Graphics&DirectX

목록 보기
13/37

Component

  • Component는 Object를 생성하기 위해 필요한 여러가지(Transform, Mesh, Collider, Light...등등)를 부품(Component)처럼 필요한 것을 Object에 추가하고 제거하는 방식으로 사용하는 것을 의미한다.

  • 유니티

    • 유니티의 경우 빈 깡통에서 부품을 추가하는 방식을 사용한다.
    • Scripts를 통해 MonoBehaviour을 상속한 Component를 만들어 다양한 기능을 만들 수 있다.
    • 상대적으로 자유도가 높고 간단하다.
  • 언리얼

    • 언리얼의 경우 유니티와는 달리 Object종류에 따라 미리 규격화하여 제공한다.
    • 틀이 강력하게 잡혀있다.
    • 따라서 상대적으로 자유도가 낮고 복잡하지만 같은 유형의 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보다 앞 순서에 배치해야한다.

    • 그 이유는 MonoBehaviour은 Scripts이기 때문에 여러개의 Component가 존재할 수 있지만, 다른 Component의 경우 GameObject당 하나의 Component만 가질 수 있다.
  • 각각의 Component는 Awake, Start, Update, LateUpdate를 갖는데 초반 초기화나 갱신에 사용된다. Component를 갖는 GameObject에도 똑같은 멤버함수가 있는데 이는 각각의 Component의 초기화 갱신 함수를 호출한다.

결론 : Component를 통해서 Object생성 시 필요한 부품을 추가하고 불필요한 부품을 제거하는 방식으로 사용이 가능하다.

Scene

  • 인게임 - 로비 - 로그인과 같이 서로 겹치지 않는 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;
};


  • Scene 클래스는 Scene에서 관리한 Object를 추가, 제거하고 Object들의 초기화와 갱신을 관리한다.
  • SceneManager클래스는 사용할 Scene을 불러오고 현재 사용 중인 Scene의 갱신을 관리한다.
  • SceneManager클래스는 싱글톤 패턴을 사용하여 정적으로 선언하여 관리하기 때문에 어디서든 호출하여 사용이 가능하도록 설계되어 있다.
결론: Scene과 SceneManager를 통해 앞선 단계에서 만든 GameObject들 중 함께 사용하는 Object들을 한번에 관리할 수 있다.
profile
공부 기록용 블로그입니다

0개의 댓글