Làm thế nào để nhanh chóng tính toán vùng nhìn trong trò chơi lát gạch 2D?


24

Tôi có một ma trận gạch, trên một số gạch đó có các đối tượng. Tôi muốn tính toán những ô nào hiển thị cho người chơi và những ô nào không, và tôi cần thực hiện nó khá hiệu quả (vì vậy nó sẽ tính toán đủ nhanh ngay cả khi tôi có ma trận lớn (100x100) và nhiều đối tượng).

Tôi đã cố gắng làm điều đó với thuật toán dòng của Bresenham , nhưng nó rất chậm. Ngoài ra, nó đã cho tôi một số lỗi:

----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)

Tôi chắc chắn điều này có thể được thực hiện - sau tất cả, chúng tôi có NetHack, Zangband và tất cả họ đều xử lý vấn đề này bằng cách nào đó :)

Thuật toán nào bạn có thể đề nghị cho việc này?


Đối với nhu cầu của tôi, tôi sẽ xác định hiển thị như thế này: lát có thể nhìn thấy khi ít nhất một phần (ví dụ góc) của ô có thể được kết nối với trung tâm của ô người chơi với một đường thẳng không giao nhau với bất kỳ chướng ngại vật nào.


1
Rất tiếc, lỗi của tôi, NetHack không gây rối với tầm nhìn :)
Rogach

Một số ý tưởng cũ hơn có thể được tìm thấy trên fadden.com/tech/fast-los.html , mặc dù điều đó đã quay trở lại thời mà CPU khá chậm và tính toán dấu phẩy động là điều tốt nhất nên tránh.
fadden

Câu trả lời:


10

Định nghĩa của bạn về hiển thị là như sau:

lát có thể nhìn thấy khi ít nhất một phần (ví dụ góc) của ô có thể được kết nối với tâm của ô người chơi bằng một đường thẳng không giao nhau với bất kỳ chướng ngại vật nào

Bạn có thể thực hiện khái niệm này hoàn toàn theo nghĩa đen bằng cách truy tìm các tia từ ô trình phát của bạn và giao cắt chúng với cảnh của bạn. Bạn ngắt từ mỗi lần lặp một lần khi tia chạm vào chướng ngại vật (hoặc vượt quá ngưỡng khoảng cách nhất định) do bạn chỉ quan tâm đến các ô mà người chơi có thể nhìn thấy trực tiếp. Tôi sẽ chia nhỏ quy trình cho bạn:

  1. Chỉ định mức độ chính xác mà bạn muốn đưa ra thuật toán. Đây sẽ là số lượng tia bạn sẽ theo dõi.
  2. Chia vòng tròn 360 độ đầy đủ cho độ chính xác đã chọn để biết có bao nhiêu độ xoay giữa mỗi tia.
  3. Bắt đầu từ 0 độ và tăng dần theo số lượng được xác định trong bước 2, tạo ra một tia có gốc tọa độ ở giữa ô xếp của người chơi và hướng được xác định bởi góc hiện tại.
  4. Đối với mỗi tia, bắt đầu từ ô người chơi, hãy đi dọc theo hướng của tia cho đến khi bạn chạm vào một chướng ngại vật. Thêm gạch đó vào danh sách gạch có thể nhìn thấy và tiến hành tia tiếp theo. Bạn cũng có thể muốn thêm một khoảng cách tối đa để "từ bỏ" trong trường hợp không tìm thấy va chạm.

Đây là một hình ảnh cho thấy 3 tia ví dụ. Các gạch màu tối hơn là "kết quả" của mỗi tia, tức là nơi xảy ra va chạm. Bạn sẽ cần phải lặp lại tất cả điều này xung quanh vòng tròn:

nhập mô tả hình ảnh ở đây

Tinh chỉnh khoảng cách tối đa và số lượng tia cho hiệu suất. Quá ít và bạn sẽ bỏ lỡ gạch, quá nhiều và hiệu suất của bạn sẽ bị ảnh hưởng. Ngoài ra, các tia xa nhất phải di chuyển càng xa, "lỗi" sẽ càng lớn và độ chính xác bạn sẽ cần càng cao.

