A * tìm đường dẫn lưới


15

Vì vậy, tôi đã tạo ra trò chơi java 2D từ trên xuống trong khung này có tên là Greenfoot và tôi đã làm việc về AI cho những kẻ mà bạn sẽ chiến đấu. Tôi muốn chúng có thể di chuyển khắp thế giới một cách thực tế để tôi sớm nhận ra, trong số một vài điều khác, tôi sẽ cần một số cách tìm đường.

Tôi đã thực hiện hai nguyên mẫu A *. Một là dựa trên lưới và sau đó tôi đã tạo một cái hoạt động với các điểm mốc, vì vậy bây giờ tôi cần tìm cách chuyển từ "bản đồ" 2 chướng ngại vật / tòa nhà sang biểu đồ các nút mà tôi có thể tạo đường dẫn từ đó. Tính năng tìm đường thực tế có vẻ ổn, chỉ các danh sách mở và đóng của tôi có thể sử dụng cấu trúc dữ liệu hiệu quả hơn, nhưng tôi sẽ làm được điều đó nếu và khi tôi cần.

Tôi dự định sử dụng lưới điều hướng cho tất cả các lý do được nêu trong bài đăng này trên ai-blog.net . Tuy nhiên, vấn đề tôi gặp phải là những gì A * nghĩ là con đường ngắn nhất từ ​​trung tâm / cạnh đa giác không nhất thiết là con đường ngắn nhất nếu bạn đi qua bất kỳ phần nào của nút. Để có được một ý tưởng tốt hơn, bạn có thể xem câu hỏi tôi đã hỏi trên stackoverflow .

