"게임 오브젝트"및 컴포넌트 기반 디자인


25

지난 3-4 년 동안 몇 가지 취미 프로젝트를 진행하고 있습니다. 간단한 2D 및 3D 게임. 그러나 최근에 더 큰 프로젝트를 시작했습니다. 지난 몇 달 동안 나는 모든 게임 객체의 기본이 될 수있는 게임 객체 클래스를 디자인하려고 노력했습니다. 따라서 많은 시험 및 다이 테스트를 거친 후 Google로 전환하여 GDC PDF 및 PowerPoint를 빠르게 가리 켰습니다. 이제 컴포넌트 기반 게임 오브젝트를 파악하려고합니다.

엔진이 게임 오브젝트를 만든 다음 건강, 물리, 네트워킹 및 사용자가하는 모든 것을 처리하는 다른 구성 요소를 연결한다는 것을 이해합니다. 그러나 내가 이해하지 못하는 것은 Y가 객체의 상태를 변경했는지 구성 요소 X가 어떻게 알 수 있는지입니다. 건강이 HealthComponent ..에 의해 제어되기 때문에 PhysicsComponent가 플레이어의 생존 여부를 어떻게 알 수 있습니까? 그리고 HealthComponent는 어떻게 "플레이어 사망 애니메이션"을 재생합니까?

나는 이것이 다음과 같은 인상을 받았다 (HealthComponent에서) :

if(Health < 0) {
   AnimationComponent.PlayAnimation("played-died-animation")
}

그러나 HealthComponent가 연결된 게임 오브젝트에 AnimationComponent가 연결되어 있음을 어떻게 알 수 있습니까? 내가 볼 수있는 유일한 해결책은

  1. AnimationComponent가 연결되어 있는지 확인하십시오 (컴포넌트 코드 내부 또는 엔진 쪽).

  2. 구성 요소에 다른 구성 요소가 필요하지만 전체 구성 요소 디자인과 싸우는 것 같습니다.

  3. HealthWithAnimationComponent, HealthNoAnimationComponent, soo on과 같이 쓰고 전체 컴포넌트 디자인 아이디어와 싸우는 것처럼 보입니다.


1
질문을 사랑하십시오. 나는 같은 달 전에 물었어야했지만 결코 그 주변에 도착하지 않았습니다. 내가 직면 한 추가 문제는 게임 객체에 동일한 구성 요소의 여러 인스턴스가있는 경우입니다 (예 : 여러 애니메이션). 대답이 그에 닿을 수 있다면 좋을 것입니다. Game 객체의 모든 구성 요소간에 공유되는 변수와 함께 알림 메시지를 사용했습니다 (따라서 변수 값을 얻기 위해 메시지를 보낼 필요가 없습니다).
ADB

1
게임 유형에 따라 상태 구성 요소가 있고 애니메이션 구성 요소가없는 게임 개체가 없을 수 있습니다. 그리고이 모든 게임 오브젝트는 아마도 Unit과 같은 것을 나타냅니다. 따라서 건강 구성 요소를 버리고 현장 건강을 유지하고 장치에 필요한 모든 구성 요소에 대해 알고있는 UnitComponent를 만들 수 있습니다. 이 세분화 된 구성 요소는 실제로 도움이되지 않습니다. 도메인 당 하나의 구성 요소 (렌더링, 오디오, 물리, 게임 논리)를 갖는 것이 더 현실적입니다.
Kikaimaru

답변:


11

모든 예에서 끔찍한 문제가 있습니다. 상태 구성 요소는 엔터티 사망에 응답해야하는 모든 구성 요소 유형에 대해 알아야합니다. 따라서 적합한 시나리오가 없습니다. 귀하의 법인은 건강 구성 요소를 가지고 있습니다. 애니메이션 구성 요소가 있습니다. 다른쪽에 의존하거나 알지 마십시오. 그들은 메시징 시스템을 통해 통신합니다.

상태 구성 요소가 엔터티가 '죽었다'는 것을 감지하면 '나는 죽었습니다'메시지를 보냅니다. 적절한 애니메이션을 재생하여이 메시지에 응답하는 것은 애니메이션 구성 요소의 책임입니다.

상태 구성 요소는 메시지를 애니메이션 구성 요소로 직접 보내지 않습니다. 어쩌면 그것은 그것을 엔티티의 모든 구성 요소, 전체 시스템에 브로드 캐스트 할 수도 있습니다. 애니메이션 구성 요소는 메시징 시스템에 '내가 죽었다'는 메시지에 관심이 있음을 알려야합니다. 메시징 시스템을 구현하는 방법에는 여러 가지가 있습니다. 그러나 구현할 때는 요점은 건강 구성 요소와 애니메이션 구성 요소가 다른 구성 요소가 존재하는지 알거나 신경 쓸 필요가 없으며 새 구성 요소를 추가해도 기존 구성 요소를 수정하여 적절한 메시지를 보내지 않아도된다는 것입니다.


