게임 구성 요소, 게임 관리자 및 개체 속성


15

구성 요소 기반 엔터티 디자인에 대해 머리를 숙이고 있습니다.

첫 번째 단계는 객체에 추가 할 수있는 다양한 구성 요소를 만드는 것이 었습니다. 모든 구성 요소 유형마다 관리자가있어 모든 구성 요소의 업데이트 기능을 호출하여 필요에 따라 키보드 상태 등을 전달합니다.

다음으로 객체를 제거하고 각 구성 요소에 ID가 있습니다. 따라서 개체는 동일한 ID를 가진 구성 요소로 정의됩니다.

이제 모든 구성 요소에 대한 관리자가 필요하지 않다고 생각합니다 (예 SizeComponent: Size속성 이있는 ). 결과적으로 SizeComponent업데이트 방법이 없으며 관리자의 업데이트 방법은 아무 것도 수행하지 않습니다.

내 첫 번째 생각은 ObjectProperty구성 요소의 속성으로 사용하는 대신 구성 요소가 쿼리 할 수 있는 클래스를 갖는 것입니다. 따라서 객체는 ObjectProperty및 의 수를 갖습니다 ObjectComponent. 구성 요소에는 개체에 속성을 쿼리하는 업데이트 논리가 있습니다. 관리자는 구성 요소의 업데이트 메소드 호출을 관리합니다.

이것은 나에게 과도하게 엔지니어링 된 것처럼 보이지만 구성 요소를 제거 할 수 있다고 생각하지 않습니다. 관리자가 어떤 객체가 어떤 구성 요소 논리를 실행 해야하는지 알 수있는 방법이 필요하기 때문입니다 (그렇지 않으면 나는 단지 구성 요소를 제거합니다) 업데이트 로직을 관리자에게 전달하십시오).

  1. 이 (데 ObjectProperty, ObjectComponent그리고 ComponentManager오버 엔지니어링 클래스)?
  2. 좋은 대안은 무엇입니까?

1
컴포넌트 모델을 배우려고 노력하면 올바른 아이디어를 얻을 수 있지만,해야 할 일을 더 잘 이해해야합니다. 그렇게하는 유일한 방법은 게임을 사용하지 않고 [주로] 완성하는 것입니다. 나는 SizeComponent객체를 만드는 것이 과잉이라고 생각한다. 대부분의 객체는 크기가 있다고 가정 할 수있다. 이것은 컴포넌트 모델이 사용되는 렌더링, AI, 물리와 같은 것들이다. 크기는 항상 동일하게 작동하므로 해당 코드를 공유 할 수 있습니다.
조나단 디킨슨


@JonathanDickinson, @Den : 내 문제는 공통 속성을 어디에 저장해야하는지 생각합니다. 예를 들어 a RenderingComponent와 a 가 사용하는 위치로서의 객체 PhysicsComponent. 나는 재산을 어디에 둘 것인지에 대한 결정을 지나치게 생각하고 있습니까? 그냥 둘 중 하나를 고수하고 다른 속성에 필요한 속성이있는 구성 요소의 객체를 쿼리해야합니까?
George Duckett

내 이전의 의견과 그 뒤에있는 생각 과정은 구성 요소가 쿼리 할 수있는 속성 (또는 관련 속성 그룹)에 대한 별도의 클래스를 갖도록 유도합니다.
George Duckett

1
나는 그 아이디어를 정말 좋아합니다. 시도해 볼 가치가 있습니다. 각 개별 속성을 설명하는 객체를 갖는 것은 정말 비쌉니다. 당신은 PhysicalStateInstance( GravityPhysicsShared게임 당 하나 )와 함께 ( 개체 당 하나)를 시도 할 수 있습니다 ; 그러나 이것이 건축가의 행복감을 불러 일으키고 있다고 말하고 싶은 유혹에 빠져 있습니다. 키스.
Jonathan Dickinson

답변:


6

첫 번째 질문에 대한 간단한 대답은 그렇습니다. 설계를 지나치게 설계했습니다. '얼마나 세분화합니까?' 다음 단계가 수행되고 중앙 객체 (일반적으로 엔티티라고 함)가 제거 될 때 질문이 매우 일반적입니다.

크기를 자체적으로 정할 수있는 수준으로 개체를 세분화하면 디자인이 너무 멀리 떨어졌습니다. 자체적으로 데이터 값은 구성 요소가 아닙니다. 내장 된 데이터 유형이며 종종 속성을 호출하기 시작한 그대로 호출 할 수 있습니다. 속성은 구성 요소가 아니지만 구성 요소에 속성이 포함되어 있습니다.