Tôi đã có một câu trả lời tốt liên quan đến một biểu đồ tầm nhìn. Tôi đã mua cuốn sách ( Hình học tính toán: Thuật toán và ứng dụng ) và đọc thêm về chủ đề này, tuy nhiên tôi vẫn ủng hộ một mạng lưới điều hướng (Xem phần " Quản lý độ phức tạp " từ Ghi chú của Amit về Tìm kiếm đường dẫn ). (Như một lưu ý phụ, có lẽ tôi có thể có thể sử dụng Theta * để chuyển đổi nhiều điểm tham chiếu thành một đường thẳng nếu đầu tiên và cuối cùng không bị che khuất. Hoặc mỗi lần tôi di chuyển trở lại kiểm tra đến điểm dừng trước khi cuối cùng để xem liệu tôi có thể đi thẳng từ cái này

Vì vậy, về cơ bản những gì tôi muốn là một lưới điều hướng trong đó một khi tôi đã đặt nó thông qua thuật toán phễu (ví dụ: cái này từ Digesting Duck ) tôi sẽ nhận được đường dẫn ngắn nhất thực sự, thay vì chỉ có một đường dẫn ngắn nhất theo nút đến nút, nhưng không phải là ngắn nhất thực tế mà bạn có thể đi qua một số đa giác và bỏ qua các nút / cạnh.

Oh và tôi cũng muốn biết làm thế nào bạn đề nghị lưu trữ thông tin liên quan đến đa giác. Đối với ví dụ nguyên mẫu điểm tham chiếu mà tôi đã tạo, tôi chỉ có mỗi nút là một đối tượng và lưu trữ một danh sách tất cả các nút khác mà bạn có thể di chuyển đến từ nút đó, tôi đoán rằng nó sẽ không hoạt động với đa giác? và làm thế nào để tôi biết nếu một đa giác là mở / di chuyển ngang hoặc nếu nó là một vật thể rắn? Làm thế nào để tôi lưu trữ các nút tạo nên đa giác?

Cuối cùng, đối với hồ sơ: Tôi muốn tự mình lập trình điều này từ đầu mặc dù đã có sẵn các giải pháp khác và tôi không có ý định sử dụng mã này trong bất kỳ điều gì khác ngoài trò chơi này nên không vấn đề gì nó chắc chắn sẽ có chất lượng kém.


Tôi không chắc nhưng những liên kết này có thể giúp ích: gamedev.stackexchange.com/questions/1327/ Khăn gamedev.stackexchange.com/questions/8087/ cũng có một câu hỏi khác về tìm đường mà tôi không thể tìm thấy ngay bây giờ , trong đó có một tiền thưởng và có một câu trả lời rất tốt.
Ali1S232

Vâng, trong liên kết thứ hai bạn có thể thấy mối quan tâm chính của tôi, thuật toán A * sẽ cho đường dẫn quanh đáy là điểm trung gian ngắn nhất nhưng đường dẫn quanh đỉnh của chướng ngại vật thực sự là ngắn nhất. Tôi muốn biết làm thế nào tôi có thể lấy A * để đưa cho tôi đường dẫn quanh đỉnh mà sau đó tôi sẽ đi thẳng (ví dụ bằng thuật toán phễu) để có được đường đi ngắn nhất thực sự, trong đó như thể nó đưa tôi đường đi ở phía dưới ngay cả khi tôi nói thẳng thì nó vẫn đi đường vòng.
tức giận

Trên thực tế, tôi chỉ đọc bài viết trên gamedev.stackexchange.com/questions/8087/ và nó dường như hoạt động bằng cách tìm tuyến đường với A *, sau đó tính toán chi phí thực sự của nó bằng thuật toán kênh được sửa đổi và sau đó tìm tuyến đường khác và tính toán nó chi phí thực sự một lần nữa và xem nếu nó là bất kỳ ngắn hơn so với những người khác. Nó lặp đi lặp lại cho đến khi nó biết nó tìm thấy con đường ngắn nhất. Điều này thực sự giải quyết vấn đề của tôi, tuy nhiên, điều này có vẻ như sẽ khá chậm vì bạn đang lặp lại cả việc tìm đường thẳng và tìm đường, sẽ khá tốn kém.
tức giận

Lưu trữ đa giác: chỉ lưu trữ các đa giác hiển thị - hoặc liên kết thẻ với mỗi đa giác (hãy nhớ mỗi đa giác sẽ cần phải là một danh sách các đỉnh của hình tròn); tương tự với các nút, bạn có thể lưu trữ ID của đa giác mà chúng bắt nguồn từ - nhưng tôi không cần phải nói với bạn điều này: đó là lưu trữ dữ liệu cơ bản. Cuối cùng tại sao bạn quan tâm đến con đường ngắn nhất thực sự? Trò chơi của bạn có thể chạy chó chậm hoặc bạn có thể có đường dẫn hơi không chính xác: chọn một. Lấy đường dẫn ngắn nhất thực sự YÊU CẦU một tìm kiếm đầu tiên đầy đủ (ít nhất là trên biểu đồ nút).
Jonathan Dickinson

@JonathanDickinson Tôi biết tôi không cần một con đường mà sẽ là 100% chính xác để pixel cuối cùng, và tôi biết tôi có thể sử dụng A * để sản xuất đường dẫn sẽ có mặt tại hầu hết các p chấp nhận. Điều này đang đi một chặng đường dài vượt qua một chướng ngại vật rất rõ ràng, như trong câu hỏi trước đây của tôi về lỗi tràn stack hoặc trong gamedev.stackexchange.com/questions/8087/ù đơn giản là quá nhiều. Tôi không thể để AI của mình đi trên một chướng ngại vật!
tức giận

Câu trả lời:


14

Tôi sẽ khuyên rằng ngay cả khi bạn sẽ viết tất cả mã của riêng mình, bạn hãy tải xuống Recast và xây dựng ứng dụng mẫu vì nó có trực quan hiển thị navmesh được tạo và nó cho phép bạn kiểm tra tìm đường bằng một điểm đơn giản và nhấp giao diện. Bạn có thể học được rất nhiều chỉ bằng cách chơi với nó.

Như bạn đã nhận ra, có hai bước để tạo ra một đường dẫn đẹp mắt - công cụ tìm đường dẫn A * và sau đó là quá trình xử lý hậu kỳ tiếp theo bao gồm đường thẳng (loại bỏ bất kỳ ngã rẽ nào không cần thiết để tránh chướng ngại vật) và cũng có thể là thêm các đường cong tại các điểm rẽ.

Tìm đường

Bạn đã thành thạo phần A *, điều đó thật tuyệt. Bạn cũng đã thực hiện quan sát rằng A * sẽ không luôn luôn tìm thấy con đường thẳng nhất. Điều quan trọng cần hiểu là điều này là do A * là một thuật toán để tìm đường đi ngắn nhất qua biểu đồ (là một khái niệm toán học trong đó các nút là không thứ nguyên) khi bạn áp dụng nó vào lưới, bằng cách nào đó bạn phải ánh xạ các nút thành các phần tử lưới.

Điều rõ ràng nhất để làm là điều hướng từ điểm trung tâm đa giác đến điểm trung tâm và căn cứ vào chi phí cho khoảng cách này, nhưng điều này có một số vấn đề. Một là nó sẽ không luôn luôn tìm thấy con đường ngắn nhất về mặt hình học và thứ hai là nếu bạn thử và đi theo con đường bạn đã tính, bạn sẽ nhận thấy rằng một đường thẳng từ trung tâm này đến trung tâm tiếp theo có thể đi qua một đa giác không 'một phần của đường dẫn (và có thể không thể điều hướng được). Đây không phải là một cách khủng khiếp để chi phí cho biểu đồ truyền tải trong khi thực hiện A * nhưng rõ ràng nó không phù hợp cho bất kỳ mục đích truyền tải nào.

Giải pháp đơn giản tiếp theo là thực hiện A * từ cạnh này sang mép kia qua lưới. Bạn sẽ thấy điều này đơn giản hơn để suy nghĩ nếu bạn tưởng tượng rằng thay vì một nút trên mỗi đa giác, bạn có một đa giác trên mỗi cạnh. Vì vậy, đường dẫn của bạn đi từ điểm bắt đầu của bạn đến ngay bên trong cạnh gần nhất, đi qua bên trong cạnh của đa giác liền kề và sau đó đến bên trong cạnh tiếp theo trong cùng một đa giác đó, v.v. Điều này tạo ra con đường ngắn nhất thường xuyên hơn và cũng có lợi ích là có thể đi qua nếu bạn không muốn thực hiện bước đi thẳng.

Đường thẳng

Thuật toán được sử dụng trong Detour (thư viện điều hướng đi kèm với Recast) khá đơn giản. Bạn nên quan sát rằng nó sẽ chỉ làm thẳng đường đi trong giới hạn của đa giác được tìm thấy trong tìm kiếm A *. Như vậy, nếu điều đó không tìm thấy con đường hẹp nhất xung quanh một chướng ngại vật, bạn cũng sẽ không có được một con đường chặt chẽ sau khi chạy thuật toán đó. Trong thực tế, các điều hướng được tạo ra bởi recast có xu hướng có một đa giác duy nhất mà bạn có thể đi qua khi điều hướng một điểm bị sặc (điểm gần nhất giữa hai chướng ngại vật) và vì vậy A * sẽ luôn tạo ra một danh sách các nút gần với chướng ngại vật như khả thi. Nếu bạn đang sử dụng gạch làm navmesh, đây sẽ không phải là trường hợp và thuật toán rất đơn giản này sẽ chèn các lượt giả.

Thuật toán làm thẳng đường đi của Detour không phức tạp lắm O (n) bởi vì khi xác định rằng nó cần chèn một ngã rẽ, nó sẽ chèn nó vào điểm cuối cùng thắt chặt phễu sang trái (khi rẽ trái và ngược lại) và sau đó bắt đầu truy tìm các nút từ điểm đó một lần nữa.

Nếu bạn muốn đi thẳng con đường bên ngoài các đa giác tạo thành một phần của tuyến A *, mọi thứ trở nên phức tạp hơn rất nhiều. Bạn sẽ cần phải thực hiện thói quen truyền tia có thể kiểm tra xem hai điểm trong điều hướng của bạn có thể nhìn thấy nhau hay không (dù sao bạn cũng nên có điều này để bạn có thể xem bạn có cần sử dụng A * không). Bạn làm điều này bằng cách giao cắt đoạn đường được hình thành bởi origin-> đích với các cạnh kết nối của đa giác chứa gốc, sau đó kiểm tra các cạnh kết nối của đa giác di chuyển bạn vào và cứ thế. Nếu bạn cắt một cạnh không kết nối (tôi gọi chúng là các cạnh biên), thì bạn đã gặp một trở ngại.

Sau đó, bạn có thể thực hiện kiểm tra truyền tia này bất cứ khi nào thuật toán phân kênh xác định nó cần chèn một lượt để xem có thực sự không, nhưng tôi nghĩ bạn sẽ phải tiếp tục thực hiện kiểm tra đó ở mọi nút cho đến khi bạn thực hiện lần lượt (tại điểm nào bạn có thể trở lại thuật toán phễu đơn giản). Điều đó sẽ trở nên đắt đỏ, khiến đường dẫn đi thẳng khoảng O (n ^ 2).

Đại diện cho hải quân

Bạn có thể biểu diễn lưới của bạn dưới dạng một mảng các lớp đa giác. Lớp đa giác có thể đơn giản như một mảng các đỉnh và một mảng các tham chiếu đến đa giác liền kề cho mỗi cạnh nếu có một đỉnh. Tất nhiên bạn có thể có thể nghĩ ra cách để lưu trữ đó gọn hơn. Vì một đỉnh thường được chia sẻ bởi một số đa giác, nên việc có một mảng lớn các đỉnh và sau đó có mỗi chỉ số lưu trữ đa giác vào mảng đó là bình thường. Tùy thuộc vào đặc điểm của điều hướng của bạn, bạn có thể có số cạnh kết nối trung bình chỉ bằng 50% hoặc ít hơn số cạnh. Trong trường hợp đó, bạn có thể muốn lưu trữ một liên kết đến một đa giác khác và chỉ mục của cạnh thay vì lưu trữ một liên kết cho mọi cạnh. Ngoài ra tôi khuyên bạn nên lưu trữ chỉ mục của đa giác trong mảng đa giác của navmesh thay vì sử dụng tham chiếu lớp.


Tôi vừa mới đọc về điều này, nhưng tôi hiểu bạn không bao giờ nên sử dụng bình phương khoảng cách (hoặc không phải căn bậc hai) cho A *: theory.stanford.edu/~amitp/GameProgramming/ giác
tức giận

Tôi không thực sự quan tâm đến việc làm thế nào để thực sự đi về con đường thẳng atm, điều tôi quan tâm là những gì bạn nói: "Bạn nên quan sát rằng nó sẽ chỉ đi thẳng con đường trong giới hạn của đa giác tìm thấy trong tìm kiếm A * Như vậy, nếu điều đó không tìm thấy con đường hẹp nhất xung quanh một chướng ngại vật, bạn cũng sẽ không có được một con đường chặt chẽ sau khi chạy thuật toán đó. "
tức giận

Tôi muốn có một lưới điều hướng trong đó A * sẽ luôn tìm thấy con đường mà một khi đi thẳng là ngắn nhất, bất kể chi phí di chuyển qua các đỉnh / điểm giữa. Tôi đánh giá cao việc này có thể được thực hiện với biểu đồ khả năng hiển thị nhưng tôi muốn sử dụng navmesh vì nó có rất nhiều lợi ích khác và vì độ phức tạp của biểu đồ khả năng hiển thị có thể phát triển rất nhanh: theory.stanford.edu/~amitp/GameProgramming/
tức giận

@theguywholikelinux bạn có thể sử dụng khoảng cách Euclide sqrt(x*x + y*y)- nhưng không phải là mỗi nút rẻ hơn x*x + y*y.
Jonathan Dickinson

@JonathanDickinson Tôi biết, do đó quan điểm của tôi.
tức giận
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.