게임 개체 파괴를 처리하는 올바른 방법


10

엔터티의로드와로드가 항상 동적으로로드되는 게임 세계를 상상해보십시오. 엔터티 목록으로 표시 할 수 있지만 제거하는 것은 어떻습니까?

추가 할 때 새 엔티티를 밀 수 있지만 컨테이너의 아무 곳이나 제거해야 할 수 있습니다. 제거 할 위치를 찾기 위해 요소를 검색하지 않으려면 어떤 선택을해야합니까?

엔티티 ID를 컨테이너에 위치로 저장하여 직접 제거 할 수있는 경로를 만들 수는 있지만 상호 의존성 '장애'를 생성하지는 않습니까?

올바른 방법은 List.RemoveAt (whereToRemove); 하지만 언제 죽어야하는지 엔터티 만 알면 어떨까요?

아니면 방금 물건을 놓쳤습니까? 목록 컨테이너는 객체가 파괴 될 때 알고 자체 크기를 줄입니까?

답변:


10

조건은 다음과 같습니다.

  • 다른 개체는 제거 된 개체가 제거 된 후에도 여전히 제거 된 개체에 종속 될 수 있습니다.

  • 엔티티 만 자신의 제거를 지정하기를 원합니다.

둘 다 가질 수는 없습니다. 왜? 엔터티 자체보다 높은 수준의 코드 (아래 예 참조)에 따라 엔터티를 사용해야하는시기가 결정되기 때문입니다. 결과적으로 동일한 수준의 코드 만 엔티티가 제거에 적합한 지 여부를 판별 할 수 있습니다.

그러나 일어날 수있는 일은 상위 레벨 코드가 수신하는 이벤트를 발생시켜 엔티티 가 자체 제거를 요청할 수 있다는 것입니다 . 그런 다음 상위 레벨은이 제거 요청을 목록에 저장합니다.


예 1 : 이벤트가없는 경우

세계의 엔터티 간 충돌을 확인하고 있습니다. 이것은 주로 주 게임 루프에서 더 높게 처리되어 모든 엔티티를 서로 비교합니다. 이 예에서 구체적으로, 엔티티가 다른 엔티티와 충돌 할 때 해당 엔티티의 내부 논리만으로 얼마나 많은 피해를 입 었는지, 그리고 "만료"되었는지 여부를 결정할 수 있습니다. 여러분의 세계에 A, B, C, D의 네 개체가있는 충돌에 대한 논리 흐름을 따르십시오. A는 우리가 우려하는 개체입니다.

A와 B의 충돌을 확인합니다. 충돌이 있습니다. A 데미지 50 %

A와 C의 충돌을 확인합니다. 충돌이 있습니다. A 데미지 50 % 피해가 0에 도달하기 때문에 A는 "죽었다"고 판단합니다. 목록에서 자신을 제거합니다.

A와 D의 충돌 여부를 검사합니다. 충돌은 없었지만 결코 도달하지 못할 것입니다. 엔티티 목록이 순회 조작 중에 수정 되었기 때문에 런타임 예외가 발생합니다.

예 2 : 이벤트

이전과 동일한 설정입니다.

A와 B의 충돌을 확인합니다. 충돌이 있습니다. A 데미지 50 %

A와 C의 충돌을 확인합니다. 충돌이 있습니다. A 데미지 50 % 피해가 0에 도달하기 때문에 A는 "죽었다"고 판단합니다. 엔터티 관리 코드에 이벤트를 발생시켜 "나를 최대한 빨리 제거하십시오"라고 말합니다. 엔티티 관리 코드는 이벤트의 일부로 전송 된 엔티티 참조를보고 해당 참조를 제거 할 엔티티 목록에 저장합니다.

우리는 A와 D의 충돌을 검사합니다. 충돌이 없으며 검사는 정상적으로 작동합니다.

이제 현재 게임 루프 반복의 마지막에서 제거 할 엔티티 목록을 실행하고 기본 엔티티 목록에서 이들을 모두 제거하십시오.


이것이 어떻게 문제를 완전히 피할 수 있는지 알 수 있습니다. 이벤트를 사용할 필요가없고 신호 나 다른 것을 사용할 수 있지만 원칙은 동일합니다. 안전하게 사용할 수있을 때까지 엔티티를 제거하지 마십시오. 일을 깨끗하고 질서있게 유지하기 위해이 접근 방식의 단점은 추가 할 엔티티와 동일하게 수행하는 것입니다. 참조를 유지하고 다음 게임 루프 반복 시작시에만 추가하십시오.

마지막으로 제거 할 목록과 추가 할 목록을 모두 사용하여 주 엔터티 목록에서 추가 / 제거를 수행 할 때마다 플러시해야합니다.

추신. 개별 삭제를 위해 기본 목록을 찾는 것을 두려워하지 마십시오. 그것은 엔터티 관리의 일부이자 소량이며 대량 목록조차도 순식간에 매우 빠른 경향이 있습니다.


0

확실히 HashMap / HashTable을 찾고 있습니다. 해시 테이블은 키를 특정 값과 일치시키는 맵입니다. 키는 무엇이든 가능합니다 (예 : 엔터티 ID).


0

smartpointer 아이디어를 사용 하여 할당 해제를 처리 할 수 있다고 생각합니다.이 경우 코드 내부의 모든 엔티티 목록을 유지할 필요가 없습니다.

어떤 경우에는 게임의 모든 오브젝트를 반복하기위한 목록이 필요합니다. 이 목록은 단순히 개체를 삽입하고 제거하는 데 정확히 O (1) 시간이 걸리는 링크 목록 일 수 있습니다.

속도를 더 높이기 위해 정적 배열 (아마도 벡터)을 사용할 수 있습니다. 이 경우 동일한 벡터 내에서 2 개의 연결된 목록을 추적해야합니다. 하나는 유효한 객체를 반복하고 다른 하나는 빈 객체를 반복합니다. smartpointer가 삭제 될 위치를 표시 할 때마다 해당 포인터를 제거하고 여유 공간 목록에 여유 공간을 추가하면됩니다. 엔티티를 추가 할 때마다 첫 번째 여유 공간 만 제거하면 엔티티 포인터로 채우고 유효한 객체 목록에 추가해야합니다.

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