[DirectX] 여러 개의 Script


오브젝트가 여러개의 Script를 가질 수 있도록 구성해보자.

GameObject


기존의 게임오브젝트는 컴포넌트를 배열을 잡았다.

그리고 스크립트 또한 컴포넌트의 구성 중 하나였었다.

그러다보니 게임오브젝트 하나당 스크립트 하나만 가질 수 있었다.

스크립트도 컴포넌트의 구성원 중 하나로 남기면서 여러개를 가질 수 있도록

스크립트를 담을 벡터를 새로 구성할 것이다.

// CGameObject.h 중에서

vector<Script*> m_vecScript;


CGameObject 클래스의 변화


// 헤더 파일

#pragma once
#include "CEntity.h"


class CComponent;
class CTransform;
class CMeshRender;
class CCamera;
class CRenderComponent;
class CScript;

class CGameObject :
    public CEntity
{
private:
    CComponent*             m_arrCom[(UINT)COMPONENT_TYPE::END];
    CRenderComponent*       m_RenderCom;
    vector<CScript*>        m_vecScript;

    CGameObject*            m_Parent;
    vector<CGameObject*>    m_vecChild;

    int                     m_iLayerIdx;


public:
    void begin();       // 레벨이 시작될 때 호출 or 시작 된 레벨에 합류할 때
    void tick();        
    void finaltick();
    void render();


public:
    void AddComponent(CComponent* _Component);
    void AddChild(CGameObject* _Object);

    CGameObject* GetParent() const { return m_Parent; }

    CTransform* Transform() const { return (CTransform*)m_arrCom[(UINT)COMPONENT_TYPE::TRANSFORM]; }
    CMeshRender* MeshRender() const { return (CMeshRender*)m_arrCom[(UINT)COMPONENT_TYPE::MESHRENDER]; }
    CCamera* Camera() const { return (CCamera*)m_arrCom[(UINT)COMPONENT_TYPE::CAMERA]; }
    CRenderComponent* GetRenderComponent() const {  return m_RenderCom; }


    CLONE(CGameObject)    
public:
    CGameObject();
    ~CGameObject();

    friend class CLayer;
};
// cpp 파일

void CGameObject::begin()
{
	for (UINT i = 0; i < (UINT)COMPONENT_TYPE::END; ++i)
	{
		if (nullptr != m_arrCom[i])
			m_arrCom[i]->begin();
	}

	for (size_t i = 0; i < m_vecScript.size(); ++i)
	{
		m_vecScript[i]->begin();
	}

	for (size_t i = 0; i < m_vecChild.size(); ++i)
	{
		m_vecChild[i]->begin();
	}
}

void CGameObject::AddComponent(CComponent* _Component)
{
	_Component->m_pOwner = this;

	// 컴포넌트가 스크립트인 경우
	if (COMPONENT_TYPE::SCRIPT == _Component->GetType())
	{
		m_vecScript.push_back((CScript*)_Component);
	}

	// 스크립트를 제외한 일반 컴포넌트인 경우
	else
	{		
		// 이미 보유하고 있는 컴포넌트인 경우
		assert(!m_arrCom[(UINT)_Component->GetType()]);

		m_arrCom[(UINT)_Component->GetType()] = _Component;

		// RenderComponent 확인
		if (COMPONENT_TYPE::MESHRENDER <= _Component->GetType()
			&& _Component->GetType() <= COMPONENT_TYPE::DECAL)
		{
			assert(!m_RenderCom);
			m_RenderCom = (CRenderComponent*)_Component;
		}
	}
}

AddComponent 함수에서 스크립트 컴포넌트의 경우에는 별도의 벡터에 넣어줄 수 있도록 코드를 재구성한다.

컴포넌트가 스크립트라면 m_vecScript 벡터에 push_back을 해준다.

단, Component를 상속받은 Script 클래스 포인터로 다운캐스팅을 해준다.

그리고 tick()함수에서 스크립트의 tick함수를 실행할 수 있도록 for문을 추가해준다.

또한 레벨이 시작되는 순간을 위한 begin함수를 추가해준다.

그리고 CLevel, CLayer, CComponent에도 begin과 관련된 코드를 추가해준다.

CLevel


// cpp 파일 중에서
void CLevel::begin()
{
	for (UINT i = 0; i < MAX_LAYER; ++i)
	{
		m_arrLayer[i]->begin();
	}
}


CLayer


// cpp 파일 중에서
void CLayer::begin()
{
	for (size_t i = 0; i < m_vecParentObj.size(); ++i)
	{
		m_vecParentObj[i]->begin();
	}
}

CComponent


// 헤더파일 중에서
public:
    virtual void begin() {}


begin함수의 용도


레벨이 시작되는 순간이나 레벨에 합류할 때 호출되는 함수이다.

나중에 툴까지 연동되어있는 상태라면 툴을 실행할 때에는 레벨이 멈춰있을 것이다.

레벨이 시작될 때 실행할 초기작업을 여기서 하는 것이다.

그리고 한정된 개수만큼 미리 생성해두었다가 현재 진행 중인 레벨에 합류시킬 때에도 begin함수가 사용된다.

생성자랑 헷갈리지 말자.

이를 사용하면 new와 delete의 비용을 아끼고, 이 과정에서 발생하는 지연을 막을 수 있다.


© 2022.07. by Wookey_Kim

Powered by Hydejack v7.5.2