서로를 볼 수있는 유닛을 그룹화하는 가장 빠른 방법?


12

내가 작업하고있는 2D 게임에서 게임 엔진은 각 유닛에 대해 뷰 범위에있는 다른 유닛의 목록을 제공 할 수 있습니다.

그룹에서 단위를 정렬하는 확립 된 알고리즘이 있는지 알고 싶습니다 . 여기서 각 그룹은 서로 "연결되어있는"모든 유닛에 의해 정의됩니다 (다른 사람을 통해서도).

예를 들어 질문을 더 잘 이해하는 데 도움이 될 수 있습니다 (E = enemy, O = own unit). 먼저 게임 엔진에서 얻을 수있는 데이터 :

E1 can see E2, E3, O5
E2 can see E1
E3 can see E1
E4 can see O5
E5 can see O2
E6 can see E7, O9, O1
E7 can see E6
O1 can see E6
O2 can see O5, E5
O5 can see E1, E4, O2
O9 can see E6

그런 다음 그룹을 다음과 같이 계산해야합니다.

G1 = E1, E2, E3, E4, E5, O2, O5
G2 = O1, O9, E6, E7

시야에 대한 교환 속성이 ​​있다고 가정 할 수 있습니다. [A가 B를보고, B가 A를보고].

명확히하기 위해 : 나는 이미 게임 엔진 정보의 각 행에서 반복되는 순진한 구현을 작성했지만, 그 모습을 보면 깊이 연구되고 다양한 확립 된 알고리즘을 가지고있을 정도로 일반적인 문제 인 것 같습니다. 나무 같은 구조를 통해?). 내 문제는 유용한 Google 조회수를 반환 한 내 문제를 설명하는 방법을 찾을 수 없다는 것입니다.

당신의 도움에 미리 감사드립니다!


1
나는이 질문이 stackoverflow에서 더 나은 답변을 얻거나 심지어 수학 (이론을 세우는 것)을 얻을 수있을 정도로 일반적이라고 생각합니다. 게임 개발에 국한되지 않습니다.
Tor Valamo

1
@Tor-아마도 사실이지만, 우리가 게임이라는 것을 알고 있다는 사실은 사람들이 문제에 대해 더 구체적인 답변을 만들 수있게 해줄 것입니다.
Robert Fraser

공간 해싱과 가시성 맵을 사용하여 영리한 작업을 수행 할 수 있다고 생각합니다. 그냥 생각하면됩니다.
Jonathan Dickinson

답변:


7

"볼 수 있음"관계가 대칭이므로 "A를 볼 수 있음"이 "B를 볼 수 있음"을 의미하는 경우 계산하려는 그룹 은 "볼 수 있음"관계에 의해 정의 된 그래프 의 연결된 구성 요소 입니다. 다른 사람들이 지적했듯이 다음과 같은 간단한 알고리즘이 있습니다.

while ungrouped units remain:
    let u = arbitrary ungrouped unit
    let g = new group
    let s = temporary stack
    assign u to g
    push u onto s
    while s is not empty:
        let v = topmost unit in s
        remove v from s
        for each unit w that v can see:
            if w is ungrouped:
                assign w to g
                push w onto s
            end if
        end for
    end while
 end while

위의 스택 대신 "새 요소 추가"및 "일부 요소 제거 및 반환"작업을 효율적으로 구현하는 큐 또는 기타 컬렉션을 사용할 수 있습니다 s.

"볼 수있는"관계가 대칭 이 아닌 경우 그룹이 강하게 연결되어 있는지 또는 약하게 연결되어 있는지를 결정해야합니다 . 약하게 연결된 구성 요소의 경우 위의 알고리즘은 라인 for each unit w that v can see을로 교체해야한다는 점을 제외하고는 그대로 작동 합니다 for each unit w that can see v, or that v can see. 들어 강하게 연결 구성 요소 , 당신은 알고리즘 중 하나 (사용할 수 있습니다 Kosaraju의 , Tarjan의 또는 Gabow의 링크 된 위키 백과 페이지에 언급).

비대칭 관계 의 경우 관계 또는 강하게 연결된 구성 요소 의 전이 폐쇄 를 계산할 수도 있습니다 . 이를 위해 Floyd–Warshall 알고리즘을 사용할 수 있습니다 . 자세한 내용 은 SO에 대한 이 답변을 참조하십시오 .


추신. 위의 노트에 링크 된 Wikipedia 기사와 같이 가시성 관계가 변경되면 그룹을 동적으로 업데이트하는 것이 더 효율적일 수 있습니다. 나는 Wikipedia에 언급 된 고급 (?) 알고리즘에 익숙하지 않지만 매번 그룹을 처음부터 다시 계산하는 것을 능가하는 무언가를 함께 모으는 것은 어렵지 않아야합니다.

