2010-01-25 4 views
2

플랫폼 독립적 인 게임 개체가 플랫폼 관련 Application 개체 내에 포함되어있는 C++로 작성된 게임 엔진 디자인이 있습니다.플랫폼 독립적 설계에 플랫폼 특정 데이터 전달?

내가 해결하려고하는 문제는 응용 프로그램의 OS 관련 데이터를 게임에 전달해야하는 경우입니다. 이 경우 DirectX 용 Windows의 기본 HWND 또는 다른 플랫폼의 OpenGL 컨텍스트를 사용중인 렌더러에 전달해야합니다. 불행하게도 렌더러에 대한 제어권이 거의 없으므로 플랫폼 별 데이터를 기대할 수 있습니다.

렌더러를 응용 프로그램 측면에서 초기화 할 수 있다는 것을 알고 있지만 게임을 언제 어디에서 할 것인지 결정해야합니다. 일반적으로 응용 프로그램 측면을 제어하지만 게임 측면은 제어 할 수 없습니다. 게임 제작자는 다른 렌더러를 사용할 수도 있습니다.

나는 또한 문자열을 통해 데이터를 전달할 수있는 일종의 "속성 관리자"가 있다는 생각을 즐겼지만 그 생각은별로 좋아하지 않습니다.

아이디어가 있으십니까?

+0

게임 개체가 플랫폼 독립적 인 경우 플랫폼 종속 변수가 전달되어야하는 이유는 무엇입니까? –

+0

좋은 질문입니다! 간단히 말해, 우리는 Application 클래스를 제어 할 수 있지만 렌더러 나 게임 클래스를 제어 할 수는 없습니다. 이것은 지금 우리가 탐색하고있는 것입니다. – djcouchycouch

답변

3

컴파일 할 때 대상 플랫폼을 알아야한다는 것을 기억하십시오. 이 정보를 사용하여 올바른 플랫폼의 구성 요소를 '교체 할 수 있습니다'.

좋은 디자인에서 게임은 이 아니야은 플랫폼에 대한 정보가 필요합니다. 논리 및 관련 구성 요소 만 보유해야합니다.

'Engine'클래스는 플랫폼에 대해 걱정해야합니다.

게임 클래스는 플랫폼과 관련이없는 공용 함수를 통해 엔진 개체와 만 인터페이스해야합니다. 각 플랫폼에 대해 여러 버전의 Engine 객체를 가질 수 있으며 컴파일 할 때 사용할 객체를 선택할 수 있습니다.

예를 들어, 게임의 텍스처를 나타내는 텍스처 '엔진'클래스를 가질 수 있습니다. OS X 및 Windows를 지원하는 경우 컴파일하는 플랫폼에 따라 "Windows/Texture.h"또는 "OSX/Texture.h"를 포함하는 "Texture.h"를 가질 수 있습니다. 두 헤더 모두 동일한 인터페이스를 가진 Texture 클래스를 정의합니다 (즉, 둘 다 동일한 인수를 사용하여 동일한 공용 함수를 가짐). 그러나 구현은 플랫폼에 따라 다릅니다.

명확히하기 위해 게임은 응용 프로그램에 렌더러를 초기화하도록 알려야합니다. 게임 논리와 구현 세부 사항 사이에는 엄격한 경계가 있어야합니다. 렌더러는 게임 로직의 일부가 아닌 구현 세부 사항입니다. 게임 클래스는 시스템과 게임 세계에 대해서만 알 수 있어야합니다.

1

템플릿 패턴 (파생 클래스에서 구성 할 수있는 순수 가상 함수가있는 추상 기본 클래스 사용)을 참조하십시오. 좀 더 제어 (덜 객체 지향) 방식을 선호하는 경우

http://en.wikipedia.org/wiki/Template_pattern

는 게임 부분은 플랫폼 별 구성을 수행하기 위해, 응용 프로그램의 일부 구성 콜백 함수를 호출해야합니다.

예컨대 :

// in Application: 
static void SetWindowHandle(GameEngine const& p_game_engine, void* p_callback_data) 
{ 
    p_game_engine.DoSomethingWithHandle(static_cast<ApplicationManager*>(p_callback_data)->GetHWND()); 
} 

void Initialize() { 
    this->m_game_engine.Initialize(this, &Application::SetWindowHandle); 
} 

// ... 
// in Game Engine: 
// ... 

typedef void (*TSetWindowsHandleCallback)(GameEngine const*, void*); 

void* m_application_data; 
TSetWindowsHandleCallback m_windows_handle_callback; 

void Initialize(void *p_application_data, TSetWindowsHandleCallback p_callback) 
{ 
    this->m_application_data = p_application_data; 
    this->m_windows_handle_callback = p_callback; 
} 

void SetWindowsHandle() 
{ 
    this->m_windows_handle_callback(*this, m_application_data); 
} 
+0

+1하지만 dauric의 접근법을 선호합니다. 파생 클래스를 사용하면 하나 이상의 플랫폼 별 동작을 캡슐화 할 수 있기 때문입니다. 효과적으로, 기본 클래스의 각 공용 메소드 == "구성 가능한 콜백 함수". –

1

어떻게 얻는 SystemContext 클래스는 전달에 대해? 당신은 Win32Context, LinuxContext 등을 가질 것이다. OGRE가 그것을 처리하는 방식이다 (RenderContext의 경우).

렌더러 클래스는 SystemContext 포인터를 사용합니다.

내부적으로 DirectXRenderer (렌더러의 자손)가 Win32Context에 대한 포인터를 dynamic_cast (한 번)하고 플랫폼 관련 데이터를 모두 추출합니다.

0

내가 좋아하는 것은 공통 데이터 멤버가있는 모든 구현에서 기본 클래스를 공유하는 것입니다. 그런 다음 기본 클래스 자체에 포함 된 플랫폼 관련 정보가있는 기본 클래스가 있습니다. 이를 위해서는 특정 디렉토리 구조가 필요합니다. 예를 들면 다음과 같습니다.

code 
    renderer 
    context.h 
    platforms 
    win32 
     renderer 
     context_native.h 
    osx 
     renderer 
     context_native.h 

code/renderer/context.h 
class RenderContextBase { /* shared members */ }; 
#include "renderer/context_native.h" 

code/platform/win32/renderer/context_native.h 
class RenderContext : public RenderContextBase { /*win32 specific */ }; 

code/platform/osx/renderer/context_native.h 
class RenderContext : public RenderContextBase { /*osx specific */ }; 

컴파일러를 사용하면 "플랫폼에 따라 적절한 디렉토리"를 추가하기 만하면됩니다. 예를 들어, win32에서는 "code/platform/win32"를 추가 디렉토리로 추가합니다. 렌더러/renderer_native.h를 포함하면 "기본"위치에서 해당 렌더러가 발견되지 않으며 추가 디렉토리를 사용하려고 시도합니다.

코드의 어느 곳에서나 RenderContext는 기본 구현입니다. 당신은 실제로 1 개의 구현을 가지고 있기 때문에 기본 클래스와 네이티브 클래스에 대한 포인터를 가질 필요가 없습니다. 이렇게하면 주어진 플랫폼을 실제로 구현할 때 기본 가상 함수를 사용하지 않아도됩니다.

관련 문제