Triển khai dây quấn (như Dây Ninja Worms) trong động cơ vật lý 2D


34

Gần đây tôi đã thử một số vật lý dây thừng và tôi thấy rằng giải pháp "tiêu chuẩn" - tạo ra một sợi dây từ một loạt các vật thể được nối với nhau bằng lò xo hoặc khớp - là không thỏa mãn. Đặc biệt là khi đu dây có liên quan đến trò chơi. Tôi không thực sự quan tâm đến khả năng quấn hay chùng của một sợi dây (dù sao điều này cũng có thể bị làm giả để tạo hình ảnh).

Đối với trò chơi, điều quan trọng là khả năng dây thừng quấn quanh môi trường và sau đó mở ra. Nó thậm chí không phải hoạt động giống như dây thừng - một "sợi dây" được tạo thành từ các đoạn thẳng sẽ làm. Đây là một minh họa:

Ninja dây, quấn quanh chướng ngại vật

Điều này rất giống với "Ninja Rope" từ trò chơi Worms.

Bởi vì tôi đang sử dụng một công cụ vật lý 2D - môi trường của tôi được tạo thành từ các đa giác lồi 2D. (Cụ thể tôi đang sử dụng SAT trong Farseer.)

Vì vậy, câu hỏi của tôi là: Làm thế nào bạn sẽ thực hiện hiệu ứng "gói"?

Có vẻ như khá rõ ràng rằng dây sẽ được tạo thành từ một loạt các phân đoạn dòng "tách" và "tham gia". Và đoạn cuối cùng (hoạt động) của dòng đó, nơi đối tượng chuyển động gắn vào, sẽ là khớp có độ dài cố định.

Nhưng toán học / thuật toán liên quan đến việc xác định thời điểm và nơi phân khúc dòng hoạt động cần được phân chia là gì? Và khi nào cần tham gia với phân khúc trước?

(Trước đây câu hỏi này cũng đã hỏi về việc thực hiện điều này cho một môi trường năng động - Tôi đã quyết định tách câu hỏi đó thành các câu hỏi khác.)

Câu trả lời:


18

Để xác định thời điểm chia dây, bạn phải nhìn vào khu vực mà dây bao phủ từng khung. Những gì bạn làm là bạn thực hiện kiểm tra va chạm với khu vực được bao phủ và hình dạng cấp độ của bạn. Khu vực mà một chiếc xích đu phải là một vòng cung. Nếu có va chạm, bạn cần tạo một đoạn mới cho sợi dây. Kiểm tra các góc va chạm với vòng cung đong đưa. Nếu có nhiều góc va chạm với vòng cung xoay, bạn nên chọn một góc trong đó góc giữa sợi dây trong khung trước đó và điểm va chạm là nhỏ nhất.

Sơ đồ hữu ích của tình huống dây ninja

Cách bạn thực hiện phát hiện va chạm là đối với gốc của đoạn dây hiện tại, O, vị trí kết thúc của sợi dây trên khung trước đó, A, vị trí kết thúc của dây trên khung hiện tại, B và mỗi điểm góc P theo hình đa giác hình học mức, bạn tính toán (OA x OP), (OP x OB) và (OA x OB), trong đó "x" đại diện cho việc lấy tọa độ Z của sản phẩm chéo giữa hai vectơ. Nếu cả ba kết quả có cùng dấu, âm hoặc dương và chiều dài của OP nhỏ hơn chiều dài của đoạn dây, điểm P nằm trong khu vực được bao phủ bởi xích đu và bạn nên chia dây. Nếu bạn có nhiều điểm góc va chạm, bạn sẽ muốn sử dụng điểm đầu tiên chạm vào sợi dây, nghĩa là điểm mà góc giữa OA và OP là nhỏ nhất. Sử dụng sản phẩm chấm để xác định góc.

Đối với việc tham gia các phân khúc, hãy so sánh giữa phân khúc trước và cung của phân khúc hiện tại của bạn. Nếu phân khúc hiện tại đã xoay từ bên trái sang bên phải hoặc ngược lại, bạn nên tham gia các phân khúc.

Đối với toán học để tham gia các phân đoạn, chúng tôi sẽ sử dụng điểm đính kèm của phân đoạn dây trước đó, Q, cũng như các điểm chúng tôi có cho trường hợp phân tách. Vì vậy, bây giờ, bạn sẽ muốn so sánh các vectơ QO, OA và OB. Nếu dấu của (QO x OA) khác với dấu của (QO x OB), thì dây đã đi từ trái sang phải hoặc ngược lại và bạn nên tham gia các phân đoạn. Điều này tất nhiên cũng có thể xảy ra nếu sợi dây xoay 180 độ, vì vậy nếu bạn muốn sợi dây có thể quấn quanh một điểm trong không gian thay vì hình đa giác, bạn có thể muốn thêm một trường hợp đặc biệt cho điều đó.