이 중 절반은 쉽다 : 서로 다른 그룹에있는 두 유닛이 그들 사이에 시야를 확보한다면, 그룹을 합치십시오. 서로를 잃어버린 유닛을 다루는 것은 좀 더 까다 롭습니다. 간단하지만 최적의 해결 방법은 영향을받는 그룹의 유닛에 대해 그룹화 알고리즘을 실행할 때마다 다시 실행하는 것입니다. 가시성 변경이 한 번에 한 쌍의 단위로 발생하는 경우이를 최적화 할 수 있습니다.

  • 유닛이 다른 유닛 만 볼 수 있고 보이지 않으면 이전 그룹에서 제거하여 새 그룹에 할당하십시오.
  • 그렇지 않으면 영향을받는 단위 중 하나에서 시작하여 다른 단위 에 대한 가시성 그래프 (예 : 직선 거리를 휴리스틱으로 사용)에서 A * 검색 을 실행할 수 있습니다. 당신이 그것을 찾으면, 그룹은 헤어지지 않았다; 그렇지 않으면 검색 한 단위 집합이 새 그룹을 형성합니다.
  • 두 단위 중 어느 것이 그룹의 작은 절반에 속할 가능성이 더 큰지 추측하고 그 단위에서 검색을 시작할 수 있습니다. 한 가지 가능성은 다른 장치를 직접 볼 수있는 장치에서 항상 시작하는 것입니다.

4

당신이 가진 것은 연결 그래프입니다. 그리고 일반적으로 연결된 노드 (예 : 문자)를 그룹화하는 가장 좋은 방법은 그래프 검색 알고리즘을 사용하는 것입니다. 깊이 우선, 너비 우선 중 어느 쪽이든 당신이하고있는 모든 다른 노드에서 도달 할 수있는 노드의 목록을 작성하는 것입니다. 그래프가 방향이 지정되지 않은 한 (A가 B에 표시되고 B가 A에 표시되면) 제대로 작동합니다.

특정 경우에이를 개선하기위한 알고리즘이있을 수 있습니다. 예를 들어, 때때로 캐릭터가 움직이지 않고 지형도 움직이지 않아 움직이지 않는 캐릭터가 계속 보이는 경우 다시 연결하지 않도록 연결 그래프를 업데이트하지 않도록 선택할 수 있습니다.

그러나 일반적으로 모든 프레임에서 가시성을 다시 테스트해야합니다. 가능성은 가시성 그룹을 찾기 위해 그래프 순회보다 느릴 것입니다.


3
기술적 용어를 추가하기 만하면 : 찾으려는 것은 연결된 그래프 구성 요소이며 표준 알고리즘은 (1) 모든 노드를 목록에 넣고 (2) 노드를 선택하고 (3) 찾기 BFS / DFS를 사용하여 연결된 모든 노드, (4) 목록에서 찾은 모든 노드를 제거하고 (5) 더 이상 노드가 남지 않을 때까지 반복합니다.
Nathan Reed

3

표준 그래프 연결 문제처럼 보입니다. 이것에 대한 일종의 알고리즘이있을 수 있으며 다음과 같이 보일 수 있습니다.

remaining units = all units
for each unit in remaining units:
    current group = create a new group
    add this unit to current group
    for each unit visible to this unit:
        if unit is in a group already:
            merge current group into that existing group
            set current group as that existing group
        else:
            remove that unit from remaining units
            add that unit to current group

계층 적 클러스터링과 같은 트리를 통해 이것을 구현하는 것이 가능할 것으로 기대하지만, 더 빨리 해결할 수 있을지는 의문입니다. .


흥미롭게도 계층 적 클러스터링 방식은 다음과 같습니다. 모든 단위에 대해 그룹을 만듭니다. 그런 다음 서로를 볼 수있는 모든 단위 쌍에 대해 서로 다른 그룹에있는 경우 그룹을 하나로 병합하고 다른 그룹을 버립니다.
Kylotan

이것이 내가 OP에서 순진한 구현 이라고 부른 것 입니다. 내가 생각했던 것만 큼 나쁘지 않을 수 있다는 것을 아는 것이 좋습니다! :)
mac

트리로하는 방법은 경로 압축과 함께 공용체 집합 을 사용하는 것 입니다. 그것은 순진하지 않으며 실제로 최적입니다.
피터 테일러

2

그래프 연결 문제라는 점에서 응답 한 다른 모든 사람들에게 동의하지만 여기서 필요한 것은 모든 관련 단위에서 생성 된 들로네 삼각 분할 (Delaunay Triangulation) 그래프입니다. 이렇게하는 것은 생성 한 그래프에서 서로 가장 가까운 단위 만 연결되도록합니다. 그래프 교차 (비평 탄성)로 인해 너무 멀리 떨어진 단위가 그래프 내에서 잘못 연결되기 때문에 다른 방법으로 수행하는 것이 매우 어려울 수 있습니다.

위의 내용은 연속 공간을 사용하는 경우에만 적용됩니다 (대부분의 자유 이동 FPS에서와 같이). 그러나 단위가 이동하는 기본 그리드 (평면 그래프)가 이미있는 경우 대신이를 사용하여 연결을 평가할 수 있습니다.

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