C ++에서 게임 엔진을 구성하는 방법은 무엇입니까? 상속을 사용하는 것이 좋은 생각입니까?


11

저는 게임 개발과 프로그래밍 모두에서 초보자입니다.

게임 엔진을 구축 할 때 몇 가지 원칙을 배우려고합니다.
간단한 게임을 만들고 싶습니다. 게임 엔진을 구현하려는 시점에 있습니다.

그래서 나는 내 게임 엔진이 이것을 제어해야한다고 생각했다.

- Moving the objects in the scene
- Checking the collisions
- Adjusting movements based on collisions
- Passing the polygons to the rendering engine

나는 다음과 같이 내 물건을 디자인했다.

class GlObject{
private:
    idEnum ObjId;
    //other identifiers
public:
    void move_obj(); //the movements are the same for all the objects (nextpos = pos + vel)
    void rotate_obj(); //rotations are the same for every objects too
    virtual Polygon generate_mesh() = 0; // the polygons are different
}

내 게임에는 비행기, 장애물, 플레이어, 총알의 4 가지 다른 개체가 있으며 다음과 같이 디자인했습니다.

class Player : public GlObject{ 
private:
    std::string name;
public:
    Player();
    Bullet fire() const; //this method is unique to the class player
    void generate_mesh();
}

이제 게임 엔진에서 충돌, 객체 이동 등을 확인할 수있는 일반 객체 목록을 원하지만 게임 엔진이 사용자 명령을 사용하여 플레이어를 제어하기를 원합니다 ...

이것이 좋은 생각입니까?

class GameEngine{
private:
    std::vector<GlObject*> objects; //an array containg all the object present
    Player* hPlayer; //hPlayer is to be read as human player, and is a pointer to hold the reference to an object inside the array
public:
    GameEngine();
    //other stuff
}

GameEngine 생성자는 다음과 같습니다 :

GameEngine::GameEngine(){
    hPlayer = new Player;
    objects.push_back(hPlayer);
}

포인터를 사용하고 있다는 사실 fire()은 Player 객체에 고유 한 것을 호출해야하기 때문 입니다.

그래서 제 질문은 : 좋은 생각입니까? 상속 사용이 여기에서 잘못 되었습니까?



게시 후 그들을 보았고 실제로 작곡은 좋은 생각입니다! 나는 항상 실제 c ++ 디자인 대신 클래스와 함께 c를 사용하는 것을 두려워합니다!
Pella86

상속보다 컴포지션을 사용해야하는 더 많은 이유가 있다고 생각합니다. 제 대답 은 그것이 제공하는 유연성 이점에 대한 몇 가지 예를 보여줍니다. 구현의 좋은 예를 보려면 내가 링크 한 기사를 확인하십시오.
코요테

답변:


12

'좋은'의 의미에 따라 다릅니다. 확실히 일을 끝낼 것입니다. 그것은 많은 단점과 단점이 있습니다. 엔진이 훨씬 복잡해질 때까지 찾을 수 없습니다. 주제에 대한 토론은 SO 에 대한 이 질문을 참조하십시오 .

어느 쪽이든 많은 의견이 있지만 엔진 코드가 아직 초기 단계이면 왜 나쁜지 설명하기가 어렵습니다.

일반적으로 Scott Meyers는 상속에 관해 말할 좋은 점이 있습니다. 아직 개발 단계에 있다면 계속하기 전에이 책 (Effective C ++)을 읽으십시오 . 환상적인 책이며 회사에서 일하는 모든 코더에게 요구되는 것입니다. 그러나 조언을 요약하자면, 만약 당신이 클래스를 작성하고 상속을 사용하는 것을 고려한다면, 클래스와 그 조상 사이의 관계가 'is a'관계라는 것을 분명히해야합니다. 즉, 모든 B는 A입니다. 상속을 A가 제공하는 기능에 대한 액세스 권한을 부여하는 쉬운 방법으로 사용하지 마십시오. 그렇게하면 심각한 아키텍처 문제가 발생할 수 있으며 다른 방법이 있습니다.

간단히 말해서; 어떤 크기의 엔진의 경우 객체가 상속이 작동하는 깔끔한 계층 구조에 거의 빠지지 않는다는 것을 빨리 알 수 있습니다. 적절할 때 사용하되 모든 것에 사용하는 함정에 빠지지 마십시오. 객체를 서로 관련시키는 다른 방법을 배우십시오.


