엔터티 시스템에서 기능을 어떻게 구현합니까?


31

엔터티 시스템 ( 1 , 2 ) 에 대해 두 가지 질문을 하고 그에 대한 기사 를 읽은 후에는 이전보다 훨씬 더 잘 이해한다고 생각합니다. 주로 파티클 이미 터, 입력 시스템 및 카메라를 만드는 것에 대한 몇 가지 불확실성이 있습니다. 나는 여전히 엔티티 시스템을 이해하는데 약간의 문제가 있으며, 그것들은 완전히 다른 범위의 객체에 적용될 수 있지만, 그것들은 매우 다른 개념이기 때문에이 세 가지를 선택했고, 매우 넓은 근거를 다루고 엔티티 시스템과 방법을 이해하는 데 도움이되어야합니다. 이와 같은 문제를 스스로 처리하십시오.

JavaScript로 엔진을 구축하고 있으며 입력 처리, 유연한 애니메이션 시스템, 파티클 이미 터, 수학 클래스 및 함수, 장면 처리, 카메라 및 렌더 및 전체 묶음을 포함한 대부분의 핵심 기능을 구현했습니다. 엔진이 일반적으로 지원하는 다른 것들. Byte56의 답변을 읽었으며 엔진을 엔터티 시스템으로 만드는 데 관심이있었습니다. 여전히 기본적인 장면 철학을 갖춘 HTML5 게임 엔진으로 남아 있지만 구성 요소에서 엔티티를 동적으로 생성하는 것을 지원해야합니다.


내가 지금 가진 문제는이 오래된 프로그래밍 개념을이 새로운 프로그래밍 패러다임에 맞추는 것입니다. 다음은 이전 질문의 일부 정의입니다.

  • 엔터티 식별자이다. 데이터가 없으며 객체가 아니며 모든 엔티티의 장면 목록에서 색인을 나타내는 간단한 ID입니다 (실제로는 구성 요소 행렬로 구현하려고합니다).

  • 요소는 하지만 데이터를 조작 할 수 방법으로, 데이터의 소유자이다. 가장 좋은 예는 Vector2D, 또는 "Position"구성 요소입니다. 이 데이터를 가지고 x하고 y있지만 좀 더 쉽게 데이터를 조작 만든다 또한 몇 가지 방법 : add(), normalize(), 등.

  • 시스템은 특정 요구 사항을 충족 개체의 집합에서 작동 할 수있는 무언가이다; 일반적으로 개체는 작동을 위해 지정된 구성 요소 세트를 가져야합니다. 시스템은 "논리적"부분, "알고리즘"부분이며, 구성 요소가 제공하는 모든 기능은 순전히 더 쉬운 데이터 관리를위한 것입니다.


카메라

카메라에는 Vector2D위치 속성, 회전 속성 및 포인트를 중심으로하는 몇 가지 방법이 있습니다. 각 프레임은 장면과 함께 렌더러에 공급되며 모든 객체는 해당 위치에 따라 변환됩니다. 그런 다음 장면이 렌더링됩니다.

엔터티 시스템에서 이러한 종류의 객체를 어떻게 표현할 수 있습니까? 카메라가 엔터티, 구성 요소 또는 조합 입니까 ( 답변에 따라 )?

파티클 이미 터

파티클 이미 터와 관련된 문제는 다시 무엇을해야 하는가입니다. 10,000 개가 넘는 입자를 지원하고 싶을 때 파티클 자체가 엔티티가되어서는 안된다고 확신합니다. 많은 엔티티를 생성하면 성능이 크게 저하 될 것으로 생각합니다.

엔터티 시스템에서 이러한 종류의 객체를 어떻게 표현할 수 있습니까?

입력 관리자

마지막으로 이야기하고 싶은 것은 입력을 처리하는 방법입니다. 현재 버전의 엔진에는이라는 클래스가 Input있습니다. 키 누름 및 마우스 위치 변경과 같은 브라우저 이벤트를 구독하고 내부 상태를 유지하는 핸들러입니다. 그런 다음 플레이어 클래스에는 react()입력 객체를 인수로 허용하는 메서드 가 있습니다. 이것의 장점은 입력 객체를 .JSON으로 직렬화 한 다음 네트워크를 통해 공유 할 수있어 부드러운 멀티 플레이어 시뮬레이션이 가능하다는 것입니다.

이것이 어떻게 엔티티 시스템으로 변환됩니까?

답변:


26
  • 카메라 : 이것을 구성 요소로 만드는 것은 매우 깔끔합니다. 그것은 단지isRenderingSean과 같은 플래그와 깊이 범위는 말했다. "시야"(2D로 스케일이라고 할 수 있을까요?)와 출력 영역 외에도. 출력 영역은이 카메라가 렌더링되는 게임 창의 부분을 정의 할 수 있습니다. 언급 한 것처럼 별도의 위치 / 회전이 없습니다. 카메라 구성 요소가있는 작성 엔티티는 해당 엔티티의 위치 및 회전 구성 요소를 사용합니다. 그런 다음 카메라, 위치 및 회전 구성 요소가있는 엔티티를 찾는 카메라 시스템이 있습니다. 시스템은 해당 엔티티를 가져 와서 위치, 회전, 심도 및 시야에서 화면의 지정된 부분으로 볼 수있는 모든 엔티티를 그립니다. 다중 뷰 포트, "캐릭터 뷰"창, 로컬 멀티 플레이어,

  • 파티클 이미 터 : 이것 역시 컴포넌트 일뿐입니다. 파티클 시스템은 위치, 회전 및 파티클 이미 터가있는 엔티티를 찾습니다. 이미 터에는 현재 이미 터를 재생하는 데 필요한 모든 속성이 있습니다. 속도, 초기 속도, 붕괴 시간 등 모든 것이 무엇인지 잘 모르겠습니다. 여러 번 패스 할 필요가 없습니다. 파티클 시스템은 해당 구성 요소가있는 엔티티를 알고 있습니다. 기존 코드를 많이 재사용 할 수 있다고 생각합니다.

  • 입력 : 나는 이것을 구성 요소로 만드는 것이 위에서 제안한 제안을 고려할 때 가장 의미가 있다고 말할 수 있습니다. 너의input system현재 입력 이벤트로 매 프레임마다 업데이트됩니다. 그런 다음 입력 구성 요소가있는 모든 항목을 통과하면 해당 이벤트가 적용됩니다. 입력 컴포넌트에는 모든 관련 메소드 콜백과 관련된 키보드 및 마우스 이벤트 목록이 있습니다. 메소드 콜백이 어디에 있는지 확실하지 않습니다. 아마도 일부 입력 컨트롤러 클래스입니까? 엔진 사용자가 나중에 수정하는 데 가장 적합한 방법은 무엇입니까? 그러나이를 통해 카메라 엔터티, 플레이어 엔터티 또는 필요한 항목에 입력 제어를 쉽게 적용 할 수 있습니다. 여러 엔티티의 움직임을 키보드와 동기화하고 싶습니까? 동일한 입력에 응답하는 모든 입력 구성 요소를 제공하면 입력 시스템은 해당 이동 이벤트를 요청하는 모든 구성 요소에 적용합니다.

따라서 대부분이 내 머리 꼭대기에 있기 때문에 추가 설명이 없으면 의미가 없습니다. 당신이 명확하지 않은 것을 알려주세요. 기본적으로, 나는 당신에게 많은 일을주었습니다 :)


또 다른 위대한 답변! 감사! 이제 내 유일한 문제는 엔티티를 빠르게 저장하고 검색하는 것이므로 사용자는 실제로 게임 루프 / 로직을 구현할 수 있습니다. 직접 알아 내려고 노력하지만 먼저 Javascript가 배열, 객체 및 메모리에 정의되지 않은 값을 사용하면 추측 할 수 있습니다 ... 브라우저마다 다르게 구현할 수 있기 때문에 문제가됩니다.
jcora

이것은 아키텍처 적으로 순수하다고 생각하지만 렌더링 시스템은 어떻게 모든 엔티티를 반복하지 않는 활성 카메라를 결정합니까?
Pace

@ 페이스 액티브 카메라를 매우 빨리 찾기를 원하기 때문에 카메라 시스템이 액티브 카메라가있는 엔티티를 참조하도록 할 수 있습니다.
MichaelHouse

여러 카메라 (보기, 회전, 이동 등)를 제어하는 ​​로직을 어디에 배치합니까? 여러 대의 카메라를 어떻게 제어합니까?
plasmacel

@plasmacel 컨트롤을 공유하는 여러 개체가있는 경우 입력을받는 개체를 결정하는 것은 제어 시스템의 책임입니다.
MichaelHouse

13

내가 어떻게 접근했는지는 다음과 같습니다.

카메라

