구성 요소 기반 시스템에서 파워 업 수행


29

구성 요소 기반 디자인에 대한 생각을 시작했습니다. 나는 이것을하는 "올바른" 방법 이 무엇인지 모른다 .

시나리오는 다음과 같습니다. 플레이어는 방패를 장착 할 수 있습니다. 방패는 플레이어 주위에 거품으로 그려지며 별도의 충돌 모양을 가지며 영역 효과로 인해 플레이어가받는 피해를 줄입니다.

이러한 방패는 구성 요소 기반 게임에서 어떻게 설계됩니까?

내가 혼란스러워하는 곳은 방패에 분명히 세 가지 구성 요소가 있다는 것입니다.

  • 피해 감소 / 필터링
  • 스프라이트
  • 충돌체.

더 나쁜 쉴드 변형은 더 많은 행동을 가질 수 있으며, 모든 구성 요소는 다음과 같습니다.

  • 플레이어 최대 건강 증진
  • 건강 재생
  • 발사체 편향
  • 기타

  1. 나는 이것을 지나치게 생각하고 있는가? 쉴드는 단지 슈퍼 컴포넌트 여야합니까?
    나는 이것이 잘못된 답이라고 생각합니다. 이것이 당신이 갈 길이라고 생각한다면 설명하십시오.

  2. 방패는 플레이어의 위치를 ​​추적하는 자체 엔티티 여야합니까?
    손상 필터링을 구현하기가 어려울 수 있습니다. 또한 연결된 구성 요소와 엔티티 사이의 선을 흐리게합니다.

  3. 실드는 다른 구성 요소를 수용하는 구성 요소 여야합니까?
    나는 이와 같은 것을 보거나들은 적이 없지만, 일반적 일 수도 있고 아직 충분히 깊지는 않습니다.

  4. 방패는 플레이어에 추가되는 일련의 구성 요소 여야합니까?
    다른 구성 요소를 관리하기위한 추가 구성 요소가있을 수 있습니다. 예를 들어 모든 구성 요소를 그룹으로 제거 할 수 있습니다. (실수로 피해 감소 구성 요소를 남겨두면 재미있을 것입니다).

  5. 더 많은 구성 요소 경험을 가진 사람에게 분명한 것이 있습니까?


나는 당신의 타이틀을 좀 더 구체적으로 만들 자유를 가졌습니다.
Tetrad

답변:


11

방패는 플레이어의 위치를 ​​추적하는 자체 엔티티 여야합니까? 손상 필터링을 구현하기가 어려울 수 있습니다. 또한 연결된 구성 요소와 엔티티 사이의 선을 흐리게합니다.

편집 : 분리 된 엔티티에 대한 "자율적 인 행동"이 충분하지 않다고 생각합니다. 이 특정한 경우, 방패는 목표를 따르고, 목표를 위해 작동하며 목표보다 오래 지속되지 않습니다. "차폐 물체"라는 개념에는 아무런 문제가 없다는 데 동의하지만이 경우 구성 요소에 잘 맞는 행동을 처리합니다. 그러나 나는 또한 순수 논리 엔티티의 옹호자입니다 (변환 및 렌더링 구성 요소를 찾을 수있는 완전한 엔티티 시스템과 반대).

실드는 다른 구성 요소를 수용하는 구성 요소 여야합니까? 나는 이와 같은 것을 보거나들은 적이 없지만, 일반적 일 수도 있고 아직 충분히 깊지는 않습니다.

다른 관점에서보십시오. 구성 요소를 추가하면 다른 구성 요소도 추가되며, 제거하면 추가 구성 요소도 사라집니다.

방패는 플레이어에 추가되는 일련의 구성 요소 여야합니까? 다른 구성 요소를 관리하기위한 추가 구성 요소가있을 수 있습니다. 예를 들어 모든 구성 요소를 그룹으로 제거 할 수 있습니다. (실수로 피해 감소 구성 요소를 남겨두면 재미있을 것입니다).

이것은 해결책이 될 수 있으며 재사용을 촉진하지만 오류가 발생하기 쉽습니다 (예를 들어 언급 한 문제). 반드시 나쁘지는 않습니다. 시행 착오와 새로운 주문 조합을 찾을 수 있습니다 :)

더 많은 구성 요소 경험을 가진 사람에게 분명한 것이 있습니까?

