2D 타일 게임에서 시력 영역을 빠르게 계산하는 방법은 무엇입니까?


24

타일 ​​매트릭스가 있는데 그 타일 중 일부에는 객체가 있습니다. 플레이어가 볼 수있는 타일과 그렇지 않은 타일을 계산하고 싶습니다. 매우 효율적으로 수행해야합니다 (따라서 큰 행렬 (100x100)과 많은 객체가있는 경우에도 충분히 빠르게 계산됩니다).

Bresenham의 line algorithm 으로 시도했지만 속도가 느 렸습니다. 또한 오류가 발생했습니다.

----XXX-        ----X**-     ----XXX-
-@------        -@------     -@------
----XXX-        ----X**-     ----XXX-
(raw version)   (Besenham)   (correct, since tunnel walls are 
                              still visible at distance)

(@ is the player, X is obstacle, * is invisible, - is visible)

나는 이것이 가능하다는 것을 확신합니다-결국, 우리는 NetHack, Zangband를 가지고 있으며, 그들은 모두이 문제를 어떻게 든 처리했습니다 :)

어떤 알고리즘을 추천 할 수 있습니까?


내 요구를 들어, 나는 정의 할 것이다 이 같은 : 타일의 일부 (예를 들어 코너) 적어도 장애물의 교차하지 않는 직선으로 플레이어 타일의 중심에 연결할 수 있습니다 때 타일을 볼 수 있습니다.


1
내 실수, NetHack은 시선을 엉망으로하지 않았다 :)
Rogach

일부 오래된 아이디어는 fadden.com/tech/fast-los.html 에서 찾을 수 있지만 CPU가 상당히 느리고 부동 소수점 계산이 피할 수 없었던 시절로 거슬러 올라갑니다.
fadden

답변:


10

visible 정의는 다음과 같습니다.

타일의 적어도 일부 (예 : 코너)가 장애물과 교차하지 않는 직선으로 플레이어 타일의 중앙에 연결될 수있을 때 타일이 보입니다.

플레이어 타일에서 광선을 추적하고 장면과 교차시킴으로써이 개념을 문자 그대로 구현할 수 있습니다. 플레이어가 직접 볼 수있는 타일에만 관심이 있기 때문에 광선이 장애물에 닿거나 특정 거리 임계 값을 초과하면 각 반복에서 벗어날 수 있습니다. 나는 당신을 위해 과정을 나눌 것입니다 :

  1. 알고리즘에 제공 할 정밀도 수준을 지정하십시오. 이것은 추적 할 광선의 수입니다.
  2. 360도 원을 선택한 정밀도로 나눠 각 광선 사이에서 회전 할 각도 수를 알 수 있습니다.
  3. 0도에서 시작하여 2 단계에서 결정된 양만큼 증가하고, 플레이어 타일의 중심에서 원점과 현재 각도에 의해 결정된 방향으로 광선을 만듭니다.
  4. 플레이어 타일에서 시작하여 각 광선에 대해 장애물 타일을 칠 때까지 광선의 방향을 따라 습니다. 타일을 보이는 타일 목록에 추가하고 다음 광선으로 진행하십시오. 충돌이없는 경우 "포기"하기 위해 최대 거리를 추가 할 수도 있습니다.

다음은 3 가지 예제 광선을 보여주는 그림입니다. 어두운 색의 타일은 각 광선의 "결과", 즉 충돌이 발생한 위치입니다. 그래도 서클 주위에서 이것을 반복해야합니다.

여기에 이미지 설명을 입력하십시오

성능을 위해 최대 거리와 광선 수를 조정하십시오. 너무 작아서 타일을 너무 많이 놓치면 성능이 저하됩니다. 또한 광선이 가장 멀리 이동해야할수록 "오류"가 커지고 더 정밀해야합니다.

편집하다

알고리즘의 교차 비트를 구현하는 데 도움이되도록 다음 3 단계, 4 단계의 레이 캐스팅에 대한 자습서를 확인하십시오.

http://www.permadi.com/tutorial/raycast/rayc7.html


고정 된 거리 (예 : 0.3 포인트)만큼 각 광선을 따라 "걸을"수 있습니까? 아니면 각 광선에서 Besenham의 알고리즘과 같은 것을 실행해야합니까?
Rogach

고정 된 거리만큼만 진행하면 누락 된 타일에 문제가 발생합니다. 레이 캐스팅에 대한이 자습서를 확인하십시오 . 그 답변을 내 대답으로 편집 할 것입니다. 기본적으로 수평 및 수직 충돌을 개별적으로 확인합니다.
David Gouveia

1
알고리즘은 좋지만 긴 1-tile-wide 터널과 함께 작동하려면 막대한 양의 광선이 필요합니다.
HolyBlackCat

@HolyBlackCat-모든 방향으로 일정한 각도로 광선을 보내는 경우에만 해당됩니다. 그러나 대부분의 광선을 보내지 않고 장면의 선 끝에 만 던질 수 있습니다. 여기에 좋은 설명이 있습니다 : redblobgames.com/articles/visibility
Rogach

8

시선 대신 그림자 광선을 드리 우고 싶습니다.

이것이 뷰 영역 (가시적으로 보이는 영역)이라고 가정하겠습니다.

######################
#####.............####
###................###
##..................##
#....................#
#....................#
#..........@.........#
#....................#
#....................#
##..................##
###................###
#####.............####
######################

# 블록은 동안 보이지 않습니다. 보인다

장애물 X를 넣자 :

######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXXX...........#
##..................##
###....X...........###
#####.............####
######################