내 카메라는 다른 구성 요소와 같이 엔티티로, 구성 요소가 첨부되어 있습니다.

  1. TransformTranslation, RotationScale속도 등 다른 사람뿐만 아니라, 속성

  2. Pov(관점)가있다 FieldOfView, AspectRatio, Near, Far, 및 어떤 다른 (A)에 더하여, 투영 매트릭스를 생성하는 데 필요한 IsOrtho관점과 직교 돌기 사이에서 전환하는 데 사용 플래그. Pov또한 ProjectionMatrix렌더링 시스템에서 사용하여 읽기시 내부적으로 계산되고 다른 속성이 수정 될 때까지 캐시되는 지연로드 속성을 제공합니다 .

전용 카메라 시스템이 없습니다. 렌더 시스템은의 목록을 유지하고 Pov렌더링 할 때 사용할 목록 을 결정하는 로직을 포함합니다.

입력

InputReceiver구성 요소는 모든 개체에 부착 될 수있다. 여기에는 현재 및 이전 키 상태, 현재 및 이전 마우스 위치 및 버튼 상태 등에 대한 매개 변수를 취하는 엔티티 별 입력 처리를 보유하는 데 사용되는 이벤트 핸들러 (또는 언어가 지원하는 경우 람다)가 첨부되어 있습니다. 마우스와 키보드에 대한 별도의 처리기가 있습니다).

예를 들어, Entity / Component에 익숙해 질 때 만든 소행성과 같은 테스트 게임에는 두 가지 입력 람다 방법이 있습니다. 하나는 화살표 키와 스페이스 바 (발 사용)를 처리하여 선박 항해를 처리합니다. 다른 하나는 일반적인 키보드 입력-종료, 일시 중지 등의 키, 재시작 레벨 등을 처리합니다. 두 개의 구성 요소를 만들고 각 람다를 자체 구성 요소에 연결 한 다음 탐색 수신기 구성 요소를 선박 엔터티에 할당하고 다른 하나는 보이지 않는 명령 프로세서 엔티티.