다음은 컴포넌트 시스템에서 개발할 때 시도하고 따르는 몇 가지 지침입니다.

  • 숟가락이 없다.
    • 이것은 중앙 객체를 제거하기 위해 이미 수행 한 단계입니다. 이것은 당신이 가지고있는 모든 것이 컴포넌트이기 때문에 Entity 객체로 들어가는 것과 컴포넌트로 들어가는 것에 대한 전체 토론을 제거합니다.
  • 구성 요소는 구조가 아닙니다
    • 데이터를 포함하는 위치로 분류하면 더 이상 구성 요소가 아니며 데이터 구조 일뿐입니다.
    • 구성 요소에는 특정 방식으로 매우 구체적인 작업을 수행하는 데 필요한 모든 기능이 포함되어야합니다.
    • IRenderable 인터페이스는 게임의 모든 것을 시각적으로 표시하는 일반적인 솔루션을 제공합니다. CRenderableSprite 및 CRenderableModel은 각각 2D 및 3D로 렌더링 할 세부 사항을 제공하는 해당 인터페이스의 컴포넌트 구현입니다.
    • IUseable은 플레이어가 상호 작용할 수있는 인터페이스입니다. CUseableItem은 활성 총을 발사하거나 선택한 물약을 마시는 구성 요소이며, CUseableTrigger는 플레이어가 포탑에 뛰어 들거나 레버를 던져 도개교를 떨어 뜨릴 수 있습니다.

따라서 구성 요소가 지침이 아닌 지침으로 인해 SizeComponent가 너무 세분화되었습니다. 여기에는 데이터 만 포함되며 크기를 정의하는 요소는 달라질 수 있습니다. 예를 들어, 렌더링 컴포넌트에서 1d 스칼라 또는 2 / 3d 벡터 일 수 있습니다. 물리 구성 요소에서는 객체의 경계 볼륨이 될 수 있습니다. 재고 품목에서는 2D 그리드에서 차지하는 공간이 클 수 있습니다.

이론과 실용성 사이에 좋은 선을 그리십시오.

도움이 되었기를 바랍니다.


일부 플랫폼에서는 인터페이스에서 함수를 호출하는 것이 부모 클래스에서 호출하는 것보다 길다는 것을 잊지 마십시오 (응답에 인터페이스 및 클래스에 대한 언급이 포함되어 있기 때문에)
ADB

기억해 두어야 할 점이 있지만 언어에 구애받지 않고 일반적인 디자인 용어로 사용하려고했습니다.
제임스

"만약 당신이 데이터를 포함하는 곳으로 분류한다면 그것은 더 이상 구성 요소가 아니라 단지 데이터 구조 일뿐입니다." -- 왜? "구성 요소"는 데이터 구조를 의미 할 수있는 일반적인 단어입니다.
Paul Manta 2019 년

@PaulManta 네, 일반적인 용어이지만이 질문과 답변의 요점은 어디에서 선을 그릴 지입니다. 당신이 인용 한대로 내 대답은 엄지 손가락 규칙에 대한 제안입니다. 항상 그렇듯이 나는 이론이나 디자인 고려 사항이 개발의 원동력이되게하는 것을 결코 옹호하지 않는다.
James

1
@James 흥미로운 토론이었습니다. :) chat.stackexchange.com/rooms/2175 구성 요소가 다른 구성 요소에 관심이있는 부분을 너무 많이 알고 있다는 것이 가장 큰 문제입니다. 앞으로 논의를 계속하고 싶습니다.
Paul Manta

14

당신은 이미 대답을 받아 들였지만 여기에 CBS의 찌르기가 있습니다. 나는 일반적인 것을 발견 Component나는에 구성 요소를 분리 제안 GDC 2009에서 급진적 엔터테인먼트에 의해 기술 설계와 함께 갔다, 그래서 클래스는 몇 가지 한계를 가지고 AttributesBehaviors. ( " Margin Chady 게임 오브젝트 구성 요소 아키텍처 이론 및 실습 ")

디자인 결정 사항을 두 페이지로 설명합니다. 여기에 붙여 넣기에 너무 길어서 링크를 게시하겠습니다. 현재 렌더링 및 물리 구성 요소가 아닌 논리 구성 요소 만 다루지 만, 내가 시도한 작업에 대한 아이디어를 제공해야합니다.

http://www.pdf-archive.com/2012/01/08/entity-component-system/preview/page/1

다음은이 문서에서 발췌 한 내용입니다.

짧은 속성 및 동작

