Phát hiện va chạm với các đường cong


12

Tôi đang làm việc trong một trò chơi 2D trong đó tôi muốn phát hiện va chạm giữa một vòng tròn chuyển động và một số loại đường cong tĩnh (có thể là đường cong Bezier).

Hiện tại trò chơi của tôi chỉ có các đường thẳng là hình học tĩnh và tôi đang thực hiện phát hiện va chạm bằng cách tính khoảng cách từ vòng tròn đến các đường và chiếu vòng tròn ra khỏi đường trong trường hợp khoảng cách nhỏ hơn bán kính vòng tròn.

Làm thế nào tôi có thể thực hiện loại phát hiện va chạm này theo cách tương đối đơn giản? Ví dụ, tôi biết rằng Box2D có tính năng phát hiện va chạm với các đường cong Bezier. Tôi không cần một cơ chế phát hiện va chạm đầy đủ tính năng, chỉ cần một cái gì đó có thể làm những gì tôi đã mô tả.


CẬP NHẬT: Cảm ơn rất nhiều cho câu trả lời tuyệt vời! Tôi sẽ phải đọc các đường cong Bezier để hiểu đầy đủ phương pháp bạn đã mô tả. Sau đó tôi sẽ lấy lại cho bạn.

Câu trả lời:


6

29/09/2012 - 23:20

Tôi đã tạo một git Repo tại đây: https://github.com/ArthurWulfWhite/Bezier-Distance/

Bạn có thể tải về các tệp nguồn dưới dạng zip từ đó. Nó cũng bao gồm một bản demo mà bạn có thể biên dịch bằng FlashDevelop. Để sử dụng bản demo, hãy mở dự án trong Flash Develop và nhấp vào 'Test Project'. Trong khi chạy bản demo, nhấp vào LMB để chọn ngẫu nhiên một đường cong Bezier mới và Vòng tròn mới.

Chúc may mắn!

Liên kết zip rất khó nhìn - chỉ cần sử dụng Ctrl + F và nhập zip. Nguồn này đại diện cho một vài tuần nghiên cứu và lập trình, tôi hy vọng bạn thích nó.


Nếu bạn có kế hoạch chia bezier theo cách đệ quy thành các phân đoạn và kiểm tra va chạm với chúng, tôi khuyên bạn nên tạo một mảng 100.100 (lưới) và đặt từng phân đoạn vào bốn ô vuông gần nhất, vì vậy bạn chỉ phải kiểm tra va chạm với 4 / 10.000 phân đoạn từng khung.

Tôi nghĩ bạn sẽ được hưởng lợi từ box2d với tư cách là một lập trình viên và là một người sáng tạo trò chơi, vì có rất nhiều trở ngại nhỏ trong việc tạo ra một công cụ vật lý 'đơn giản' làm cho chuyển động có vẻ hơi gập ghềnh và ít trôi chảy hơn.

Câu trả lời cũ: Cách thuần khiết.

Bạn thực sự có thể thấy nếu một vòng tròn đang va chạm với một đường cong Bezier, bằng cách kiểm tra khoảng cách giữa khoảng cách giữa tâm của vòng tròn và điểm gần nhất trên đường cong.

Phương trình khoảng cách (nói chung)

giải thích:

Phương trình Bezier:

q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Điều này có thể được tóm tắt đến (với một số đại số) - Tôi sẽ bỏ qua. (X, y) để dễ đọc (chúng vẫn là các điểm, không phải là một số)

q(t) = (start -2 * cont + end) t^2 + (-2 * start + 2 * control) + start

Khoảng cách từ điểm (x, y) là:

sqrt ((q(t).x - point.x)^2 + (q(t).y - point.y)^2)