Phương pháp này tất nhiên giả định rằng bạn đang thực hiện phát hiện va chạm cho đối tượng treo trên dây, để nó không kết thúc bên trong hình dạng cấp.


1
Vấn đề với cách tiếp cận này là các lỗi chính xác của dấu phẩy động khiến cho sợi dây có thể "đi qua" một điểm.
Andrew Russell

16

Lâu lâu tôi mới chơi Worms, nhưng từ những gì tôi nhớ - khi sợi dây quấn quanh mọi thứ, chỉ có một phần (thẳng) của sợi dây di chuyển bất cứ lúc nào. Phần còn lại của dây trở nên tĩnh

Vì vậy, có rất ít vật lý thực tế liên quan. Phần hoạt động có thể được mô hình hóa như một lò xo cứng duy nhất với khối lượng ở cuối

Bit thú vị sẽ là logic để tách / nối các phần không hoạt động của dây đến / từ phần hoạt động.

Tôi tưởng tượng có 2 thao tác chính:

'Tách' - Sợi dây đã giao nhau một cái gì đó. Chia nó tại giao lộ thành một phần không hoạt động và phần mới, ngắn hơn, hoạt động

'Tham gia' - Sợi dây hoạt động đã di chuyển đến vị trí nơi giao lộ gần nhất không còn tồn tại (đây có thể chỉ là thử nghiệm sản phẩm góc / chấm đơn giản?). Tham gia lại 2 phần, tạo phần mới, dài hơn, hoạt động

Trong một cảnh được xây dựng từ các đa giác 2D, tất cả các điểm phân chia phải ở một đỉnh trên lưới va chạm. Phát hiện va chạm có thể đơn giản hóa thành một thứ gì đó dọc theo dòng 'Nếu sợi dây đi qua một đỉnh trên bản cập nhật này, hãy tách / nối dây ở đỉnh đó?


2
Anh chàng này đã đúng ngay tại chỗ ... Thật ra, đó không phải là một mùa xuân "cứng", bạn chỉ xoay một số đường thẳng xung quanh ...
speeder

Câu trả lời của bạn là đúng kỹ thuật. Nhưng tôi giả định rằng có các phân đoạn dòng và tách và tham gia chúng là rõ ràng. Tôi quan tâm đến thuật toán / toán học thực tế để làm điều đó. Tôi đã làm cho câu hỏi của tôi cụ thể hơn.
Andrew Russell

3

Kiểm tra cách dây ninja ở Gusanos được thực hiện:

  • Sợi dây hoạt động như một hạt cho đến khi nó gắn vào một cái gì đó.
  • Sau khi gắn vào, sợi dây chỉ cần tác dụng một lực lên con sâu.
  • Gắn vào các đối tượng động (như các loại sâu khác) vẫn là TODO: trong mã này.
  • Tôi không thể nhớ lại nếu quấn quanh các vật / góc được hỗ trợ ...

Đoạn trích có liên quan từ ninjarope.cpp :


void NinjaRope::think()
{
    if ( m_length > game.options.ninja_rope_maxLength )
        m_length = game.options.ninja_rope_maxLength;

    if (!active)
        return;

    if ( justCreated && m_type->creation )
    {
        m_type->creation->run(this);
        justCreated = false;
    }

    for ( int i = 0; !deleteMe && i < m_type->repeat; ++i)
    {
        pos += spd;

        BaseVec<long> ipos(pos);

        // TODO: Try to attach to worms/objects

        Vec diff(m_worm->pos, pos);
        float curLen = diff.length();
        Vec force(diff * game.options.ninja_rope_pullForce);

        if(!game.level.getMaterial( ipos.x, ipos.y ).particle_pass)
        {
            if(!attached)
            {
                m_length = 450.f / 16.f - 1.0f;
                attached = true;
                spd.zero();
                if ( m_type->groundCollision  )
                    m_type->groundCollision->run(this);
            }
        }
        else
            attached = false;

        if(attached)
        {
            if(curLen > m_length)
            {
                m_worm->addSpeed(force / curLen);
            }
        }
        else
        {
            spd.y += m_type->gravity;

            if(curLen > m_length)
            {
                spd -= force / curLen;
            }
        }
    }
}