Attributes하나의 데이터 범주를 관리하고 범위에 제한이있는 모든 논리. 예를 들어, Health현재 값이 최대 값보다 크지 않도록하고 현재 값이 특정 위험 수준 아래로 떨어지면 다른 구성 요소에 알릴 수 있지만 더 복잡한 논리는 포함하지 않습니다. 또는 Attributes에 의존하지 않습니다 .AttributesBehaviors

Behaviors기업이 게임 이벤트에 반응하는 방식을 제어하고 결정을 내리며 Attributes필요에 따라 가치를 변경 합니다. Behaviors일부 에 의존 Attributes하지만 서로 직접 상호 작용할 수는 없습니다. 서로간에 Attributes’값이 변경되는 방식 Behaviors과 전송 된 이벤트 에만 반응합니다 .


편집 : 다음 은 구성 요소가 서로 통신하는 방법을 보여주는 관계 다이어그램입니다.

속성과 동작 간의 통신 다이어그램

구현 세부 사항 : 엔티티 레벨 EventManager은 사용 된 경우에만 작성됩니다. Entity클래스는 단지에 대한 포인터를 저장하는 EventManager경우에만 일부 구성 요소의 요청을 초기화된다.


편집 : 다른 질문에 나는 이것에 대해 비슷한 대답을했습니다. 시스템에 대한 더 나은 설명을 위해 여기에서 찾을 수 있습니다.
/gamedev//a/23759/6188


2

실제로 필요한 속성과 필요한 위치에 따라 다릅니다. 보유한 메모리 양과 사용할 처리 능력 / 유형 나는 다음을 보려고 노력했다.

  • 여러 구성 요소에서 사용하지만 하나만 수정 한 속성은 해당 구성 요소에 저장됩니다. 모양은 AI 시스템, 물리 시스템 및 렌더링 시스템이 기본 모양에 액세스해야하는 게임에서 좋은 예입니다. 이는 무거운 속성이며 가능한 경우 한 곳에만 있어야합니다.
  • 위치와 같은 속성을 복제해야하는 경우가 있습니다. 예를 들어 여러 시스템을 병렬로 실행하는 경우 시스템 간 엿보기를 피하고 위치를 동기화합니다 (마스터 구성 요소에서 복사 또는 델타를 통해 동기화하거나 필요한 경우 충돌 패스와 동기화).
  • 컨트롤 또는 AI "의도"에서 비롯된 속성은 외부에서 보지 않고도 다른 시스템에 적용 할 수 있으므로 전용 시스템에 저장할 수 있습니다.
  • 단순한 특성은 복잡해질 수 있습니다. 많은 데이터 (포지션, 방향, 프레임 델타, 총 델타 전류 이동, 현재 프레임 및 이전 프레임의 델타 이동, 회전 ...)를 공유해야하는 경우 위치에 전용 시스템이 필요할 수 있습니다. 이 경우 시스템과 함께 이동하여 전용 구성 요소의 최신 데이터에 액세스해야하며 누산기 (델타)를 통해 데이터를 변경해야 할 수도 있습니다.
  • 때로는 속성을 원시 배열 (double *)에 저장할 수 있으며 구성 요소에 다른 속성을 보유하는 배열에 대한 포인터가있을뿐입니다. 가장 확실한 예는 대규모 병렬 계산 (CUDA, OpenCL)이 필요한 경우입니다. 따라서 포인터를 올바르게 관리 할 수있는 하나의 시스템을 갖추면 도움이 될 수 있습니다.

이러한 원칙에는 한계가 있습니다. 물론 지오메트리를 렌더러로 푸시해야하지만 거기서 지오메트리를 검색하고 싶지는 않을 것입니다. 마스터 지오메트리는 변형이 발생하고 렌더러와 동기화되는 경우 (물리의 거리에 따라 때때로) 물리 엔진에 저장됩니다. 그래서 어쨌든 그것을 복제 할 것입니다.

완벽한 시스템이 없습니다. 그리고 일부 게임은 더 간단한 시스템으로 더 나아질 것이고 다른 게임은 시스템간에 더 복잡한 동기화가 필요할 것입니다.

먼저 구성 요소에서 모든 속성에 간단한 방식으로 액세스 할 수 있어야 시스템 미세 조정을 시작한 후 속성을 저장하는 방법을 투명하게 변경할 수 있습니다.

일부 속성을 복사 할 때 부끄러움이 없습니다. 일부 구성 요소가 로컬 사본을 보유해야하는 경우 "외부"값에 액세스하는 것보다 복사 및 동기화하는 것이 더 효율적인 경우가 있습니다.

