이것은 힘든 일입니다. 특정 경험 (YMMV)을 바탕으로 몇 가지 질문에 답하려고합니다.
컴포넌트는 다른 컴포넌트의 데이터에 액세스해야합니다. 예를 들어 렌더 구성 요소의 draw 메서드는 변환 구성 요소의 위치에 액세스해야합니다. 이것은 코드에 의존성을 만듭니다.
여기에서 커플 링 / 의존의 정도와 복잡성을 정도를 과소 평가하지 마십시오. 당신은 이것의 차이점을 볼 수 있습니다 (그리고이 다이어그램은 이미 장난감과 같은 수준으로 엄청나게 단순화되었으며 실제 예제에는 커플 링을 풀기위한 인터페이스가 있습니다).
... 이:
... 아니면 이거:
구성 요소는 다형성 일 수 있으며, 이는 약간의 복잡성을 추가로 야기시킨다. 예를 들어 렌더링 구성 요소의 가상 그리기 방법을 재정의하는 스프라이트 렌더링 구성 요소가있을 수 있습니다.
그래서? vtable 및 virtual dispatch에 해당하는 유사 (또는 리터럴)는 기본 상태 / 데이터를 숨기는 객체 대신 시스템을 통해 호출 할 수 있습니다. 유사 vtable 또는 함수 포인터가 시스템을 호출하기 위해 일종의 "데이터"로 바뀌면 "순수한"ECS 구현으로 다형성이 여전히 실용적이고 실현 가능합니다.
다형성 거동 (예를 들어, 렌더링을 위해)이 어딘가에 구현되어야하므로 시스템으로 아웃소싱됩니다. (예 : 스프라이트 렌더 시스템은 렌더 노드를 상속하고 렌더 엔진에 추가하는 스프라이트 렌더 노드를 만듭니다)
그래서? 나는 이것이 빈정 거림으로 나오지 않기를 희망합니다 (내가 자주 비난을 받았지만 텍스트를 통해 감정을 더 잘 전달할 수 있기를 바랍니다). 그러나이 경우 다형성 행동을 "아웃소싱"한다고해서 반드시 추가가 발생하는 것은 아닙니다 생산성 비용.
시스템 간의 통신을 피하기 어려울 수 있습니다. 예를 들어 충돌 시스템에는 콘크리트 렌더 구성 요소가 무엇이든 계산 된 경계 상자가 필요할 수 있습니다.
이 예는 특히 이상하게 보입니다. 렌더러가 데이터를 씬으로 다시 출력하는 이유를 알지 못하거나 (이 컨텍스트에서는 일반적으로 렌더러를 읽기 전용으로 간주) 렌더러가 다른 시스템 대신 AABB를 파악하여 렌더러 및 충돌 / 물리학 (여기서는 "렌더링 컴포넌트"이름에 걸려있을 수 있습니다). 그러나 나는이 예제에 너무 매달리고 싶지는 않습니다. 여전히 시스템 간 통신 (다른 시스템에서 수행 한 변환에 직접 의존하는 시스템을 사용하여 중앙 ECS 데이터베이스에 대한 간접 읽기 / 쓰기 형식의 경우에도)은 자주 필요하지 않아도되어야합니다. 그'
시스템의 업데이트 기능을 호출하는 순서가 정의되어 있지 않으면 사전 문제가 발생할 수 있습니다.
이것은 절대적으로 정의되어야합니다. ECS는 코드베이스에서 가능한 모든 시스템의 시스템 처리 평가 순서를 재정렬하고 프레임과 FPS를 다루는 최종 사용자에게 정확히 동일한 종류의 결과를 다시 얻는 최종 솔루션이 아닙니다. 이것은 ECS를 설계 할 때 적어도 어느 정도 선행해야한다고 강하게 제안하는 것 중 하나입니다. 시스템 호출 / 평가).
그러나 매 프레임마다 전체 타일 맵을 다시 계산하는 것은 비용이 많이 듭니다. 따라서 시스템에서 변경하기 위해 수행 된 모든 변경 사항을 추적하려면 목록이 필요합니다. OOP 방식으로 이것은 타일 맵 컴포넌트에 의해 캡슐화 될 수 있습니다. 예를 들어 SetTile () 메서드는 호출 될 때마다 꼭짓점 배열을 업데이트합니다.
나는 이것이 데이터 지향적 인 관심사라는 것을 제외하고는 이것을 이해하지 못했습니다. 그리고 그러한 성능 함정을 피하기 위해 메모를 포함하여 ECS에 데이터를 표현하고 저장하는 데 따르는 함정은 없습니다 (ECS를 가진 가장 큰 것들은 ECS 최적화의 가장 어려운 측면). 논리와 데이터가 "순수한"ECS로 분리되었다고해서 OOP 표현에서 캐시 / 메모리화할 수있는 항목을 갑자기 재 계산해야한다는 의미는 아닙니다. 내가 매우 중요한 것을 고집하지 않는 한 그것은 똥 / 관련이없는 요점입니다.
"순수한"ECS를 사용하면이 데이터를 타일 맵 구성 요소에 계속 저장할 수 있습니다. 유일한 주요 차이점은이 정점 배열을 업데이트하는 논리가 시스템으로 이동한다는 것입니다.
ECS에 의존하여와 같은 별도의 구성 요소를 생성하는 경우 엔터티에서이 캐시의 무효화 및 제거를 단순화 할 수도 있습니다 TileMapCache
. 캐시가 필요하지만 TileMap
구성 요소 가있는 엔티티에서 사용할 수없는 시점에서 캐시 를 계산하고 추가 할 수 있습니다. 무효화되거나 더 이상 필요하지 않은 경우 무효화 및 제거를 위해 특별히 더 많은 코드를 작성하지 않고도 ECS를 통해 제거 할 수 있습니다.
시스템에 숨겨져 있지만 구성 요소 간의 종속성이 여전히 존재합니다.
"순수한"담당자의 구성 요소간에 종속성이 없습니다 (시스템에 의해 종속성이 숨겨져 있다고 말하는 것이 옳지 않다고 생각합니다). 말하자면 데이터는 데이터에 의존하지 않습니다. 논리는 논리에 의존합니다. "순수한"ECS는 시스템이 작동하는 데 필요한 데이터 및 로직의 최소 최소 서브 세트에 의존하도록 로직을 작성하는 경향이 있습니다. 실제 작업에 필요한 것보다 훨씬 많은 기능. 순수한 ECS 권한을 사용하는 경우 가장 먼저 알아야 할 사항 중 하나는 디커플링 이점이며 동시에 OOP에서 평가 한 정보와 캡슐화 및 특히 정보 숨기기에 대해 알게 된 모든 것에 의문을 제기합니다.
디커플링이란 시스템이 작동하는 데 필요한 정보가 거의 없다는 것을 의미합니다. 모션 시스템은 Particle
또는 보다 복잡한 것에 대해 알 Character
필요조차 없습니다 (시스템 개발자는 시스템에 존재하는 이러한 엔티티 아이디어를 알 필요조차 없습니다). 구조체에 몇 개의 부동 수만큼 단순 할 수있는 위치 구성 요소와 같은 최소 데이터에 대해 알아야합니다. 순수한 인터페이스 IMotion
가 가지고 다니는 것보다 정보와 외부 의존성이 적습니다 . 각 시스템이 작동해야하는 최소한의 지식 덕분에 ECS는 종종 계단식 인터페이스 파손에 직면하지 않고 예상치 못한 예기치 않은 설계 변경을 처리 할 수 있습니다.
"불완전한"접근 방식은 변경 사항이 계단식 파손을 일으키지 않는 시스템에만 로직이 현지화되지 않았기 때문에 이점이 다소 줄어들 것이라고 제안합니다. 로직은 이제 여러 시스템이 액세스하는 구성 요소에서 어느 정도 집중되어 있으며, 이제는이를 사용할 수있는 모든 다양한 시스템의 인터페이스 요구 사항을 충족해야합니다. 이제 모든 시스템에 대한 지식이 더 필요합니다. 정보가 해당 구성 요소와 함께 작동해야합니다.
데이터에 대한 의존성
ECS에 대해 논쟁의 여지가있는 것 중 하나는 추상 인터페이스에 대한 종속성을 원시 데이터로 대체하는 경향이 있으며 일반적으로 덜 바람직하고 더 단단한 형태의 커플 링으로 간주된다는 것입니다. 그러나 ECS가 매우 유리할 수있는 게임과 같은 종류의 영역에서는 시스템의 일부 중앙 레벨에서 해당 데이터로 수행 할 수있는 작업을 설계하는 것보다 데이터 표현을 미리 설계하고 안정적으로 유지하는 것이 더 쉬운 경우가 많습니다. 그것은 코드베이스의 노련한 베테랑들조차도 COM 스타일의 순수한 인터페이스 접근 방식을와 같은 것을 사용하여 고통스럽게 관찰 한 것 IMotion
입니다.
개발자는이 중앙 인터페이스에 기능을 추가, 제거 또는 변경해야하는 이유를 계속 발견했으며, 각 변경 사항은 IMotion
사용 된 시스템의 모든 장소와 함께 구현 된 모든 단일 클래스를 중단시키는 경향이 있기 때문에 비용과 비용이 많이 듭니다 IMotion
. 그동안 많은 고통스럽고 계단식 변화가 일어났던 전체 시간 동안 구현 된 객체 IMotion
는 모두 4x4 행렬의 플로트를 저장하고 전체 인터페이스는 이러한 플로트를 변환하고 액세스하는 방법에만 관심이있었습니다. 데이터 표현은 처음부터 안정적이었으며, 이러한 중앙 집중식 인터페이스가 예상치 못한 설계 요구에 따라 변경되기 쉬운 경우에도 처음부터 존재하지 않으면 많은 고통을 피할 수있었습니다.
이것은 전역 변수처럼 거의 역겨운 것처럼 들릴 수 있지만 ECS 가이 데이터를 시스템을 통해 유형별로 명시 적으로 검색 된 구성 요소로 구성하는 방식의 본질은 그렇게합니다. 컴파일러는 정보 숨기기와 같은 것을 숨길 수 없습니다. 데이터는 일반적으로 변이를 효과적으로 유지하고 한 시스템에서 다음 시스템으로 어떤 종류의 변환 및 부작용이 발생하는지 예측할 수있을 정도로 명확하고 명확합니다 (실제로는 특정 영역에서 OOP보다 간단하고 예측 가능할 수있는 방식으로). 시스템은 평평한 종류의 파이프 라인으로 바뀝니다).
마지막으로 순수한 ECS에서 애니메이션을 처리하는 방법에 대한 질문을하고 싶습니다. 현재 애니메이션을 0과 1 사이의 진행 상황을 기반으로 엔티티를 조작하는 펑터로 정의했습니다. 애니메이션 구성 요소에는 애니메이션 목록이있는 애니메이터 목록이 있습니다. 업데이트 기능에서 현재 엔티티에 활성화 된 모든 애니메이션을 적용합니다.
우리는 모두 실용 주의자입니다. gamedev에서도 상충되는 아이디어 / 응답을 얻을 수 있습니다. 심지어 가장 순수한 ECS조차도 비교적 새로운 현상, 개척 영역이며, 사람들이 고양이를 피부에 대는 방법에 대해 가장 강한 의견을 제시하지는 않았습니다. 내 직감 반응은 렌더링 시스템이 표시하기 위해 애니메이션 구성 요소에서 이러한 종류의 애니메이션 진행을 증가시키는 애니메이션 시스템이지만 특정 응용 프로그램 및 컨텍스트에 대한 많은 뉘앙스를 무시합니다.
ECS를 사용하면 은색 총알이 아니며 여전히 새로운 시스템을 추가하고 일부를 제거하고 새로운 구성 요소를 추가하며 기존 시스템을 변경하여 새로운 구성 요소 유형을 선택하는 경향이 있습니다. 여전히 처음부터 제대로. 그러나 내 경우의 차이점은 특정 디자인 요구 사항을 미리 예측하지 못하면 중심을 바꾸지 않는다는 것입니다. 나는 계단식 파손의 파급 효과를 얻지 못하고있어서 모든 곳을 다니고 자르는 새로운 요구를 처리하기 위해 많은 코드를 변경해야하므로 시간을 크게 절약 할 수 있습니다. 또한 특정 시스템에 앉을 때 관련 구성 요소 (데이터) 이외의 다른 작업에 대해 많은 것을 알 필요가 없기 때문에 뇌에서 더 쉬워졌습니다.