선박 InputReceiver구성 요소 (C #)에 부착 된 프레임 사이에 유지되는 키를 처리하는 이벤트 핸들러는 다음과 같습니다 .

  void ship_input_Hold(object sender, InputEventArgs args)
    {
        var k = args.Keys;
        var e = args.Entity;

        var dt = (float)args.GameTime.ElapsedGameTime.TotalSeconds;

        var verlet = e.As<VerletMotion>();
        var transform = e.As<Transform>();

        if (verlet != null)
        {

        /// calculate applied force 
            var force = Vector3.Zero;
            var forward = transform.RotationMatrix.Up * Settings.ShipSpeedMax;

            if (k.Contains(Keys.W))
                force += forward;

            if (k.Contains(Keys.S))
                force -= forward;

            verlet.Force += force * dt;
        }

        if (transform != null)
        {
            var theta = Vector3.Zero;

            if (k.Contains(Keys.A))
                theta.Z += Settings.TurnRate;

            if (k.Contains(Keys.D))
                theta.Z -= Settings.TurnRate;

            transform.Rotation += theta * dt;
        }

        if (k.Contains(Keys.Space))
        {
            var time = (float)args.GameTime.TotalGameTime.TotalSeconds - _rapidFireLast;

            if (time >= _rapidFireDelay)
            {
                Fire();
                _rapidFireLast = (float)args.GameTime.TotalGameTime.TotalSeconds;
            }
        }
    }

카메라가 모바일 인 경우, 자체 제공 InputReceiver하고 Transform, 구성 요소 구현 종류 제어 당신이 원하는 무엇이든 람다 또는 핸들러를 첨부하면됩니다.

InputReceiver네비게이션 핸들러를 사용 하여 컴포넌트를 우주선에서 소행성 또는 그 밖의 다른 것으로 이동하여 대신 날아갈 수 있다는 점에서 깔끔 합니다. 또는 Pov소행성, 가로등 등 장면의 다른 요소에 구성 요소를 할당하면 해당 엔티티의 관점에서 장면을 볼 수 있습니다.

InputSystem키보드, 마우스 등의 내부 상태를 유지 하는 클래스 InputSystem는 내부 엔터티 컬렉션을 InputReceiver구성 요소 가있는 엔터티로 필터링합니다 . 이 Update()방법 에서는 해당 콜렉션을 반복하고 렌더링 시스템이 Renderable컴포넌트를 사용하여 각 엔티티를 그리는 것과 같은 방식으로 각 컴포넌트에 연결된 입력 핸들러를 호출합니다 .

입자

이것은 실제로 입자와의 상호 작용 계획에 달려 있습니다. 하나의 객체처럼 행동하는 파티클 시스템이 필요하다면 (예 : 불꽃 놀이가 플레이어가 건드 리거나 칠 수 없다는 것을 보여줍니다) ParticleRenderGroup파티클에 필요한 모든 정보를 포함 하는 단일 엔티티와 구성 요소를 생성합니다. 부패 등- Renderable구성 요소에 포함되지 않습니다 . 렌더링 할 때 렌더 시스템은 엔티티가 RenderParticleGroup첨부되어 있는지 확인 하고 적절하게 처리합니다.

충돌 감지에 참여하고 입력에 응답하는 데 개별 입자가 필요하지만 배치로 렌더링하려면 Particle입자별로 정보를 포함 하는 구성 요소를 만들고 다음과 같이 만듭니다. 별도의 엔티티. 렌더 시스템은 여전히 ​​배치 할 수 있지만 다른 시스템에서는 별도의 객체로 취급됩니다. (이것은 인스턴스화와 매우 잘 작동합니다.)

그런 다음 MotionSystem(또는 엔티티 위치 업데이트를 처리하는 사용 등) 또는 전용 ParticleSystem에서 프레임 당 각 입자에 필요한 처리를 수행하십시오. 는 RenderSystem/ 건축 일괄 처리하고 자신이 만든 파괴하고 같은 입자 컬렉션을 캐싱에 대한 책임, 그리고 필요에 따라 렌더링 것이다.

이 접근 방식의 한 가지 좋은 점은 입자의 충돌, 컬링 등에 특별한 경우가 필요하지 않다는 것입니다. 다른 모든 종류의 엔티티에 대해 작성한 코드를 계속 사용할 수 있습니다.

결론

크로스 플랫폼 (JavaScript에 적용 할 수 없음)을 고려중인 경우 모든 플랫폼 별 코드 (즉, 렌더링 및 입력)가 두 시스템으로 분리됩니다. 게임 로직은 플랫폼에 독립적 인 클래스 (모션, 콜리 전 등)로 유지되므로 포팅시 해당 로직을 건드릴 필요가 없습니다.

본인은 응용 프로그램의 요구 사항을 충족시키기 위해 패턴을 조정하는 대신 패턴을 엄격하게 준수하기 위해 신발 모양의 물건을 패턴으로 만드는 Sean의 입장을 이해하고 동의합니다. Input, Camera 또는 Particles에서 그런 종류의 처리가 필요한 것은 보이지 않습니다.


여러 카메라 (보기, 회전, 이동 등)를 제어하는 ​​로직을 어디에 배치합니까?
plasmacel

7

입력 및 게임 로직은 엔터티 구성 요소 시스템 외부의 전용 코드 덩어리에서 처리 될 수 있습니다. 기술적으로 디자인에 적용하는 것은 가능하지만 이점은 거의 없습니다. 게임 로직과 UI는 해킹되어 있으며 추상화에 누출이 많으며, 건축 순도를 위해 사각형 구멍을 둥근 구멍에 넣는 것은 낭비입니다. 시간.

마찬가지로 파티클 이미 터는 특히 성능에 관심이있는 경우 특별한 짐승입니다. 이미 터 구성 요소는 의미가 있지만 그래픽은 나머지 렌더링을 위해 마법과 혼합되어 해당 구성 요소와 특별한 마법을 수행합니다.

카메라와 관련하여 카메라에 활성 플래그와 "깊이"인덱스를 부여하고 그래픽 시스템이 활성화 된 모든 카메라를 렌더링하도록합니다. 이것은 실제로 GUI를 포함한 많은 트릭에 유용합니다 (게임 세계에서 직교 모드로 GUI를 렌더링하고 싶습니까? 문제 없습니다. 다른 오브젝트 마스크를 가진 두 대의 카메라에 불과하고 GUI가 상위 계층으로 설정되어 있습니다). 특수 효과 레이어 등에 유용합니다.


4

카메라가 엔티티일까요, 아니면 단순히 컴포넌트일까요?

이 질문이 실제로 무엇인지 잘 모르겠습니다. 게임에서 당신이 가진 유일한 것은 엔터티이므로 카메라는 엔터티 여야합니다. 카메라 기능은 일종의 카메라 구성 요소를 통해 구현됩니다. "포지션"및 "회전"구성 요소가 따로 없습니다. 너무 낮은 수준입니다. 그것들은 월드에 위치한 어떤 엔티티에도 적용되는 일종의 WorldPosition 컴포넌트로 결합되어야합니다. 어느 것을 사용 해야하는지에 관해서는 어떻게 든 시스템에 로직을 가져와야합니다. 카메라 처리 시스템에 하드 코딩하거나 스크립트 등을 첨부 할 수 있습니다. 도움이되는 경우 카메라 구성 요소에서 활성화 / 비활성화 플래그를 가질 수 있습니다.

파티클 자체가 엔티티가되어서는 안된다고 확신합니다

나도. 파티클 이미 터는 엔티티 일 것이고, 파티클 시스템은 주어진 엔티티와 관련된 파티클을 추적 할 것입니다. 이와 같은 것은 "모든 것이 실체라는 것"이 ​​터무니없는 것임을 깨닫는 곳입니다. 실제로, 엔터티 인 유일한 요소는 구성 요소 조합의 이점이있는 비교적 복잡한 개체입니다.

입력에 관해서 : 게임 세계에는 입력이 존재하지 않으므로 시스템에 의해 처리됩니다. 게임의 모든 것이 컴포넌트를 중심으로 회전하지는 않기 때문에 반드시 '컴포넌트 시스템'일 필요는 없습니다. 그러나 입력 시스템이있을 것입니다. 어떤 종류의 Player 컴포넌트로 입력에 응답하는 엔티티를 표시하고 싶을 수도 있지만, 입력은 복잡하고 완전히 게임에 따라 달라 지므로이를위한 컴포넌트를 만들려는 시도는 거의 없습니다.


1

다음은 이러한 문제를 해결하기위한 아이디어 중 일부입니다. 그들은 아마도 그들에게 문제가있을 것입니다. 아마도 더 나은 접근 방식이있을 것입니다. 그래서 제 대답을하십시오.

카메라 :

엔터티에 추가 할 수있는 "카메라"구성 요소가 있습니다. 그래도이 컴포넌트에 어떤 데이터를 넣어야하는지 알 수 없습니다. 별도의 "Position"과 "Rotation"컴포넌트를 가질 수 있습니다! follow이 이미 연결되어 엔티티를 다음 있기 때문에 방법이 구현 될 필요가 없습니다! 그리고 나는 그것을 자유롭게 움직일 수 있습니다. 이 시스템의 문제점은 다양한 카메라 오브젝트 일 것입니다. 어떤 카메라 오브젝트 RendererSystem를 사용해야하는지 어떻게 알 수 있습니까? 또한 카메라 객체를 전달하는 데 사용되었지만 이제는 RendererSystem모든 엔티티를 두 번 반복해야합니다. 먼저 카메라와 같은 역할을하는 객체를 찾고, 실제로는 모든 것을 렌더링합니다.

파티클 이미 터 :

이 될 것이다 ParticleSystem는 "터"구성 요소를 가진 모든 개체를 업데이트 할 것이다. 입자는 해당 구성 요소 내부의 상대 좌표 공간에있는 멍청한 개체입니다. 여기에 렌더링 문제가 있습니다. ParticleRenderer시스템 을 만들 거나 기존 시스템의 기능을 확장해야합니다.

입력 시스템 :

여기서 가장 큰 관심사는 논리 또는 react()방법이었습니다. 내가 생각해 낸 유일한 해결책은 별도의 시스템과 각 시스템의 구성 요소입니다. 이것은 정말 해키처럼 보이며 잘 처리하는 방법을 모르겠습니다. 한 가지 문제는 내가 염려 Input하는 한 클래스로 구현할 수는 있지만 나머지 게임에 어떻게 통합 할 수 있는지 알 수 없다는 것입니다.


RendererSystem이 모든 엔티티를 반복하는 이유는 없습니다. 이미 드로어 블 목록 (및 카메라, 라이트 (드로어가 드로어 블이 아닌 경우))이 있거나 해당 목록의 위치를 ​​알고 있어야합니다. 또한 렌더링하려는 카메라를 컬링하기를 원할 수 있으므로 카메라에 보이는 드로어 블 엔티티 ID 목록이 포함될 수 있습니다. 여러 대의 카메라와 하나의 활성 카메라 또는 서로 다른 POV에 연결된 하나의 카메라를 가질 수 있습니다. 두 카메라 모두 스크립트와 트리거 및 입력과 같은 여러 가지로 제어 할 수 있습니다.

@ melak47도 마찬가지입니다. 나도 생각했지만 Aremis가하는 방식으로 구현하고 싶었습니다. 그러나이 "시스템 저장소 관련 항목에 대한 참조"는 점점 더 결함이있는 것 같습니다 ...
jcora

Artemis는 각 구성 요소 유형을 자체 목록에 저장하지 않습니까? 따라서 드로어 블 구성 요소, 카메라 구성 요소, 조명 및 어딘가에없는 구성 요소 목록이 정확히 없습니까?
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.