Vòng tròn bên trong va chạm vòng tròn


9

Trong một trong những dự án của tôi, tôi có một khu vực trò chơi theo hình tròn. Bên trong vòng tròn này một vòng tròn nhỏ khác đang di chuyển xung quanh. Những gì tôi muốn làm là giữ cho vòng tròn nhỏ không di chuyển bên ngoài vòng tròn lớn hơn. Dưới đây bạn có thể thấy rằng trong khung 2, vòng tròn nhỏ nằm bên ngoài, tôi cần một cách để di chuyển nó trở lại ngay trước khi nó sắp di chuyển ra ngoài. Điều này có thể giải quyết như thế nào?

Ví dụ cơ bản

Ngoài ra, tôi cần điểm va chạm dọc theo vòng cung của vòng tròn lớn để tôi có thể cập nhật vận tốc của vòng tròn nhỏ. Làm thế nào một người sẽ đi về tính toán điểm này?

Những gì tôi muốn làm là trước khi di chuyển vòng tròn nhỏ, tôi dự đoán vị trí tiếp theo của nó và nếu nó ở bên ngoài tôi tìm thấy thời gian va chạm giữa t = 0 và t = 1 (t = 1 bước toàn thời gian). Nếu tôi có thời gian va chạm t thì tôi chỉ di chuyển vòng tròn nhỏ trong t thay vì bước toàn thời gian. Nhưng một lần nữa, vấn đề là tôi không biết cách phát hiện tại thời điểm va chạm xảy ra khi có hai vòng tròn và một vòng tròn nằm trong vòng tròn kia.

BIÊN TẬP:

Ví dụ về điểm va chạm (màu xanh lá cây) tôi muốn tìm. Có thể hình ảnh là một chút tắt nhưng bạn có được ý tưởng.

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

Câu trả lời:


10

Giả sử vòng tròn lớn có tâm Avà bán kính Rvà vòng tròn nhỏ có tâm Bvà bán kính rdi chuyển về phía vị trí C.

Có một cách thanh lịch để giải quyết vấn đề này, đó là sử dụng tổng số Minkovski (trừ, thực tế): thay thế đĩa bán kính Rbằng đĩa bán kính R-rvà đĩa bán kính rbằng đĩa bán kính 0, tức là. một điểm đơn giản nằm ở B. Vấn đề trở thành một vấn đề giao nhau đường tròn.

Sau đó, bạn chỉ cần kiểm tra xem khoảng cách ACcó nhỏ hơn không R-r. Nếu có, các vòng tròn không va chạm. Nếu nó lớn, chỉ cần tìm thấy những điểm Dtrên BCở khoảng cách R-rcủa Avà đây là vị trí mới của trung tâm của vòng tròn nhỏ của bạn. Điều này tương đương với việc tìm kiếm knhư vậy:

  vec(BD) = k*vec(BC)
and
  norm(vec(AD)) = R-r

Thay thế vec(AD)bằng vec(AB) + vec(BD)cho:

