이번에 팀에서 GameBryo R&D를 진행 중입니다. 차기작을 위한 준비죠. 수 개월 내에 간단한 프로토타입을 내놓기로 했는데, 일단 구조 설계 중입니다. 그래서 이런저런 토의를 하면서 프레임워크 구조 잡는 것 부터 하고 있습니다. 저는 스터디용으로 제작하던 엔진도 있고해서, 지금 사용 중인 방식을 의견으로 내놓았죠. ( 아직 딱히 이렇게 하자 정해진 상태는 없음 )

void CFramework::Run( HWND hWnd )
{
	// 핸들이 없으면 종료
	if( hWnd == NULL )
		return;

	m_hWnd = hWnd;

	// 커널 생성
	if( CreateKernel() )
	{
		if( OnInitialize() )
		{
			// 루프에 돌임
			ProcLoop();
		}
	}

	Cleanup();
}

단순합니다. 생성된 윈도우 핸들을 받아 커널을 생성하고, 게임 실행에 필요한 초기화를 실행 하는게 전부입니다. 여기서 커널은 엔진 커널을 뜻하며, 커널 생성이 완료되면 엔진이 준비 된 상태가 되는 거죠. 커널 생성시 실행 되는 부분은 그래픽 관련 작업을 담당하는 그래픽코어와 입력처리 담당을 하는 그래픽코어, 씬 부분을 담당하는 씬 코어등을 생성하는 것이 주된 일입니다.

int CFramework::CreateKernel()
{
	// 커널 생성
	m_pKernel = new ae_CKernel(m_hWnd);

	// 코어 생성
	m_pInputCore = (ae_CInputCore*)m_pKernel->CreateCore( ae_CKernel::CORE_INPUT );
	if( m_pInputCore == NULL )
	{
		m_pKernel->WriteLog(L"인풋 코어 생성 실패!!!");
		return 0;
	}
	m_pResourceCore = (ae_CResourceCore*)m_pKernel->CreateCore( ae_CKernel::CORE_RESOURCE );
	if( m_pResourceCore == NULL )
	{
		m_pKernel->WriteLog(L"리소스 코어 생성 실패!!!");
		return 0;
	}
	m_pSceneCore = (ae_CSceneCore*)m_pKernel->CreateCore( ae_CKernel::CORE_SCENE );
	if( m_pSceneCore == NULL )
	{
		m_pKernel->WriteLog(L"씬 코어 생성 실패!!!");
		return 0;
	}

	return 1;
}

그리고 각 코어 생성시에는 각자 역할에 맞는 초기화 작업을 수행하죠. 그래픽 코어라면 그래픽 디바이스 생성 및 초기화등을 수행하고, 인풋 코어라면 키 입력 시스템 초기화를 하듯이 말이죠. 코어 생성은 팩토리 패턴을 적용하여, 커널에서 모든 코어를 관리 할수 있도록 작성 했습니다.

ae_CCoreBase* CKernel::CreateCore( eCoreType eType )
{
	// 해당 코어가 이미 생성 되어있는지 검사. 있으면 날려주자~
	CCoreBase* pFindCore = GetCore( eType );
	if( pFindCore != NULL )
		return pFindCore;

	switch( eType )
	{
	case CORE_SCENE:
		{
			CSceneCore* pCore = new CSceneCore();
			m_CoreList.insert( make_pair( CORE_SCENE, pCore ) );
			if( pCore->InitializeCore( this ) )
				return pCore;
			return NULL;
		}
	case CORE_RESOURCE:
		{
			CResourceCore* pCore = new CResourceCore();
			m_CoreList.insert( make_pair( CORE_RESOURCE, pCore ) );
			if( pCore->InitializeCore( this ) )
				return pCore;
			return NULL;
		}
	case CORE_INPUT:
		{
			CInputCore* pCore = new CInputCore();
			m_CoreList.insert( make_pair( CORE_INPUT, pCore ) );
			if( pCore->InitializeCore( this ) )
				return pCore;
			return NULL;
		}
	default:
		return NULL;
	}

	return NULL;
}

심플하죠.
다른 분들은 어떤식으로 작성하는지 궁금하네요. 나는 이런식으로 실행한다. 하는 의견 있으면 팍팍~ 남겨주세요.
  1. 행인.. 2010.04.18 23:49

    지나가다.. 글 남겨 봅니다.. ^^;
    커널에서 팩토리를 써서 코어들을 생성하는건 참 갠찮은거 같네요..
    하지만 여전히 커널이 코어들을 알고 있다는게 추후 확장이 용이 하지 못한 결과를 나을것 같은 생각이 듭니다.
    각 코어 생성에 좀더 확장성을 염두해서 작성하는게 좋을것 같은 생각이 드네요.
    예를 들어.. 입력 코어라면 툴에서 쓰는 입력 방식과 게임에서 쓰는 입력 방익이 다를수도 있지요.
    리소스도 역시나 다를수 있습니다.
    프레임워크는 게임 컨텐츠 , 각종 툴.. 이 될 가능성이 많다고 보여지는데요..
    처음 프레임 워크에서 커널을 생성할때 코어타입별로 팩토리를 넘겨주는 것은 어떨까요?
    예를 들면.. 툴이라면.

    pKernel->registFactory(CORE_INPUT, new ToolInputCoreFactory);
    pKernel->registFactory(CORE_RESOURCE, new ToolResourceCoreFactory);

    이런 식으로 말이죠. 커널은 간단히 팩토리만 관리하면 되겠네요.
    커널은 코어를 생성할때 따로 객체를 생성할 필요가 없을거구요.. 팩토리에게 맞기면 되니까요.
    Core* CreateCore(coreType)
    {
    pFactory = mapFactory.find(coreType);
    return pFactory->createInstance();
    }

    객체 레이어간 상호 참조는 되도록 피하는게 좋구요.. 객체 순환 참조가 되면 그 순간 넘 꼬여버려서..
    예를 들어 A -> B 로 볼수 있다고 하면 B -> A 로는 보면 안되겠죠?

    멋진 엔진 만드시기 바랍니다.. ^^;

  2. BlogIcon usrobj 2011.08.23 20:14

    엔진을 직접 제작하신다니! 멋지시네요... 난 언제쯤 이런거 하게될까...

+ Recent posts