Để tìm điểm gần nhất trên bezier với quả bóng, bạn cần lấy đạo hàm và tìm tất cả các điểm mà đạo hàm bằng 0 (gốc). Nó là một đa thức bậc ba, do đó bạn có thể sử dụng một công thức đóng nhưng nó có thể không đáng tin cậy vì độ chính xác của dấu phẩy động của máy tính đại diện cho các phân số có thể không đủ. Nó là tốt hơn nhiều để sử dụng Newton hoặc một cái gì đó có tính chất đó.

Đạo hàm bạn cần tìm gốc là:

Giả sử: a = start b = control c = end d = điểm trung tâm cirlce

Đạo hàm sử dụng wolfram alpha

Phần khó khăn là nhân lên điểm này, bạn phải sử dụng sản phẩm chấm.

Nếu bạn thích, tôi có mã cho điều này và tôi có thể chia sẻ nó ở đây dưới dạng một hàm chỉ đơn giản trả về boolean nếu có va chạm hay không và góc va chạm. Một số vấn đề có thể xuất hiện khi triển khai một động cơ va chạm như thế này chẳng hạn, một quả bóng chuyển động nhanh có thể bị kẹt giữa hai đường cong.

Tôi khuyên bạn nên tránh nó ngay bây giờ, chỉ cần tổng hợp các hệ số cho trục x và cho trục y và thêm chúng lên.

Việc sử dụng bất kỳ phương pháp đáng tin cậy nào bạn có thể chọn như Newton để tìm gốc, kiểm tra khoảng cách từ các điểm gốc trên bezier, 0 <= t <= 1 đến tâm vòng tròn và kiểm tra khoảng cách cho hai đầu của bezier (bắt đầu và kết thúc) đến trung tâm vòng tròn, bất cứ nơi nào gần nhất, sẽ cho bạn biết nếu có va chạm.

Nếu bán kính nhỏ hơn khoảng cách tối thiểu, có va chạm.

Góc này xấp xỉ một góc giữa tâm của vòng tròn và điểm gần nhất trên bezier.

Điều đó đang được nói, nếu bạn thực sự muốn làm một trò chơi với vật lý va chạm, tôi khuyên bạn chỉ nên lặp đi lặp lại trên bezier

    q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Chia từng mảnh ở giữa một cách đệ quy cho đến khi nó đủ nhỏ, giả sử 10 pixel trở xuống, sau đó xây dựng bezier khoảng từ các hộp và sử dụng Box2d cho vật lý vì có thể việc viết tất cả mã phát hiện va chạm này sẽ chứng tỏ là tuyệt vời thời gian chìm mà không tăng cường chơi trò chơi nhiều. Sử dụng Box2d đã chứng tỏ bản thân trong vô số dự án trong quá khứ.


Phương pháp bạn mô tả để tính điểm ngắn nhất cho đường cong chính xác là phương pháp tôi hiện đang sử dụng với các đường thay vì các đường cong. Nhưng làm tương tự cho các đường cong với phương pháp bạn giải thích nghe có vẻ hơi phức tạp. Mà theo tôi hiểu thì đó cũng là điều bạn nghĩ. Và liên quan đến Box2D. Tôi chắc chắn rằng đó là một công việc tuyệt vời. Nhưng vật lý trong trò chơi của tôi thực sự rất đơn giản và do đó tôi đã quyết định rằng một động cơ vật lý toàn diện là quá mức cần thiết.
paldepind

Có bao nhiêu đối tượng trong trò chơi của bạn? Có bao nhiêu có thể va chạm với nhau? Đôi khi sử dụng một động cơ Vật lý có thể mang lại lợi ích lớn như nó tính toán chính xác thời gian va chạm. (vì các khung là rời rạc và va chạm là có thật (không xảy ra chính xác khi bạn kết xuất khung)
AturSams

Thường là những thách thức không mong muốn khi thực hiện một cái gì đó mới và vẻ đẹp của việc sử dụng api vật lý 2d, là nó giống như sử dụng bất kỳ ngôn ngữ lập trình nào, nó không đòi hỏi nỗ lực đặc biệt của bạn ngoài việc đầu tư một vài giờ để học nó và kết quả rất khả quan.
AturSams

Tôi đã thêm một vài chi tiết ngay bây giờ, chúc may mắn. :)
AturSams