또한 모든 프레임에서 동기화를 수행 할 필요는 없습니다. 일부 구성 요소는 다른 구성 요소보다 덜 자주 동기화 될 수 있습니다. 렌더 컴포넌트는 종종 좋은 예입니다. 플레이어와 상호 작용하지 않는 것은 멀리 떨어져있는 것과 같이 덜 자주 동기화 될 수 있습니다. 카메라 필드와 멀리 떨어진 사람들은 훨씬 덜 동기화 될 수 있습니다.


크기 구성 요소와 관련하여 위치 구성 요소 내에 번들 될 수 있습니다.

  • 예를 들어, 크기가있는 모든 엔티티가 물리 구성 요소를 갖는 것은 아닙니다. 예를 들어 물리와 번들로 묶는 것이 최선의 관심사가 아닙니다.
  • 위치가 없으면 크기가 중요하지 않을 것입니다
  • 위치가있는 모든 객체의 크기는 아마도 스크립트, 물리, AI, 렌더링 등에 사용될 수 있습니다.
  • 크기는 아마도 매 사이클마다 업데이트되지는 않지만 위치는 변경 될 수 있습니다.

크기 대신 크기 수정자를 사용할 수도 있습니다.

일반적인 속성 저장 시스템에 모든 속성을 저장하는 방법은 ... 올바른 방향으로 가고 있는지 잘 모르겠습니다 ... 게임의 핵심 속성에 집중하고 가능한 많은 관련 속성을 묶는 구성 요소를 만드십시오. 이러한 속성에 대한 액세스를 적절하게 추상화하면 (예 : 필요한 구성 요소의 게터를 통해) 너무 많은 로직을 손상시키지 않고 나중에 이동, 복사 및 동기화 할 수 있어야합니다.


2
BTW +1 또는 -1 저의 현재 담당자는 11 월 9 일 이후 666입니다. 오싹합니다.
코요테

1

구성 요소를 엔티티에 임의로 추가 할 수 있으면 주어진 구성 요소가 엔티티에 있는지 조회하고 참조를 얻는 방법이 필요합니다. 따라서 원하는 것을 찾을 때까지 ObjectComponent에서 파생 된 객체 목록을 반복하여 반환 할 수 있습니다. 그러나 올바른 유형의 객체를 반환합니다.

C ++ 또는 C #에서는 일반적으로와 같은 엔티티에 템플릿 메소드가 있음을 의미합니다 T GetComponent<T>(). 그리고 일단 당신이 그 참조를 가지고 있다면, 당신은 그것이 보유하고있는 회원 데이터를 정확히 알고 있으므로, 직접 액세스하십시오.

루아 또는 파이썬과 같은 무언가에서 반드시 그 객체의 명시 적 유형을 가질 필요는 없으며 아마도 신경 쓰지 않을 것입니다. 그러나 멤버 변수에 액세스하고 존재하지 않는 것에 액세스하려고 할 때 발생하는 예외를 처리 할 수 ​​있습니다.

객체 속성에 대한 쿼리는 정적 형식 언어의 컴파일 시간 또는 동적 형식 언어의 런타임에서 언어가 수행 할 수있는 작업을 복제하는 것처럼 명시 적으로 들립니다.


엔티티에서 제네릭 등을 사용하여 강력한 형식의 구성 요소를 얻는 것에 대해 이해합니다. 제 질문은 해당 속성이 어디로 가야하는지, 특히 여러 구성 요소에서 속성을 사용하고 단일 구성 요소를 소유 할 수없는 곳에 관한 것입니다. 질문에 대한 나의 3 번째와 4 번째 코멘트를보십시오.
George Duckett

기존 구성 요소가 맞으면 선택하거나 새 구성 요소에 맞지 않으면 속성을 고려하십시오. 예를 들어 Unity에는 위치에 불과한 'Transform'컴포넌트가 있으며, 객체의 위치를 ​​변경해야 할 경우 해당 컴포넌트를 통해 수행합니다.
Kylotan

1

"제 생각에 문제는 공통 속성을 어디에 저장해야하는지입니다. 예를 들어 RenderingComponent와 PhysicsComponent에서 사용하는 오브젝트를 위치로 사용합니다. 속성을 배치 할 위치를 결정할 때 과도하게 생각하고 있습니까? 다른 속성에 필요한 속성이있는 구성 요소에 대한 개체를 쿼리합니까? "

문제는 RenderingComponent position을 사용 하지만 PhysicsComponent가이를 제공 한다는 것입니다. 각 사용자 구성 요소에 사용할 공급자를 알려주는 방법이 필요합니다. 이상적으로는 불가지론 적으로, 그렇지 않으면 의존성이 있습니다.