Chỉnh sửa

Kiểm tra hướng dẫn sau đây về raycasting, đặc biệt là Bước 3 và Bước 4, để giúp bạn thực hiện bit giao nhau của thuật toán:

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


Tôi có nên chỉ "đi bộ" dọc theo mỗi tia theo một khoảng cách cố định (giả sử là 0,3 điểm) hay tôi cần chạy thứ gì đó như thuật toán của Besenham trên mỗi tia?
Rogach

Nếu bạn tiến lên chỉ bằng một khoảng cách cố định, bạn sẽ gặp vấn đề với các ô bị bỏ lỡ. Kiểm tra hướng dẫn này về raycasting . Tôi cũng sẽ chỉnh sửa câu trả lời đó. Về cơ bản, bạn kiểm tra các va chạm ngang và dọc riêng biệt.
David Gouveia

1
Thuật toán là tốt, nhưng nó sẽ đòi hỏi một lượng lớn tia để hoạt động chính xác với các đường hầm dài 1 gạch.
HolyBlackCat

@HolyBlackCat - đó sẽ chỉ là trường hợp nếu bạn phát ra các tia ở các góc chẵn theo mọi hướng. Nhưng bạn có thể tránh gửi hầu hết các tia đó và chỉ ném chúng ở đầu cuối trong cảnh của bạn. Đây là một lời giải thích tốt: redblobgames.com/articles/visibility
Rogach

8

Tôi thà sử dụng các tia bóng thay vì các tia nhìn.

Giả sử đây là khu vực xem của bạn (khu vực có khả năng hiển thị)

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

Các khối # không thể nhìn thấy trong khi. có thể nhìn thấy

Hãy đặt một số trở ngại X:

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

Bạn có một danh sách X nằm trong vùng xem, sau đó bạn đánh dấu là ẩn mọi ô phía sau mỗi chướng ngại vật này: khi một chướng ngại vật được đánh dấu là ẩn, bạn xóa nó khỏi danh sách.

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

Trong ví dụ trên, bạn có thể thấy bóng đổ ở phía bên phải của bức tường phía dưới và cách bóng này xóa chướng ngại vật ẩn khỏi danh sách chướng ngại vật bạn phải kiểm tra (X phải kiểm tra; * đã kiểm tra).

Nếu bạn nhận được sắp xếp danh sách bằng cách sử dụng một số partiton nhị phân để cosest X được kiểm tra trước, bạn có thể tăng tốc kiểm tra một chút.

Bạn có thể sử dụng một loại thuật toán "Trận chiến hải quân" để kiểm tra khối X ngay lập tức (về cơ bản là tìm kiếm một X giả mạo theo hướng có thể làm cho hình nón rộng hơn)

[CHỈNH SỬA]

Cần có hai tia để chiếu chính xác một bóng và, vì một hình xếp là hình chữ nhật, rất nhiều giả định có thể được thực hiện bằng cách sử dụng các đối xứng có sẵn.

Các tọa độ tia có thể được tính bằng cách sử dụng phân vùng không gian đơn giản xung quanh ô vật cản:

Ví dụ phân vùng không gian

Mỗi khu vực hình chữ nhật tạo thành một lựa chọn về những gì góc của gạch nên được lấy làm cạnh hình nón.

Lý do này có thể được đẩy xa hơn để kết nối nhiều gạch liền kề và để chúng đúc một hình nón rộng hơn như sau.

Bước đầu tiên là đảm bảo rằng không có chướng ngại vật nào hướng về phía người quan sát, trong trường hợp đó, chướng ngại vật gần nhất được xem xét thay thế:

chọn chướng ngại vật gần nhất

Nếu ngói màu vàng là một trở ngại thì gạch trở thành ngói đỏ mới.

Bây giờ hãy xem xét các cạnh hình nón trên:

gạch ứng cử viên