상속에 대한 의견은 두 번째입니다. 내 개인적인 경험 법칙은 : 다른 방법으로해야하거나 어리석은 일 아니라면하지 마십시오 . 다시 말해 99 %의 경우 (적어도 :)의 상속은 나쁜 생각입니다. 또한 게임 로직 (회전 / 이동)과 렌더링 (generate_mesh ())을 분리하는 것이 좋습니다. 또 다른 것은 fire ()입니다. 액션 목록과 일반 액션 (my_action) 함수를 고려해보십시오. 이렇게하면 모든 클래스에 걸쳐 다양한 기능이 퍼져 나가지 않게됩니다. 두 경우 모두 문제가 발생할 때 단순하고 무자비하게 리팩터링하십시오.
길르앗

8

게임 오브젝트 (엔티티)의 로직 데이터 및 기능을 위해서는 컴포지션 오버 상속을 사용하는 것이 좋습니다. 좋은 시작은 구성 요소 기반 접근 방식입니다. 그것은 잘 설명되어 이 카우보이 프로그래밍 글 이 아키텍처가 구현 될 수있는 방법을 설명하고 어떻게 토니 호크 프랜차이즈 혜택.

또한 엔터티 시스템에 대한이 기사는 처음 읽을 때 영감을 받았습니다.

상속은 다형성을위한 훌륭한 도구입니다. 매우 간단한 프로젝트를 제외하고는 엔터티와 게임 논리를 구성하는 방법으로 사용하지 않아야합니다. 상속을 받으면 공통 부모로부터 상속받을 수없는 함수를 구현하기 위해 동일한 코드의 복사본을 복제하고 유지 관리해야합니다. 그리고 너무 많은 코드 복제를 피하기 위해 가장 일반적으로 사용되는 논리 및 데이터로 클래스를 오염시키기 시작할 것입니다.

구성 요소는 다양한 상황에서 매우 편리합니다. 당신은 그것들을 사용하여 훨씬 더 많은 것을 달성 할 수 있습니다 :

엔터티 유형에 대한 유연성 : 게임 개발 중에 일부 엔터티가 갑자기 진화하고 게임 디자이너가 개발자가이를 구현해야하는 결정을 내리는 경우가 있습니다. 코드를 복제하지 않고 기존 동작을 추가하려면 몇 단계 만 거치면됩니다. 컴포넌트 기반 시스템은 프로그래머가 아닌 사람이 더 많은 변경을 수행 할 수 있도록합니다. 예를 들어, 클래스로 표시되는 대신 각 유형의 엔티티는 유형을 구성하는 데 필요한 모든 구성 요소 이름 및 매개 변수를 포함하는 설명 파일로 표시 될 수 있습니다. 이를 통해 비 프로그래머는 게임을 다시 컴파일하지 않고도 변경 사항을 수행하고 테스트 할 수 있습니다. 설명 파일을 편집하기 만하면 각 엔티티 유형에서 사용하는 구성 요소를 추가, 제거 또는 변경할 수 있습니다.

특정 인스턴스 및 특정 시나리오에서의 유연성 : 플레이어가 무기 나 아이템을 장비 할 수 있어야하는 경우가 있습니다. 인벤토리 구성 요소를 플레이어에 추가 할 수 있습니다. 게임을 개발하는 동안 인벤토리를 가지기 위해 다른 개체가 필요합니다 (예 : 에니메이션). 그리고 어느 시점에서 시나리오에는 트리에 일종의 숨겨진 항목이 포함되어 있어야합니다. 구성 요소를 사용하면 추가 프로그래밍 노력없이 설계되지 않은 유형의 엔티티에도 인벤토리 구성 요소를 추가 할 수 있습니다.

런타임 유연성 : 구성 요소는 런타임시 엔터티의 동작을 변경하는 매우 효과적인 방법을 제공합니다. 런타임에 구성 요소를 추가 및 제거 할 수 있으므로 필요할 때 동작 및 속성을 만들거나 제거 할 수 있습니다. 또한 여러 유형의 데이터를 여러 GPU에서 개별적으로 병렬 계산할 수있는 그룹으로 분리 할 수도 있습니다.

시간 유연성 : 구성 요소를 사용하여 버전 간 호환성을 유지할 수 있습니다. 예를 들어 게임 릴리스간에 변경이있을 때 새로운 동작과 변경을 구현하는 새로운 구성 요소를 추가 할 수 있습니다 (항상 그런 것은 아님). 그런 다음 게임은로드 된 저장 파일, 피어 연결 또는 플레이어가 참여하는 서버에 따라 엔티티에 연결된 올바른 구성 요소를 인스턴스화합니다. 모든 플랫폼 (Steam, Mac App Store, iPhone, Android ...)에서 새 버전의 출시 날짜를 제어 할 수없는 시나리오에서 매우 유용합니다.

더 나은 통찰력을 얻으려면 [component-based][entity-system] 태그가 지정된 질문을 살펴보십시오 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.