보기 영역 내에있는 X 목록이 있고이 장애물 각각 뒤에있는 모든 타일을 숨겨둔 것으로 표시합니다. 장애물이 숨겨져있는 것으로 표시되면 목록에서 제거합니다.

######################
#####.............####
###................###
##.....X.....XXX....##
#......X.......X.....#
#...X.XX.............#
#...X......@.........#
#...X..........X.....#
#...XXXXX*...........#
##......##..........##
###....*#..........###
#####.###.........####
######################

위의 예에서 맨 아래 벽의 가장 오른쪽에 드리운 그림자와이 그림자가 확인해야하는 장애물 목록에서 숨겨진 장애물을 삭제하는 방법을 볼 수 있습니다 (X 확인해야 함; * 확인 됨).

이진 partiton을 사용하여 목록을 정렬하면 가장 성가신 X를 먼저 확인하면 검사 속도가 약간 빨라질 수 있습니다.

일종의 "해군 전투"알고리즘을 사용하여 한 번에 X 블록을 검사 할 수 있습니다 (기본적으로 그림자 원뿔을 더 넓게 만들 수있는 방향에있는 외부 X 찾기)

[편집하다]

그림자를 올바르게 투사하려면 두 개의 광선이 필요하며 타일이 직사각형이므로 사용 가능한 대칭을 사용하여 많은 가정을 수행 할 수 있습니다.

장애물 타일 주위의 간단한 공간 분할을 사용하여 광선 좌표를 계산할 수 있습니다.

공간 분할 예

각 직사각형 영역은 타일 모서리에서 그림자 원뿔 가장자리로 간주해야 할 항목을 선택합니다.

이 추론은 여러 개의 인접한 타일을 연결하고 다음과 같이 하나의 더 넓은 원뿔을 캐스팅하도록 추가로 푸시 될 수 있습니다.

첫 번째 단계는 관찰자 방향을 향한 장애물이 없도록하는 것입니다.이 경우 가장 가까운 장애물이 대신 고려됩니다.

가장 가까운 장애물을 선택하십시오

노란색 타일이 장애물이면 해당 타일이 새 빨간색 타일이됩니다.

이제 상단 원뿔 가장자리를 고려하십시오.

후보 타일

파란색 타일은 그림자 원뿔을 더 넓게 만들 수있는 모든 후보입니다. 하나 이상이 장애물 인 경우 이전에 본 타일 주위의 공간을 사용하여 광선을 이동할 수 있습니다.

녹색 타일은 관찰자가 다음 주황색 선 위에있는 경우에만 후보입니다.

연장 확인

다른 장애물과 적색 장애물에 대한 관찰자의 다른 위치도 마찬가지입니다.

기본 아이디어는 각 콘 캐스팅에 가능한 한 많은 영역을 다루고 확인해야 할 장애물 목록을 가능한 빨리 단축하는 것입니다.


흥미로운 접근 방식과 빼기 특성으로 인해 더 나은 아이디어입니다. 이것을 읽은 후 아마이 방법으로 구현했을 것입니다.
David Gouveia

나는 이런 상황에서 문제를 예견 할 수있다 . 노란색 플레이어, 파란색과 보라색 장애물. 플레이어 녹색 장애물이 보여주는 것처럼 자주색 장애물을 볼 수 있어야합니다. 그러나 파란색 장애물을 통과하는 붉은 그림자 광선은 자주색 타일을 거부합니다. 그러나 나는 시선 버전이 이것보다 더 큰 문제를 일으킬 가능성이 있다고 생각합니다.
David Gouveia

이 문제는 "숨겨진"의 정의에서 비롯됩니다. 광선이 타일과 교차 할 때 (거의) 이것을 완전히 덮지 않습니다. 선 세그먼트를 렌더링 할 때 앨리어싱으로 동일한 문제가 해결됩니다. 개인적으로 타일의 주요 부분을 덮었을 때 타일이 숨겨져 있다고 생각합니다. 숨겨진 것으로 정의 할 수 있습니다. 커버가 완전히 덮힌다면 그림자 그림자 원뿔을 넓게 만들 수있는면을 노출시킬 수 있습니다 ... 어쨌든, 당신은 할 수 있습니다 완전히 덮힌 블록 만 나열합니다.
FxIII

@DavidGouveia-더 큰 문제는 무엇입니까?
Rogach

@DavidGouveia-그림자 "콘"으로 접근을 시도했지만 매우 비효율적이었습니다. 가시 광선의 정밀도에 관해서는 ~ 5500 광선이 벽 근처에 직접 서 있으면 각 방향으로 벽 20 타일을 볼 수 있으며 단일 타일 만 보이는 거리가 훨씬 길어집니다. 그리고 더 먼 거리에서 타일을 잃어버린 것에 관해서는-모든 사람이 시력을 지니고 있지는 않습니까?
Rogach

8

해결하려는 문제를 FOV (Field of View)라고도합니다. RogueBasin 위키가 주제에 대해 무엇을 말해야하는지 (구현에 대한 링크가 있음) 살펴보아야합니다. http://www.roguebasin.com/index.php?title=Field_of_Vision

장단점이 서로 다른 알고리즘이 몇 가지 있습니다. RogueBasin에서도 매우 편리한 비교를 수행 할 수 있습니다 .


정말 좋고 완전한 요약!
Rogach

해당 웹 사이트는 해당 링크를 공유해 주셔서 감사합니다. 또한 :-) 방법 A * 길 찾기 작품의 놀라 울 정도로 이해할 설명을 포함
uliwitness

답변의 링크가 이제 사이트 홈 페이지로 이동합니다 -roguebasin.com/index.php?title=Category:FOV 가 합당한 것으로 보입니다.
초에 fadden


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