조금 더 자세히 설명하겠습니다.

엔터티에 추가 된 구성 요소에 관계없이 일부 구성 요소의 우선 순위가 어떻게 결정되는지 알고 있습니다 (다른 질문에도 대답 할 것임).

또한 메시지 기반 통신을 사용한다고 가정합니다 (토론을 위해 현재로서는 메소드 호출에 대한 추상화 일뿐입니다).

쉴드 구성 요소가 "설치"될 때마다 쉴드 구성 요소 메시지 핸들러는 특정 (더 높은) 순서로 연결됩니다.

Handler Stage    Handler Level     Handler Priority
In               Pre               System High
Out              Invariant         High
                 Post              AboveNormal
                                   Normal
                                   BelowNormal
                                   Low
                                   System Low

In - incoming messages
Out - outgoing messages
Index = ((int)Level | (int)Priority)

"stats"구성 요소는 In / Invariant / Normal 인덱스에 "손상"메시지 핸들러를 설치합니다. "손상"메시지가 수신 될 때마다 "값"만큼 HP를 줄이십시오.

공정한 표준 행동 (자연 피해 저항 및 / 또는 인종적 특성 등)

방패 구성 요소는 In / Pre / High 색인에 "손상"메시지 핸들러를 설치합니다.

Every time a "damage" message is received, deplete the shield energy and substract
the shield energy from the damage value, so that the damage down the message
handler pipeline is reduced.

damage -> stats
    stats
        stats.hp -= damage.value

damage -> shield -> stats
    shield
        if(shield.energy) {
            remove_me();
            return;
        }
        damage.value -= shield.energyquantum
        shield.energy -= shield.energyquantum;

     stats
        stats.hp -= damage.value

메시지 처리 파이프 라인 구성 요소 메시지 이벤트 처리기의 어느 부분이 설치되어 있는지 확인해야하기 때문에 구성 요소 상호 작용을 디자인 할 때는 신중한 계획이 필요하지만 이것이 매우 유연하다는 것을 알 수 있습니다.

맞는 말이다? 자세한 내용을 추가 할 수 있는지 알려주세요.

편집 : 여러 구성 요소 인스턴스 (두 갑옷 구성 요소)에 관한 것입니다. 하나의 엔터티 인스턴스에서 총 인스턴스 수를 추적하고 (구성 요소 당 상태를 종료) 메시지 이벤트 핸들러를 계속 추가하거나 구성 요소 컨테이너가 중복 구성 요소 유형을 미리 허용하도록 할 수 있습니다.


아무런 이유도없이 첫 번째 질문에 "아니요"라고 답했습니다. 다른 사람들을 가르치는 것은 그들이 어떤 결정의 근거가되는 이유를 이해하도록 돕는 것입니다. IMO, RL에서 힘 장이 자기 몸과 분리 된 "물리적 실체"라는 사실은 그것이 코드에서 분리 된 실체가되기에 충분합니다. 이 경로를 이용하는 것이 왜 나쁜지 제안 할만한 충분한 이유를 제안 할 수 있습니까?
엔지니어

@Nick, 나는 아무에게도 아무 것도 가르치려고하지 않고, 그 주제에 관해 내가 아는 것을 공유하려고하지 않습니다. 그러나 그 불쾌한 다운 보트를 제거 할 수있는 "아니오"에 대한 이론적 근거를 추가하려고합니다 :(
Raine

자율성 요점은 합리적입니다. 그러나 당신은 "이 경우 우리는 행동을 다루고있다"고 지적합니다. True-완전히 분리 된 물리적 객체 (차폐 충돌 모양) 와 관련된 동작 입니다. 나를 위해, 하나의 개체는 하나의 물리 몸체 (또는 관절에 의해 연결된 몸체의 복합 세트)에 연결됩니다. 이것을 어떻게 조정합니까? 내 입장에서는 플레이어가 방패를 사용하는 경우에만 활성화되는 "더미"물리적 고정물을 추가하는 것이 불편하다고 생각합니다. IMO는 융통성이 없으며 모든 조직에서 유지 관리하기가 어렵습니다. 또한 쉴드 벨트가 사망 후에도 쉴드를 유지하는 게임을 고려하십시오 (Dune).
엔지니어 :

@Nick, 엔티티 시스템의 대다수는 논리적 및 그래픽 관련 컴포넌트를 모두 가지고 있으므로이 경우 실드에 대한 엔티티를 갖는 것이 절대적으로 합리적입니다. 순전히 논리적 인 엔터티 시스템에서 "자율성"은 개체의 복잡성, 종속성 및 수명의 산물입니다. 결국, 요구 사항은 최고입니다. 그리고 엔터티 시스템이 무엇인지에 대한 실제 합의가 없다는 것을 고려할 때 프로젝트 맞춤형 솔루션을위한 충분한 공간이 있습니다 :)
Raine