1
Uhmn ... điều này dường như không trả lời câu hỏi của tôi cả. Toàn bộ câu hỏi của tôi là quấn một sợi dây quanh một thế giới được làm bằng đa giác. Gusanos dường như không có sự bao bọc và một thế giới bitmap.
Andrew Russell

1

Tôi e rằng tôi không thể đưa cho bạn một thuật toán cụ thể trên đỉnh đầu, nhưng với tôi, chỉ có hai điều quan trọng để phát hiện va chạm cho dây ninja: bất kỳ và tất cả các đỉnh có khả năng va chạm vào chướng ngại vật trong bán kính "chia" cuối cùng bằng với độ dài còn lại của đoạn; và hướng xoay hiện tại (theo chiều kim đồng hồ hoặc ngược chiều kim đồng hồ). Nếu bạn đã tạo một danh sách các góc tạm thời từ đỉnh "chia" cho từng đỉnh gần đó, thuật toán của bạn sẽ chỉ cần quan tâm nếu phân đoạn của bạn sắp vượt qua góc đó cho bất kỳ đỉnh nào. Nếu đúng như vậy, thì bạn cần thực hiện một thao tác phân tách, dễ như ăn bánh - Đó chỉ là một dòng từ đỉnh phân tách cuối cùng đến phân tách mới, và sau đó một phần còn lại mới được tính.

Tôi nghĩ rằng chỉ có các đỉnh. Nếu bạn có nguy cơ đâm vào một đoạn giữa các đỉnh trên một chướng ngại vật, thì việc phát hiện va chạm bình thường của bạn đối với anh chàng treo ở đầu sợi dây sẽ phát ra. Nói cách khác, sợi dây của bạn sẽ không bao giờ bị "giật" dù sao đi nữa, vì vậy các phân đoạn giữa sẽ không thành vấn đề.

Xin lỗi tôi không có bất cứ điều gì cụ thể, nhưng hy vọng rằng điều đó sẽ đưa bạn đến nơi bạn cần, về mặt khái niệm, để thực hiện điều này. :)


1

Đây là một bài đăng có liên kết đến các bài báo về các loại mô phỏng tương tự (trong bối cảnh kỹ thuật / học thuật thay vì cho các trò chơi): https://gamedev.stackexchange.com/a/10350/6398

Tôi đã thử ít nhất hai cách tiếp cận khác nhau để phát hiện va chạm + phản ứng cho loại mô phỏng "dây" này (như đã thấy trong trò chơi Umihara Kawase); ít nhất, tôi nghĩ rằng đây là những gì bạn đang theo đuổi - dường như không có một thuật ngữ cụ thể nào cho loại mô phỏng này, tôi chỉ có xu hướng gọi nó là "dây" chứ không phải là "dây" coi "sợi dây" đồng nghĩa với "một chuỗi hạt". Và, nếu bạn muốn hành vi dính của dây ninja (tức là nó có thể đẩy VÀ kéo), thì đây giống như một sợi dây cứng hơn là một sợi dây. Dù sao..

Câu trả lời của Pekuja là tốt, bạn có thể thực hiện phát hiện va chạm liên tục bằng cách giải quyết trong thời gian khi diện tích đã ký của ba điểm là 0.

(Tôi không thể nhớ lại hoàn toàn OTOH nhưng bạn có thể tiếp cận nó như sau: tìm thời điểm t khi điểm a được chứa trong dòng đi qua b, c, (Tôi nghĩ rằng tôi đã làm điều này bằng cách giải quyết khi dấu chấm (ab, cb) = 0 để tìm giá trị của t) và sau đó đưa ra thời gian hợp lệ 0 <= t <1, tìm vị trí tham số s của a trên đoạn bc, tức là a = (1-s) b + s c và nếu a nằm giữa b và c (tức là nếu 0 <= s <= 1) thì đó là một xung đột hợp lệ.

AFAICR bạn cũng có thể tiếp cận nó theo cách khác (nghĩa là giải quyết cho s và sau đó cắm cái này vào để tìm t) nhưng nó ít trực quan hơn nhiều. (Tôi xin lỗi nếu điều này không có ý nghĩa gì, tôi không có thời gian để tìm hiểu các ghi chú của mình và đã vài năm rồi!))

Vì vậy, bây giờ bạn có thể tính toán tất cả các lần xảy ra sự kiện (nghĩa là các nút dây phải được chèn hoặc loại bỏ); xử lý sự kiện sớm nhất (chèn hoặc loại bỏ một nút) và sau đó lặp lại / lặp lại cho đến khi không còn sự kiện nào nữa giữa t = 0 và t = 1.

