2017-02-08 3 views
2

그래서 첫 번째 게임 엔진을 개발 중이며 벽에 부딪 혔습니다. 현재 일부 시스템 관리자 클래스 (graphisManager, PhysicsManager 등) 내의 구성 요소 개체에 대한 포인터를 보유 할 구성 요소 포인터 벡터가있는 Entity 기본 클래스가 있습니다. 여기에 (주 문제에 초점을 벗었) 나의 현재의 엔터티 헤더입니다 :게임 엔진에서 구성 요소를 가장 잘 관리하는 방법은 무엇입니까?

Entity.h

class Component; 

namespace BlazeGameWorld 
{ 
    class Entity 
    { 
    public: 
     BlazeFramework::Math::Vector2D position; 

    protected: 
     Vector<Component*> components; 

     static BlazeGraphics::GraphicsManager graphicsManager; 
     static BlazePhysics::PhysicsManager physicsManager; 
     static BlazeInput::InputManager inputManager; 
     //....other managers 

    private: 

     /////////////////////////////////////////////////////////////////////// 

    public: 
     Entity(); 
     ~Entity(); 

     virtual bool Initialize(); 
     virtual bool Shutdown(); 

     virtual void Update() = 0; 

     void AddComponent(Component* p_component); 

     //Part of the broadcast messaging system for components to be able 
     //to talk to one another in a decoupled way. 
     void SendMessage(uint messageID); 

    protected: 

    private: 
    }; 
} 

당신이 볼 수 있듯이이 아이디어는 실제에 대한 포인터를 관리 정적의 SystemManager 클래스를 가지고있다 힙의 구성 요소. 여기에 잠재적 인 PhysicsManager 클래스에 대한 대략적인 헤더이다 (그리고 다른 관리자 클래스와 비슷) :

PhysicsManager.h

class PhysicsComponent; 

namespace BlazePhysics 
{ 
    class PhysicsManager 
    { 
    public: 

    protected: 
     int numPhysicsComponents; 
    private: 
     Vector<PhysicsComponent*> physicsComponents; 

     ///////////////////////////////////////////////////////////// 

    public: 
     PhysicsManager(); 
     ~PhysicsManager(); 

     bool Initialize(); 
     bool Shutdown(); 

     void Update(); 

     template <typename PhysicsComponentType> 
     PhysicsComponentType* CreatePhysicsComponent(); 

    private: 
    }; 

    //template definitions 
    template <typename PhysicsComponentType> 
    PhysicsComponentType* PhysicsManager::CreatePhysicsComponent() 
    { 
     PhysicsComponentType* physicsComponent = new PhysicsComponentType 
     physicsComponents.push_back(physicsComponent); 

     return physicsComponents.at(numPhysicsComponents++); 
    } 
} 

그래서 나는 PhysicsManger 벡터의 모든 다른 physicsComponent 포인터를 저장할 수 있습니다 (포인터로 CollisionComponents, PositionComponents 등). 문제는 특정 물리 구성 요소에 특정한 메서드를 호출하고 싶습니다. 컴파일 할 수 없습니다. 예를 들어 PhysicsManager의 업데이트 루프에서 collisionComponent의 CheckCollision() 메서드를 업데이트하기를 원한다면 컴파일러가 CollisionComponent를 컴파일 타임에 알 수 없기 때문에 각 루프에 대해 말할 수 없습니다. physicsComponents.at(i).CheckCollision 어쩌면 배열의 구성 요소 유형을 먼저 추론 한 다음 CollisionComponent가 CheckCollision 메서드를 호출하는 것과 일치하는지 확인하는 방법이 있습니까? 아니면 이것이 좀 어색해 보이기 때문에 이것을 구현하는 것이 더 낫습니까?

+0

여기에 컴포넌트 기반 엔진이 있으면 좋겠지 만, 당신과 비슷한 구조의 첫 번째 게임 엔진에 대해서도 작업하고 있습니다. 그러나 각 시스템에 게임 엔진 참조를 전달하여 참조를 사용하여 다른 시스템에 액세스 할 수 있습니다. 나는 그것이 좋은지는 모르지만 적어도 그것이 효과가있다. XD –

+0

당신이 듣고있어 기쁘게 생각합니다. 다른 구성 요소 형식의 배열 배열을 구현하는 몇 가지 솔루션을 찾고 있어요.그런 식으로 뭔가를 구현하는 방법을 알아낼 수 있다면 나 스스로 해결책을 게시 할 수 있습니다. – Jason

답변

2

엔티티는 시스템에 대해 알지 않아야하며 구성 요소 모음 일뿐입니다. 그렇지 않으면 다른 엔진 시스템을 도입하는 과정에서 엔티티 클래스도 변경해야합니다. ECS는 ECS의 모든 목적을 무시합니다.

시스템 역시 구성 요소를 관리해서는 안됩니다. 하나의 시스템은 여러 구성 요소를 사용할 수 있으며 많은 시스템이 사용할 수 있습니다. 위치/충돌 지오메트리 구성 요소.

그래서, 내 의견으로는 모든 처리가 시스템 내에서 수행되는 동안

  • 구성 요소, 이상적으로, 간단한 데이터 전용 클래스해야한다.
  • 엔터티는 구성 요소를 추가 및 제거하는 방법과 특정 구성 요소가 있는지 여부를 알려주는 을 제공해야합니다.
  • 어떤 종류의 엔티티 관리자는 시스템이 캐시에 접근 할 수 있도록 캐시 친숙한 방법으로 구성 요소를 저장해야하며 시스템에 특정 구성 요소/태그 집합을 가진 엔티티 목록을 제공 할 수 있어야합니다.

이 방법은 일부 엔터티에 스크립트 동작을 추가하려는 경우 ScriptComponentScriptingSystem을 추가하는 것입니다. 기존 코드는 모두 변경하지 않아도됩니다.

This question에는이 주제에 대해 많은 유용한 자료가 있습니다.

+0

좋아요, 그렇다면 Entity Manger 클래스가 게임에서 엔티티의 모든 구성 요소를 다루는 것에 대해 책임이 있다고 말하면 되나요? 그리고 모든 시스템 (graphicsSystem, PhysicsSystem, ScriptingSystem)은 컴포넌트를 사용하고 교환 할 수 있습니다. – Jason

+0

@ Jason 더 설명적인 것으로 불릴 수도 있지만 (아마도 더 좋을 수도 있음) 시스템 자체는 아닙니다. 시스템은 일반적으로 구성 요소를 추가/제거하지 않을 것이므로 자신의 세계/장면이됩니다. ECS와 일부 오픈 소스 구현에 관한 많은 논문들이있다. 확실히 확인해야한다. – w1ck3dg0ph3r

+0

@Jason 또한 Vittorio Romeo의 CppCon15에서 [ECS 구현에 대한 좋은 토론] (https://www.youtube.com/watch?v=NTWSeQtHZ9M)이있었습니다. – w1ck3dg0ph3r