좋아요, 이치에 맞습니다. 그러나 누가 '죽음'또는 '포탈이 끊어짐'과 같은 '상태'를 선언 하는가? 구성 요소 또는 엔진? 건강 구성 요소를 부착하지 않을 물건에 '죽은'상태를 추가하면 나에게 낭비가 될 것입니다. 나는 그냥 들어가서 코드를 테스트하고 작동하는 것을 볼 것이라고 생각합니다.
hayer

Michael과 Patrick Hughes는 위의 정답을 가지고 있습니다. 구성 요소는 단지 데이터 일뿐입니다. 엔터티가 언제 죽었는지 감지하고 메시지를 보내는 것은 실제로 건전한 구성 요소가 아니라 게임 고유 논리의 일부입니다. 그것이 당신에게 달려있는 추상화하는 방법. 실제 사망 상태는 어디에도 저장 될 필요가 없습니다. 상태가 <0 인 경우 개체가 죽었으며 상태 구성 요소는 '동작 없음'을 위반하지 않고 해당 데이터 검사 논리를 캡슐화 할 수 있습니다! 구성 요소의 상태를 동작으로 수정하는 항목 만 고려하는 경우 제한 사항.
Blecki

궁금한 점이 있다면, 어떻게 MovementComponent를 처리 할 것입니까? 입력을 감지하면 PositionComponent에서 속도를 증가시켜야합니다. 메시지는 어떻게 생겼습니까?
Tips48

8

하는 방식 아르테미스이 문제를 해결는 구성 요소에서 처리하지 않을 것입니다. 구성 요소에는 필요한 데이터 만 포함됩니다. 시스템은 여러 구성 요소 유형을 읽고 필요한 처리를 수행합니다.

따라서 귀하의 경우 HealthComponent (및 기타)를 읽고 적절한 애니메이션을 큐에서 재생하는 RenderSystem이있을 수 있습니다. 이런 방식으로 기능에서 데이터를 분리하면 종속성을 올바르게 관리하기가 쉬워집니다.


결과적으로 문제를 처리하는 좋은 방법은 다음과 같습니다. 구성 요소는 속성을 나타내는 반면 시스템은 서로 다른 속성을 묶어 작업에 사용합니다. 그것은 전통적인 OOP 사고와는 거리가 멀고 일부 사람들의 머리가 아프게합니다 =)
Patrick Hughes

자, 이제 나는 정말로 길을 잃었습니다. "반대로 ES에서, 당신이 전장에 100 개의 유닛을 가지고 있고, 각각 엔티티로 표시된다면, 당신은 유닛에서 호출 할 수있는 각 방법의 사본이 0 개 있습니다. 엔티티는 메소드를 포함하지 않으며 컴포넌트는 메소드를 포함하지 않습니다. 대신 각 측면에 대한 외부 시스템이 있으며 외부 시스템에는 컴포넌트를 보유한 엔티티에서이를 호출 할 수있는 모든 엔티티에서 호출 할 수있는 모든 메소드가 포함됩니다. 체계." 글쎄, GunComponent의 데이터는 어디에 저장되어 있습니까? 라운드 등. 모든 엔티티가 동일한 구성 요소를 공유하는 경우.
hayer

1
내가 이해하는 한 모든 엔터티가 동일한 구성 요소를 공유하지 않으면 각 엔터티에 N 개의 구성 요소 인스턴스를 연결할 수 있습니다. 그런 다음 시스템은 게임에 쿼리하여 자신이 관심을 갖는 구성 요소 인스턴스가있는 모든 엔티티 목록을 찾은 다음 처리를 수행합니다
Jake Woods

이것은 단지 문제를 움직입니다. 시스템은 어떤 구성 요소를 사용해야하는지 어떻게 알 수 있습니까? 시스템에는 다른 시스템도 필요할 수 있습니다 (예 : StateMachine 시스템은 애니메이션을 요구할 수 있습니다). 그러나 WHO가 데이터를 소유하는 문제를 해결합니다. 사실, 간단한 구현은 게임 오브젝트에 사전을 두는 것이고 각 시스템은 거기에 변수를 만듭니다.
ADB

그것은 문제를 주변으로 옮기지 만 더 끈질긴 곳으로 옮깁니다. 시스템에는 관련 구성 요소가 유선으로 연결되어 있습니다. 시스템은 구성 요소를 통해 서로 통신 할 수 있습니다 (StateMachine은 애니메이션이 읽어야 할 구성 요소 값을 설정하여 수행 할 작업 (또는 이벤트를 발생시킬 수 있음)을 설정할 수 있습니다) 사전 접근 방식은 속성 패턴처럼 들리며 작동 할 수도 있습니다. 구성 요소는 관련 속성이 함께 그룹화되어 정적으로 확인할 수 있다는 것입니다. 한 장소에 "Dammage"를 추가했지만 다른 곳에서는 "Damage"를 사용하여 검색하려고했기 때문에 기괴한 오류가 없습니다.
Michael