Tôi đang tạo một Elasto Mania đơn giản như trò chơi. Chỉ có ba vòng tròn chuyển động và hình học tĩnh. Toàn bộ động cơ đã hoàn thành và hoạt động tuyệt vời. Điều duy nhất còn lại là cho phép các đường cong mà tôi sắp giải quyết nhờ vào sự giúp đỡ trong câu trả lời này :) Hãy đăng mã bạn đã đề cập. Làm thế nào thích hợp để bạn nghĩ rằng nó sẽ được sử dụng trong cuộc sống thực? Tốt hơn là chuyển đổi bezier thành các dòng nhỏ?
paldepind

7

Để làm điều này, tôi sẽ:

  • Phá vỡ đường cong bezier thành các đoạn đường chính và lưu trữ chúng.

  • Đặt tất cả các phân đoạn này trong một hộp giới hạn căn chỉnh trục cho toàn bộ đường cong.

Phát hiện va chạm:

1) kiểm tra xem hình cầu có nằm trong hộp giới hạn chính không. nếu không, không va chạm.

2) nếu không, hãy kiểm tra xem có bất kỳ phân đoạn riêng lẻ nào được tính toán ở trên va chạm với hình cầu không. Xem bài viết về giao diện hình cầu Line Line từ Wikipedia .

EDIT: nếu bạn cần độ chính xác cao và muốn hiệu suất tốt, bạn cũng có thể tạo hộp giới hạn chính cho toàn bộ đường cong, sau đó chia đường cong thành hai phân đoạn (ví dụ: [0.0 - 0.5][0.5 - 1.0]). Tạo một hộp hoa cho mỗi người trong số họ, sau đó chia nhỏ từng phân đoạn này thành hai phân đoạn (do đó [0 - 0.25], [0.25 - 0.5][0.5 - 0.75], [0.75 - 1.0]). Tiếp tục như vậy cho đến khi bạn đạt đủ độ chính xác. cuối cùng, bạn sẽ có một binary treehộp giới hạn với hộp giới hạn đường cong chính ở các đoạn gốc và đường thẳng ở lá. tìm kiếm trong cây sẽ cho bạn O(log n)thay vì O(n)(trong đó n= số đoạn đường cho đường cong)


Giải pháp này có ý nghĩa với tôi và chắc chắn là dễ hiểu nhất và tôi có thể giải quyết nó. Nhưng tôi tò mò liệu có tồn tại một lựa chọn "thuần túy" hơn không.
paldepind

5

Giao điểm giữa đường thẳng và đường cong Bezier đạt được bằng toán học bằng cách chia đường cong. Điều này có nghĩa là dựa vào đặc tính thân lồi của đường cong và chia nó thành các cung nhỏ hơn với các đa giác điều khiển khác nhau theo kiểu phân chia-et-đế chế.

Bài viết này đề cập đến nó tới một điểm: http://students.cs.byu.edu/~tom/557/text/cic.pdf .

Phần thú vị là thuật toán hoạt động với bất kỳ dòng nào, bạn chỉ cần áp dụng một biến đổi cứng nhắc cho đường cong để bạn có thể coi đường đích của mình là song song với trục Ox.

Tương tự, bạn có thể kiểm tra đối với vòng tròn và đa giác của mỗi cung tròn như vậy khi bạn chia một cung Bezier thành hai cung phụ. Vòng tròn nên giao nhau với đa giác điều khiển của một cung để kiểm tra đường cong đến vòng tròn có ý nghĩa.


Tôi chưa đọc bài báo này. Nhưng làm thế nào để tôi đi từ giao điểm giữa đường thẳng và đường cong Bezier đến giao điểm giữa đường tròn và đường Bezier? Kiểm tra va chạm với một vòng tròn và một đa giác nghe có vẻ hơi phức tạp đối với tôi.
paldepind
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.