@deft_code, 답변을 개선 할 수 있는지 알려주십시오.
Raine

4

1) 나는 이것을 너무 생각하고 있습니까? 쉴드는 단지 슈퍼 컴포넌트 여야합니까?

아마도 재사용이 가능한 코드와 코드의 의미에 따라 달라질 수 있습니다.

2) 방패는 플레이어의 위치를 ​​추적하는 자체 엔티티 여야합니까?

이 방패가 어떤 단계에서 독립적으로 걸어 다닐 수있는 일종의 생물이 아니라면 아닙니다.

3) 실드는 다른 구성 요소를 수용하는 구성 요소 여야합니까?

이것은 실체와 비슷하게 들리므로 대답은 아니오입니다.

4) 방패는 플레이어에 추가되는 일련의 구성 요소이어야합니까?

그것은 가능성이 높습니다.

"손상 감소 / 필터링"

  • 코어 실드 구성 요소 기능.

"스프라이트"

  • 문자 엔터티에 다른 SpriteComponent를 추가 할 수없는 이유가 있습니까 (즉, 엔터티 당 특정 유형의 둘 이상의 구성 요소)?

"충돌기"

  • 다른 것이 필요합니까? 이것은 물리 엔진에 따라 다릅니다. 캐릭터 엔티티의 ColliderComponent에 메시지를 보내고 모양을 변경하도록 요청할 수 있습니까?

"플레이어 최대 체력, 체력 재생, 발사체 처짐 등"

  • 다른 유물 (도검, 장화, 반지, 주문 / 물약 / 방문 신사 등)이이를 수행 할 수 있으므로 이것들은 구성 요소 여야합니다.

3

물리적 실체 로서의 실드 는 다른 물리적 실체와 다르지 않습니다 . 따라서 쉴드를 별도의 논리 엔티티로 만듭니다 (따라서 자체 구성 요소를 유지할 수 있음).

방패에 충돌 형태를 나타내는 물리적 / 공간적 구성 요소와, 엔티티가있을 때마다 손상을 증가 또는 감소시킬 대상 (예 : 플레이어 캐릭터)에 대한 참조를 보유하는 DamageAffector 구성 요소 DamageAffector를 잡고 있으면 손상됩니다. 따라서 플레이어는 "프록시로"손상을 입습니다.

방패 개체의 위치를 ​​틱마다 플레이어의 위치로 설정하십시오. (이를 수행하는 재사용 가능한 구성 요소 클래스를 작성하십시오. 한 번 작성하고 여러 번 사용하십시오.)

예를 들어 쉴드 엔터티를 만들어야합니다. 파워 업을 수집에. 나는 일반적으로 참조하는 EntityFactory를 사용하여 새로운 엔티티를 생성하는 엔티티 구성 요소 유형 인 Emitter라는 일반적인 개념을 사용합니다. 이미 터의 위치는 당신에게 달려 있습니다. 전원을 켜고 전원을 켤 때 트리거되도록하십시오.


방패는 플레이어의 위치를 ​​추적하는 자체 엔티티 여야합니까? 손상 필터링을 구현하기가 어려울 수 있습니다. 또한 연결된 구성 요소와 엔티티 사이의 선을 흐리게합니다.

논리적 하위 구성 요소 (공간, AI, 무기 슬롯, 입력 처리 등)와 실제 하위 구성 요소 사이에는 미세한 선이 있습니다. 어떤 유형의 엔티티 시스템을 강력하게 정의하기 때문에 어느쪽에 서 있는지 결정해야합니다. 필자의 경우, 엔티티의 물리 하위 컴포넌트는 물리 계층 구조 관계 (예 : 신체의 사지-장면 그래프 노드 생각)를 처리하는 반면, 위에서 언급 한 로직 컨트롤러는 일반적으로 엔티티 컴포넌트로 표시되는 것입니다. 개별 물리적 "비품".