AB² + k² BC² + 2k vec(AB).vec(BC) = (R-r

Với vị trí ban đầu là bên trong vòng tròn lớn, phương trình bậc hai knày có một gốc dương. Đây là cách giải phương trình, trong mã giả:

b = - vec(AB).vec(BC) / BC²    // dot product
c = (AB² - (R-r)²) / BC²
d = b*b - c
k = b - sqrt(d)
if (k < 0)
    k = b + sqrt(d)
if (k < 0)
    // no solution! we must be slightly out of the large circle

Với giá trị này k, trung tâm mới của vòng tròn nhỏ là Dnhư vậy BD = kBC.

Chỉnh sửa : thêm giải phương trình bậc hai


Cảm ơn, nó trông thanh lịch nhưng tôi không chắc là tôi hiểu. Ví dụ: "chỉ cần tìm điểm D trên BC ở khoảng cách Rr của A". Tôi đã vẽ một bức tranh để cố gắng hiểu rõ hơn. Vì vậy, nếu chúng ta bắt đầu tại B (AX, AY- (Rr)) và C là nơi chúng ta sẽ kết thúc với vận tốc hiện tại. Cách tôi hiểu văn bản được trích dẫn: Tìm một điểm D trên đoạn thẳng BC cách khoảng cách Rr so với A. Nhưng cách tôi nhìn thấy nó trên hình tôi đã vẽ là chỉ chính xác B là Rr cách xa A. Tất cả điểm khác sẽ là> Rr đi từ A. Tôi đang thiếu gì?
dbostream

@dbostream Bạn không thiếu thứ gì. Nếu hai vòng tròn đã tiếp xúc thì không có xung đột thực sự để phát hiện : va chạm xảy ra trong Bk=0. Bây giờ nếu đó là độ phân giải va chạm mà bạn muốn, tôi đã không đề cập đến điều đó trong câu trả lời của mình bởi vì nó sẽ đòi hỏi kiến ​​thức về các tính chất vật lý của các đối tượng. Điều gì sẽ xảy ra? Vòng tròn bên trong có nên nảy bên trong? Hay cuộn? Quét?
sam hocevar

Tôi muốn vòng tròn nhỏ bắt đầu trượt dọc theo vòng cung của vòng tròn lớn. Vì vậy, nếu tôi không nhầm, tôi muốn điểm va chạm trên vòng cung của vòng tròn lớn để tôi có thể sử dụng bình thường của nó để cập nhật vận tốc.
dbostream

@dbostream nếu chuyển động nên bị hạn chế theo cách như vậy thì tôi khuyên bạn nên tuân theo ràng buộc đó càng sớm càng tốt: nếu vận tốc là V, hãy làm cho vòng tròn bên trong tiến V*tdọc theo chu vi của R-rvòng tròn. Điều này có nghĩa là một vòng quay V*t/(R-r)radian góc xung quanh điểm A. Và vectơ vận tốc có thể được quay theo cùng một cách. Không cần biết bình thường (luôn luôn hướng về trung tâm của vòng tròn) hoặc cập nhật vận tốc theo bất kỳ cách nào khác.
sam hocevar

Tôi vẫn cần di chuyển vòng tròn nhỏ đến điểm va chạm trước khi quay. Và khi tôi cố gắng xoay vị trí bằng ma trận xoay, vị trí mới không chính xác (nhưng gần như) Rr ra khỏi trung tâm của vòng tròn lớn, nhưng sự khác biệt nhỏ đó là đủ để thử nghiệm va chạm của tôi thất bại trong lần chạy tiếp theo. Tôi có phải xoay vị trí để tìm vị trí mới không, có thể sử dụng các phép toán vectơ như bạn có thể nếu có thứ gì đó va chạm với một bức tường thẳng không?
dbostream

4

Giả sử hình tròn lớn là hình tròn A và hình tròn nhỏ là hình tròn B.

Kiểm tra xem B có ở trong A không:

distance = sqrt((B.x - A.x)^2 + (B.y - A.y)^2))
if(distance > A.Radius + B.Radius) { // B is outside A }

Nếu trong khung n-1B ở bên trong A và trong khung nB nằm ngoài A và thời gian giữa các khung không quá lớn (hay còn gọi là B không di chuyển quá nhanh), chúng ta có thể ước chừng điểm va chạm bằng cách chỉ tìm tọa độ Descartes của B đến A:

collision.X = B.X - A.X;
collision.Y = B.Y - A.Y;

Sau đó chúng ta có thể chuyển đổi điểm này thành một góc:

collision.Normalize(); //not 100% certain if this step is necessary     
radians = atan2(collision.Y, collision.X)

Nếu bạn muốn biết chính xác hơn tB ở bên ngoài A lần đầu tiên bạn có thể thực hiện giao điểm vòng tròn tia ở mọi khung hình và sau đó so sánh nếu khoảng cách từ B đến điểm va chạm lớn hơn thì khoảng cách B có thể đi được không tốc độ hiện tại. Nếu vậy bạn có thể tính toán thời gian va chạm chính xác.


Cảm ơn, nhưng nó có thực sự chính xác khi bắn một tia từ trung tâm của vòng tròn nhỏ khi thực hiện bài kiểm tra giao nhau đó không? Chúng ta sẽ không kết thúc với kịch bản ở giữa bức tranh này chứ? Ý tôi là điểm đầu tiên trên vòng cung của vòng tròn nhỏ va chạm với vòng tròn lớn không nhất thiết là điểm trên vòng cung theo hướng tốc độ. Tôi nghĩ rằng tôi cần một cái gì đó giống như trong kịch bản dưới cùng của hình ảnh mà tôi liên kết đến. Tôi đã thêm một hình ảnh mới trong bài đăng đầu tiên cho thấy một ví dụ về những gì tôi nghĩ rằng tôi cần.
dbostream

Hmm tôi cho rằng kịch bản là có thể. Có thể kiểm tra với một vòng tròn C mới có B.Radius + chuyển động tối đa của B khung này, kiểm tra xem nó có va chạm với A không và sau đó tập trung vào điểm C trên đó là A. (Không thử btw này)
Roy T.

3
Sử dụng ít từ hơn: if (distance (A, B))> (Ra-Rb) xảy ra va chạm và bạn chỉ cần di chuyển vòng tròn nhỏ để có khoảng cách bằng Ra-Rb. Khác, bạn di chuyển vòng tròn nhỏ bình thường. Nhân tiện, @dbostream bạn đang sử dụng một cái gì đó tương tự như một dạng Danh bạ đầu cơ được đơn giản hóa, hãy thử tìm kiếm nó.
Darkwings

@Darkwings +1 bạn hoàn toàn đúng và điều đó nghe có vẻ đơn giản hơn nhiều!
Roy T.

Nghe có vẻ đơn giản vì tôi đã loại bỏ tất cả các hình dạng cơ bản cần thiết. Thay vì đặt tên là 'va chạm', bạn có thể đặt tên cho nó là ràng buộc vì đó thực sự là: vectơ tự do AB bị ràng buộc với (0,0). Khi bạn bình thường hóa, bạn nhận được cả hai phương trình song song với bó AB của các đường thẳng và cũng là một vectơ đơn vị hữu ích. Sau đó, bạn có thể nhân vectơ đơn vị đó cho bất kỳ khoảng cách D nào và thêm các thông số mới tìm thấy vào A để tìm điểm va chạm bạn cần: C (Ax + Dx, Ay + Dy). Bây giờ nghe có vẻ phức tạp hơn nhưng đó là điều tương tự: P
Darkwings

0

Đặt (Xa, Ya) vị trí của vòng tròn lớn và đó là bán kính R, và (Xb, Yb) vị trí của vòng tròn nhỏ hơn và bán kính r.

Bạn có thể kiểm tra xem hai vòng tròn này có va chạm hay không

DistanceTest = sqrt(((Xa - Xb) ^ 2) + ((Ya - Yb) ^ 2)) >= (R - r)

Để tìm ra vị trí va chạm, hãy tìm thời điểm chính xác khi các vòng tròn va chạm, bằng cách sử dụng tìm kiếm nhị phân nhưng với một số bước cố định. Tùy thuộc vào cách trò chơi của bạn được thực hiện, bạn có thể tối ưu hóa phần mã này (tôi đã cung cấp giải pháp này độc lập với cách hoạt động của quả bóng nhỏ. Nếu nó có gia tốc liên tục hoặc tốc độ không đổi, phần mã này có thể được tối ưu hóa và thay thế bằng một công thức đơn giản).

left = 0 //the frame with no collision
right = 1 //the frame after collision
steps = 8 //or some other value, depending on how accurate you want it to be
while (steps > 0)
    checktime = left + (right - left) / 2
    if DistanceTest(checktime) is inside circle //if at the moment in the middle of the interval [left;right] the small circle is still inside the bigger one
        then left = checktime //the collision is after this moment of time
        else right = checktime //the collision is before
    steps -= 1
finaltime = left + (right - left) / 2 // the moment of time will be somewhere in between, so we take the moment in the middle of interval to have a small overall error

Khi bạn biết thời gian va chạm, hãy tính vị trí của hai vòng tròn ở lần cuối cùng và điểm va chạm cuối cùng là

CollisionX = (Xb - Xa)*R/(R-r) + Xa
CollisionY = (Yb - Ya)*R/(R-r) + Ya

0

Tôi đã thực hiện một bản demo của một quả bóng nảy trong một vòng tròn trên jsfiddle bằng thuật toán được mô tả bởi Sam Hocevar :

http://jsfiddle.net/klenwell/3ZdXf/

Đây là javascript xác định điểm liên lạc:

find_contact_point: function(world, ball) {
    // see https://gamedev.stackexchange.com/a/29658
    var A = world.point();
    var B = ball.point().subtract(ball.velocity());
    var C = ball.point();
    var R = world.r;
    var r = ball.r;

    var AB = B.subtract(A);
    var BC = C.subtract(B);
    var AB_len = AB.get_length();
    var BC_len = BC.get_length();

    var b = AB.dot(BC) / Math.pow(BC_len, 2) * -1;
    var c = (Math.pow(AB_len, 2) - Math.pow(R - r, 2)) / Math.pow(BC_len, 2);
    var d = b * b - c;
    var k = b - Math.sqrt(d);

    if ( k < 0 ) {
        k = b + Math.sqrt(d);
    }

    var BD = C.subtract(B);
    var BD_len = BC_len * k;
    BD.set_length(BD_len);

    var D = B.add(BD);
    return D;
}
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.