Một cảnh báo về cách tiếp cận này: nếu các vật mà sợi dây có thể quấn quanh là động (đặc biệt là nếu bạn mô phỏng chúng VÀ tác động của chúng lên sợi dây và ngược lại) thì có thể có vấn đề nếu các vật đó kẹp / đi qua từng vật khác - dây có thể bị rối. Và chắc chắn sẽ rất khó khăn để ngăn chặn loại tương tác / chuyển động này (các góc của các vật thể trượt qua nhau) trong một mô phỏng vật lý kiểu box2d .. một lượng nhỏ sự xâm nhập giữa các vật thể là hành vi bình thường trong bối cảnh đó.

(Ít nhất .. đây là một vấn đề với một trong những triển khai "dây" của tôi.)

Một giải pháp khác, ổn định hơn nhiều nhưng lại bỏ lỡ một số va chạm trong một số điều kiện nhất định là chỉ sử dụng các thử nghiệm tĩnh (nghĩa là không lo lắng về việc đặt hàng theo thời gian, chỉ cần chia nhỏ đệ quy từng phân đoạn khi bạn tìm thấy chúng), có thể mạnh mẽ hơn nhiều - dây sẽ không bị rối ở các góc và một lượng nhỏ xuyên thấu sẽ ổn.

Tôi nghĩ cách tiếp cận của Pekuja cũng hiệu quả với điều này, tuy nhiên có những cách tiếp cận khác. Một cách tiếp cận tôi đã sử dụng là thêm dữ liệu va chạm phụ trợ: tại mỗi đỉnh lồi v trên thế giới (nghĩa là các góc của hình dạng mà sợi dây có thể quấn quanh), thêm một điểm u tạo thành đường thẳng uv hướng, trong đó bạn là một số điểm "bên trong góc" (tức là bên trong thế giới, "phía sau" v; để tính u bạn có thể chiếu một tia vào trong từ v dọc theo nội suy của nó và dừng một khoảng cách sau v hoặc trước khi tia giao nhau với một cạnh của thế giới và thoát khỏi vùng rắn. Hoặc, bạn chỉ có thể vẽ thủ công các phân đoạn vào thế giới bằng cách sử dụng công cụ trực quan / trình chỉnh sửa cấp độ).

Dù sao, bây giờ bạn có một bộ uv "góc đường"; đối với mỗi uv và từng đoạn ab trong dây, kiểm tra xem ab và uv có giao nhau không (ví dụ: truy vấn giao nhau đường tĩnh, boolean lineseg-lineseg); nếu vậy, hãy lặp lại (tách đường thẳng ab thành av và vb, tức là chèn v), ghi lại hướng nào của sợi dây uốn tại v. Sau đó, cho mỗi cặp đường lân cận ab, bc trong dây, kiểm tra xem hướng uốn hiện tại tại b giống như khi b được tạo ra (tất cả các bài kiểm tra "hướng uốn cong" này chỉ là các bài kiểm tra khu vực đã ký); nếu không, hợp nhất hai phân đoạn thành ac (tức là loại bỏ b).

Hoặc có thể tôi đã hợp nhất và sau đó chia tách, tôi quên - nhưng nó chắc chắn hoạt động trong ít nhất một trong hai đơn đặt hàng có thể! :)

Với tất cả các phân đoạn dây được tính cho khung hiện tại, sau đó bạn có thể mô phỏng giới hạn khoảng cách giữa hai điểm cuối dây (và thậm chí bạn có thể liên quan đến các điểm bên trong, tức là các điểm tiếp xúc giữa dây và thế giới, nhưng liên quan nhiều hơn một chút ).

Dù sao, hy vọng điều này sẽ được sử dụng ... các bài viết trong bài tôi liên kết cũng sẽ cung cấp cho bạn một số ý tưởng.


0

Một cách tiếp cận này là mô hình sợi dây như các hạt có thể va chạm, được nối với nhau bằng lò xo. (những người khá cứng, thậm chí có thể chỉ là một xương thay thế). Các hạt va chạm với môi trường, đảm bảo dây quấn quanh các vật phẩm.

Đây là bản demo với nguồn: http://www.ewjordan.com/rgbDemo/

(Di chuyển sang bên phải ở cấp độ đầu tiên, có một sợi dây màu đỏ bạn có thể tương tác)


2
Uh - đây là cụ thể những gì tôi không muốn (xem câu hỏi).
Andrew Russell

À. Điều đó không rõ ràng từ câu hỏi ban đầu. Cảm ơn đã dành thời gian để làm rõ nó rất nhiều. .
Rachel Blum
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.