3

실드는 다른 구성 요소를 수용하는 구성 요소 여야합니까?

다른 구성 요소는 포함하지 않지만 하위 구성 요소의 수명을 제어합니다. 따라서 일부 의사 코드에서는 클라이언트 코드에이 "차폐"구성 요소가 추가됩니다.

class Shield : Component
{
    void Start() // happens when the component is added
    {
        sprite = entity.add_component<Sprite>( "shield" );
        collider = entity.add_component<Collider>( whatever );
        //etc
    }

    void OnDestroy() // when the component is removed
    {
        entity.remove_component( sprite );
        entity.remove_component( collider );
    }

    void Update() // every tick
    {
        if( ShouldRemoveSelf() ) // probably time based or something
            entity.remove_component( this );
    }
}

this답에 어떤 의미가 있는지 명확하지 않습니다 . thisShield 구성 요소를 언급하고 있습니까 , 아니면 보호막을 사용하는 엔티티를 의미합니까? 혼란은 나의 잘못일지도 모른다. "구성 요소 기반" 은 다소 모호합니다. 구성 요소 기반 엔터티 버전에서 엔터티는 그 자체로 최소한의 기능 (개체 이름, 태그, 메시징 등)이있는 구성 요소 컨테이너입니다.
deft_code

내가 사용 gameObject하거나 무언가를 사용하면 혼란이 줄어 듭니다 . 현재 게임 오브젝트 / 엔티티 / 구성 요소를 소유 한 모든 것에 대한 참조입니다.
Tetrad

0

구성 요소 시스템에서 스크립팅을 허용하는 경우 쉴드 구성 요소는 거의 "효과"매개 변수에 대해 스크립트를 호출하는 수퍼 구성 요소 일 수 있습니다. 이렇게하면 쉴드에 대한 단일 구성 요소의 단순성을 유지하고 엔티티 정의에 의해 쉴드에 제공되는 사용자 지정 스크립트 파일에 실제로 수행하는 모든 논리를 오프로드합니다.

Moveable 구성 요소와 비슷한 작업을 수행하며 키 반응 스크립트 (내 엔진의 스크립트 하위 클래스) 인 필드를 계산합니다.이 스크립트는 내 입력 메시지를 따르는 메소드를 정의합니다. 따라서 나는 단순히 tempalte 정의 파일에서 이와 같은 것을 할 수 있습니다

camera template
    moveable
    {
        keyreaction = "scriptforcameramoves"

    }  

player template
    moveable
    {
        keyreaction = "scriptfroplayerkeypress"

    }  

메시지 등록 중에 움직일 수있는 구성 요소에서 스크립트 Do 메소드 (C #의 코드)를 등록하십시오.

Owner.RegisterHandler<InputStateInformation>(MessageType.InputUpdate, kScript.Do);

물론 이것은 내 RegisterHandler가 취하는 함수 패턴에 따라 내 Do 메소드에 의존합니다. 이 경우 (IComponent 전송자, 참조 유형 인수)

그래서 내 "스크립트"(내 경우에도 C #은 runime 컴파일)

 public class CameraMoveScript : KeyReactionScript
{
 public override void Do(IComponent pSender, ref InputStateInformation inputState)
 {
    //code here
 }
}

내 기본 클래스 KeyReactionScript

public class KeyReactionScript : Script
{
      public virtual void Do(IComponent pSender, ref InputStateInformation inputState);
}

나중에 입력 컴포넌트가 MessageTypes.InputUpdate 유형의 메시지를 다음과 같은 유형으로 보낼 때

 InputStateInformation myInputState = InputSystem.GetInputState();
 SendMessage<InputStateInformation>(MessageTypes.InputUpdate, ref myInputState);

해당 메시지 및 데이터 유형에 바인딩 된 스크립트의 메소드가 시작되고 모든 논리를 처리합니다.

코드는 엔진에 따라 상당히 다르지만 어떤 경우에도 로직은 작동해야합니다. 구성 요소 구조를 간단하고 유연하게 유지하기 위해 여러 유형에 대해이 작업을 수행합니다.

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