Các ô màu xanh là tất cả các ứng cử viên có thể để cho hình nón rộng hơn: nếu ít nhất một trong số chúng là chướng ngại vật, tia có thể được di chuyển bằng cách sử dụng không gian phân chia xung quanh ô đó như đã thấy trước đó.

Gạch màu xanh lá cây chỉ là một ứng cử viên nếu người quan sát ở trên đường màu cam theo sau:

kiểm tra mở rộng

Điều tương tự là viết tắt của các tia khác và cho các vị trí khác của người quan sát về chướng ngại vật màu đỏ.

Ý tưởng cơ bản là bao phủ càng nhiều diện tích càng tốt cho mỗi lần đúc hình nón và rút ngắn càng nhanh càng tốt danh sách các chướng ngại vật cần kiểm tra.


Cách tiếp cận thú vị và có lẽ là một ý tưởng tốt hơn vì bản chất trừ của nó. Sau khi đọc nó, có lẽ tôi cũng sẽ thực hiện theo cách này.
David Gouveia

Tôi có thể thấy trước các vấn đề trong các tình huống như thế này . Người chơi màu vàng, chướng ngại vật màu xanh và màu tím. Người chơi sẽ có thể nhìn thấy chướng ngại vật màu tím (như tia màu xanh lá cây cho thấy). Nhưng tia sáng màu đỏ đi qua chướng ngại vật màu xanh từ chối ngói màu tím. Nhưng tôi đoán dòng phiên bản tầm nhìn có khả năng có vấn đề lớn hơn thế này.
David Gouveia

Vấn đề này xuất phát từ định nghĩa "ẩn": khi một tia giao nhau với một ô, nó sẽ (gần như) không bao giờ bao phủ hoàn toàn điều này. Vấn đề tương tự được giải quyết với răng cưa khi kết xuất các đoạn đường. Cá nhân tôi nghĩ rằng một ô bị ẩn khi phần chính của nó được che phủ, người ta có thể định nghĩa nó ẩn được che phủ hoàn toàn, bạn có thể tìm thấy nếu nó lộ ra một mặt có khả năng làm cho hình nón rộng hơn ... Dù sao, bạn có thể hủy bỏ chỉ các khối được bảo hiểm đầy đủ.
FxIII

@DavidGouveia - vấn đề nào lớn hơn?
Rogach

@DavidGouveia - Tôi đã thử cách tiếp cận với "hình nón", và nó rất không hiệu quả. Đối với độ chính xác của các tia nhìn thấy - ~ 5500 tia là đủ để nhìn thấy bức tường 20 gạch theo mỗi hướng nếu bạn đang đứng trực tiếp gần nó, và khi khoảng cách chỉ nhìn thấy một viên gạch là nhiều hơn. Và như đã bỏ lỡ một số gạch ở khoảng cách lớn hơn - tốt, không phải ai cũng có thị lực hoàn hảo, nhỉ?
Rogach

8

Vấn đề bạn đang cố gắng giải quyết đôi khi được gọi là Field of View, viết tắt là FOV. Như bạn đã đề cập đến roguelike làm ví dụ, bạn nên xem wiki RogueBasin nói gì về chủ đề này (thậm chí còn có liên kết đến việc triển khai): http://www.roguebasin.com/index.php?title=Field_of_Vision

Có khá nhiều thuật toán khác nhau với những ưu và nhược điểm khác nhau - một so sánh rất tiện dụng cũng có sẵn tại RogueBasin: http://www.roguebasin.com/index.php?title=Comparative_study_of_field_of_view_alerskyms_for_2D_grid_basing_world


Tóm tắt thực sự tốt và đầy đủ!
Rogach

Trang web đó là một tài nguyên tuyệt vời, cảm ơn vì đã chia sẻ liên kết đó. Nó cũng chứa một mô tả đáng kinh ngạc về cách hoạt động của A * pathfinding :-)
uliwitness

Liên kết trong câu trả lời bây giờ đi đến trang chủ của trang web - roguebasin.com/index.php?title=C Category: FOV dường như là một kết hợp hợp lý.
fadden


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.