"... 내 질문은 이러한 속성이 어디로 가야하는지, 특히 여러 구성 요소가 속성을 사용하는 곳에서 단일 구성 요소를 소유한다고 할 수없는 경우에 관한 것입니다. 질문에 대한 3 번째 및 4 번째 의견을 참조하십시오."

일반적인 규칙은 없습니다. 특정 속성에 따라 다릅니다 (위 참조).

추악하지만 구성 요소 기반 아키텍처로 게임을 만든 다음 리팩터링하십시오.


나는 PhysicsComponent그때 무엇을 해야하는지 잘 이해하지 못한다고 생각 합니다. 잘못 것 같다, 그래서 나를 추가 할 필요가 시뮬레이션 할 필요가 렌더링 할 것을 모든 것 :이 혼란 날 리드 물리적 환경 내에서 개체를 시뮬레이션 관리로 볼 PhysicsComponent내가 추가 할 때 RenderingComponent이 위치를 포함하고 있기 때문에 그 RenderingComponent사용합니다. 상호 연결된 구성 요소의 웹으로 끝나는 것을 쉽게 알 수 있습니다. 즉, 각 엔터티에 모두 / 대부분을 추가해야합니다.
George Duckett

나는 비슷한 상황이 실제로 있었다 :). PhysicsBodyComponent와 SimpleSpatialComponent가 있습니다. 둘 다 위치, 각도 및 크기를 제공합니다. 그러나 첫 번째는 물리 시뮬레이션에 참여하고 추가 관련 속성을 가지고 있으며 두 번째는 해당 공간 데이터를 보유합니다. 당신이 당신의 자신의 물리 엔진을 가지고 있다면 당신은 후자를 전자를 상속받을 수도 있습니다.
Den

"내가 상호 연결된 구성 요소의 웹으로 끝나는 것을 쉽게 알 수있었습니다. 즉, 각 엔터티에 모두 / 대부분을 추가해야합니다." 실제 게임 프로토 타입이 없기 때문입니다. 여기서는 몇 가지 기본 구성 요소에 대해 이야기하고 있습니다. 그들이 어디에나 사용될 것이라는 것은 당연합니다.
Den

1

당신의 창자가 그를 가진 당신을 말하고 ThingProperty, ThingComponent그리고 ThingManager모든을위한 Thing부품 A의 유형 조금 과잉. 나는 그것이 옳다고 생각합니다.

그러나 시스템에서 사용하는 시스템, 소속 된 엔티티 등의 측면에서 관련 구성 요소를 추적 할 수있는 방법이 필요합니다.

TransformProperty꽤 일반적인 것입니다. 그러나 누가 렌더링 시스템을 담당합니까? 물리 시스템? 사운드 시스템? Transform구성 요소 자체를 업데이트해야하는 이유는 무엇 입니까?

해결책은 getter, setter 및 initializer 외부의 속성에서 모든 종류의 코드를 제거하는 것입니다. 컴포넌트는 게임의 시스템에서 렌더링, AI, 사운드 재생, 이동 등과 같은 다양한 작업을 수행하는 데 사용되는 데이터입니다.

Artemis에 대해 읽으십시오 : http://piemaster.net/2011/07/entity-component-artemis/

코드를 보면 의존성을 목록으로 선언하는 시스템을 기반으로한다는 것을 알 수 ComponentTypes있습니다. 각 System클래스를 작성 하고 constructor / init 메소드에서 시스템이 의존하는 유형을 선언하십시오.

레벨 또는 기타를 설정하는 동안 엔티티를 작성하고 컴포넌트를 추가합니다. 그런 다음 해당 엔티티에 Artemis에 다시보고하도록 지시하면 Artemis는 해당 엔티티의 구성을 기반으로 해당 엔티티에 대해 알고 자하는 시스템이 무엇인지 파악합니다.

그런 다음 루프의 업데이트 단계에서 업데이트 System할 엔티티 목록이 있습니다. 당신이 밖으로 미친 시스템, 빌드 엔티티를 고안 할 수 있도록 이제 구성 요소의 단위를 가질 수 있습니다 ModelComponent, TransformComponent, FliesLikeSupermanComponent, 및 SocketInfoComponent화장 같은 이상한 일을하고, 할 클라이언트 사이의 파리는 멀티 플레이어 게임에 연결하는 비행 접시. 좋아, 그렇지 않을 수도 있지만, 아이디어는 사물을 분리하고 유연하게 유지하는 것입니다.

Artemis는 완벽하지 않으며 사이트의 예제는 약간 기본이지만 코드와 데이터의 분리는 강력합니다. 캐시를 올바르게 사용하면 캐시에도 좋습니다. 아르테미스는 아마도 그 일을 제대로 수행하지 못하지만 배우는 것이 좋습니다.

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