Component란?
Unity로 예를 들자면 Cube Object아래 Transform, Cube (Mesh Filter), Mesh Renderer Component가 붙어있고 Unity 상에서 Component를 추가/삭제를 할 수 있다.
즉, Object의 기능 집합을 Component라 할 수 있다.
<< 아래가 하나하나의 Component(부품) 이다 >>
< Cube Object > ----- < Transform >
|
---- < Mesh >
|
---- ...
Component 클래스
#pragma once
enum class COMPONENT_TYPE : uint8
{
// Component의 기능 정의
TRANSFORM,
MESH_RENDERER,
// ... (기능이 추가되면 여기에 넣자)
MONO_BEHAVIOUR,
END,
};
enum
{
FIXED_COMPONENT_COUNT = static_cast<uint8>(COMPONENT_TYPE::END) - 1
};
class GameObject;
class Transform;
class Component
{
public:
Component(COMPONENT_TYPE type);
virtual ~Component();
public:
virtual void Awake() { }
virtual void Start() { }
virtual void Update() { }
virtual void LateUpdate() { }
public:
COMPONENT_TYPE GetType() { return _type; }
bool IsValid() { return _gameObject.expired() == false; }
shared_ptr<GameObject> GetGameObject();
shared_ptr<Transform> GetTransform();
private:
friend class GameObject;
void SetGameObject(shared_ptr<GameObject> gameObject) { _gameObject = gameObject; }
protected:
COMPONENT_TYPE _type;
// weak_ptr로 선언한 이유?
// GameObject내에서도 Component를 알고있을 예정 순환참조를 방지하기 위해서
weak_ptr<GameObject> _gameObject;
};
#include "pch.h"
#include "Component.h"
#include "GameObject.h"
Component::Component(COMPONENT_TYPE type) : _type(type)
{
}
Component::~Component()
{
}
shared_ptr<GameObject> Component::GetGameObject()
{
return _gameObject.lock();
}
shared_ptr<Transform> Component::GetTransform()
{
return _gameObject.lock()->GetTransform();
}
GameObject 클래스
#pragma once
#include "Component.h"
class Transform;
class MeshRenderer;
class MonoBehaviour;
// enable_shared_from_this<GameObject>는 shared_from_this()를 위해 선언
class GameObject : public enable_shared_from_this<GameObject>
{
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:
// 기본적으로 생성하는 Component는 array로 관리(딱 하나만 존재하는 Component)
array<shared_ptr<Component>, FIXED_COMPONENT_COUNT> _components;
// 사용자가 만드는 MonoBehavior는 vector로 관리
vector<shared_ptr<MonoBehaviour>> _scripts;
};
#include "pch.h"
#include "GameObject.h"
#include "Transform.h"
#include "MeshRenderer.h"
#include "MonoBehaviour.h"
GameObject::GameObject()
{
}
GameObject::~GameObject()
{
}
void GameObject::Init()
{
// 무조건 Transform은 갖도록 만들었음.
AddComponent(make_shared<Transform>());
}
void GameObject::Awake()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Awake();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Awake();
}
}
void GameObject::Start()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Start();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Start();
}
}
void GameObject::Update()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Update();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Update();
}
}
void GameObject::LateUpdate()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->LateUpdate();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->LateUpdate();
}
}
shared_ptr<Transform> GameObject::GetTransform()
{
uint8 index = static_cast<uint8>(COMPONENT_TYPE::TRANSFORM);
return static_pointer_cast<Transform>(_components[index]);
}
void GameObject::AddComponent(shared_ptr<Component> component)
{
component->SetGameObject(shared_from_this());
// shared_from_this() : shared_ptr로 내 자신을 보내기 위해 호출함.
// 절대 네버 make_shared<GameObject>() 이걸로 보내면 안됨
uint8 index = static_cast<uint8>(component->GetType());
if (index < FIXED_COMPONENT_COUNT)
{
// 커스텀화 된 Component는 배열에 넣고
_components[index] = component;
}
else
{
// 새롭게 생성된 Component는 스크립트에 관리한다.
_scripts.push_back(dynamic_pointer_cast<MonoBehaviour>(component));
// dynamic_pointer_cast : dynamic_cast의 포인터 버전이라 생각
}
}
대표 예제 Component : MonoBehavior
아직까진 기능은 없다.
#pragma once
#include "Component.h"
class MonoBehaviour : public Component
{
public:
MonoBehaviour();
virtual ~MonoBehaviour();
public:
};
#include "pch.h"
#include "MonoBehaviour.h"
MonoBehaviour::MonoBehaviour() : Component(COMPONENT_TYPE::MONO_BEHAVIOUR)
{
}
MonoBehaviour::~MonoBehaviour()
{
}
MeshRenderer 클래스
#pragma once
#include "Component.h"
class Mesh;
class Material;
class MeshRenderer : public Component
{
public:
MeshRenderer();
virtual ~MeshRenderer();
void SetMesh(shared_ptr<Mesh> mesh) { _mesh = mesh; }
void SetMaterial(shared_ptr<Material> material) { _material = material; }
virtual void Update() override { Render(); }
void Render();
private:
shared_ptr<Mesh> _mesh;
shared_ptr<Material> _material;
};
#include "pch.h"
#include "MeshRenderer.h"
#include "Mesh.h"
#include "Material.h"
MeshRenderer::MeshRenderer() : Component(COMPONENT_TYPE::MESH_RENDERER)
{
}
MeshRenderer::~MeshRenderer()
{
}
void MeshRenderer::Render()
{
//GetTransform()->Update();
_material->Update();
_mesh->Render();
}
Transform 클래스
#pragma once
#include "Component.h"
struct TransformMatrix
{
Vec4 offset;
};
class Transform : public Component
{
public:
Transform();
virtual ~Transform();
// TODO : 온갖 Parent/Child 관계
private:
// TODO : World 위치 관련
};
#include "pch.h"
#include "Transform.h"
Transform::Transform() : Component(COMPONENT_TYPE::TRANSFORM)
{
}
Transform::~Transform()
{
}
사용해 보기
void Game::Init(const WindowInfo& info)
{
GEngine->Init(info);
vector<Vertex> vec(4);
vec[0].pos = Vec3(-0.5f, 0.5f, 0.5f);
vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
vec[0].uv = Vec2(0.f, 0.f);
vec[1].pos = Vec3(0.5f, 0.5f, 0.5f);
vec[1].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[1].uv = Vec2(1.f, 0.f);
vec[2].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
vec[2].uv = Vec2(1.f, 1.f);
vec[3].pos = Vec3(-0.5f, -0.5f, 0.5f);
vec[3].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[3].uv = Vec2(0.f, 1.f);
vector<uint32> indexVec;
{
indexVec.push_back(0);
indexVec.push_back(1);
indexVec.push_back(2);
}
{
indexVec.push_back(0);
indexVec.push_back(2);
indexVec.push_back(3);
}
// 오늘 테스트
gameObject->Init(); // Transform
/*
void GameObject::Init()
{
AddComponent(make_shared<Transform>());
}
*/
shared_ptr<MeshRenderer> meshRenderer = make_shared<MeshRenderer>();
{
shared_ptr<Mesh> mesh = make_shared<Mesh>();
mesh->Init(vec, indexVec);
meshRenderer->SetMesh(mesh);
}
{
shared_ptr<Shader> shader = make_shared<Shader>();
shared_ptr<Texture> texture = make_shared<Texture>();
shader->Init(L"..\\Resources\\Shader\\default.hlsli");
texture->Init(L"..\\Resources\\Texture\\veigar.jpg");
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(shader);
material->SetFloat(0, 0.3f);
material->SetFloat(1, 0.4f);
material->SetFloat(2, 0.3f);
material->SetTexture(0, texture);
meshRenderer->SetMaterial(material);
}
gameObject->AddComponent(meshRenderer);
GEngine->GetCmdQueue()->WaitSync();
}
MeshRenderer ------ Mesh(정점정보)
|
------ Material -------- Shader(쉐이더)
|
-------- Texture(텍스쳐)