6

코드에는 객체가 상태가 변경되었는지 알 수있는 방법이 있습니다 (필자는 다른 방법이있을 수 있습니다).

  1. 문자 보내.
  2. 구성 요소에서 직접 데이터를 읽습니다.

1) AnimationComponent가 부착되어 있는지 확인하십시오 (컴포넌트 코드 내부 또는 엔진 쪽)

이를 위해 1. GameObject의 HasComponent 기능을 사용했습니다. 2. 구성 요소를 연결할 때 일부 구성 함수에서 종속성을 확인할 수 있습니다.

2) 구성 요소에 다른 구성 요소가 필요하지만 전체 구성 요소 디자인과 싸우는 것 같습니다.

내가 읽은 일부 기사에서 Ideal 시스템 구성 요소는 서로 의존하지 않지만 실제로는 그렇지 않습니다.

3) HealthWithAnimationComponent, HealthNoAnimationComponent, soo on과 같이 쓰면 전체 구성 요소 디자인 아이디어와 싸우는 것처럼 보입니다.

이러한 구성 요소를 작성하는 것은 나쁜 생각입니다. 내 앱에서 Health 구성 요소를 가장 독립적으로 만들었습니다. 이제 가입자에게 특정 이벤트 (예 : "적중", "치료"등)를 알리는 관찰자 패턴에 대해 생각하고 있습니다. 따라서 AnimationComponent는 애니메이션 재생시기를 스스로 결정해야합니다.

그러나 CBES에 관한 기사를 읽었을 때 감동을 받았으므로 CBES를 사용하고 새로운 가능성을 발견하면 매우 기쁩니다.


1
음, google.no/... @ 슬라이드 16
hayer

@bobenko, CBES 관련 기사 링크를 제공하십시오. 나도 그것에서 매우 흥미있다;)
Edward83

1
그리고 lambdor.net/?p=171 @ bottom, 내 질문에 대한 요약입니다. 복잡하고 비 원소 구성 요소의 측면에서 다른 기능을 어떻게 정의 할 수 있습니까? 가장 기본적인 구성 요소는 무엇입니까? 기본 구성 요소는 순수한 기능과 어떤면에서 다른가요? 기존 구성 요소가 어떻게 새 구성 요소의 새 메시지와 자동으로 통신 할 수 있습니까? 구성 요소가 모르는 메시지를 무시하는 요점은 무엇입니까? 결국 입력 프로세스 출력 모델은 어떻게 되었습니까?
hayer

1
여기에 CBES에 대한 좋은 대답이 있습니다. stackoverflow.com/a/3495647/903195 내가 조사한 대부분의 기사 는이 답변에서 나왔습니다 . 나는 cowboyprogramming.com/2007/01/05/evolve-your-heirachy에서 시작하여 영감을 얻은 다음 Gems 5에서 기억합니다.
Yevhen

그러나 다른 개념의 기능적 반응성 프로그래밍은 어떻습니까?이 질문은 여전히 ​​열려 있지만 연구를위한 좋은 방향입니다.
Yevhen

3

마이클, 패트릭 휴즈, 블레 키도 마찬가지다. 단순히 문제를 해결하는 것을 피하는 해결책은 문제를 일으키는 이데올로기를 포기하는 것입니다.

OOD가 적고 기능 프로그래밍과 비슷합니다. Component-Based Design으로 실험을 시작했을 때이 문제를 발견했습니다. 나는 더 많은 것을 봤는데, "Functive Reactive Programming"이 해결책이라는 것을 알았습니다.

이제 내 구성 요소는 현재 상태를 설명하는 변수 및 필드 모음 일뿐입니다. 그런 다음 관련된 모든 구성 요소를 업데이트하는 많은 "시스템"클래스가 있습니다. 반응 부분은 시스템을 잘 정의 된 순서대로 실행하여 달성됩니다. 이를 통해 처리 및 업데이트를 수행하기 위해 다음 시스템이 무엇이든, 읽고 업데이트하려는 구성 요소 및 엔티티가 무엇이든 항상 최신 데이터를 처리 할 수 ​​있습니다.

그러나 어떤 식 으로든 여전히 문제가 다시 이동했다고 주장 할 수 있습니다. 시스템이 어떤 순서로 실행되어야하는지에 대해서는 어떨까요? if-else와 switch 문을 엉망으로 만들기 전에 주기적 관계와 시간 문제 만 있다면 어떨까요? 암시적인 형태의 메시징입니다. 언뜻보기에는 작은 위험이 있다고 생각합니다. 일반적으로 사물은 순서대로 처리됩니다. 플레이어 입력-> 엔티티 위치-> 충돌 감지-> 게임 로직-> 렌더링-> 다시 시작합니다. 이 경우 각 시스템마다 하나의 시스템이 있고 각 시스템에 update () 메서드를 제공 한 다음 게임 루프에서 순서대로 실행합니다.

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