Xử lý va chạm 2D Platformer


8

Tôi đang cố gắng tạo ra một trò chơi platformer 2D (loại Mario) và tôi gặp một số vấn đề với việc xử lý va chạm đúng cách. Tôi đang viết trò chơi này bằng C ++, sử dụng SDL cho đầu vào, tải hình ảnh, tải phông chữ, vân vân. Tôi cũng đang sử dụng OpenGL thông qua thư viện FreeGLUT kết hợp với SDL để hiển thị đồ họa.

Phương pháp phát hiện va chạm của tôi là AABB (Hộp giới hạn theo trục), đây thực sự là tất cả những gì tôi cần để bắt đầu. Những gì tôi cần là một cách dễ dàng để cả hai phát hiện va chạm xảy ra ở phía nào và xử lý các va chạm đúng cách. Vì vậy, về cơ bản, nếu người chơi va chạm với đỉnh của nền tảng, hãy định vị lại anh ta lên đỉnh; nếu có va chạm sang hai bên, hãy định vị lại người chơi quay lại phía bên của vật thể; nếu có va chạm xuống đáy, hãy định vị lại người chơi dưới nền tảng.

Tôi đã thử nhiều cách khác nhau để làm điều này, chẳng hạn như cố gắng tìm độ sâu thâm nhập và định vị lại người chơi bằng độ sâu thâm nhập. Đáng buồn thay, không có gì tôi đã cố gắng dường như hoạt động chính xác. Chuyển động của người chơi cuối cùng rất rối mắt và định vị lại người chơi khi tôi không muốn. Một phần lý do có lẽ là vì tôi cảm thấy đây là một việc quá đơn giản nhưng tôi lại nghĩ quá nhiều.

Nếu bất cứ ai nghĩ rằng họ có thể giúp đỡ, xin vui lòng xem mã dưới đây và giúp tôi cố gắng cải thiện điều này nếu bạn có thể. Tôi muốn không sử dụng thư viện để xử lý việc này (vì tôi muốn tự học) hoặc một cái gì đó giống như SAT (Định lý trục tách) nếu có thể. Cảm ơn rất nhiều về sự trợ giúp của bạn!

void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
    if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
    {
        de2dObj ballPrev;
        ballPrev.coords[0] = ball.coords[0];
        ballPrev.coords[1] = ball.coords[1];
        ballPrev.coords[2] = ball.coords[2];
        ballPrev.coords[3] = ball.coords[3];
        ballPrev.coords[0] -= ball.xspeed;
        ballPrev.coords[1] -= ball.yspeed;
        ballPrev.coords[2] -= ball.xspeed;
        ballPrev.coords[3] -= ball.yspeed;

        int up = 0;
        int left = 0;
        int right = 0;
        int down = 0;

        if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
        {
            left = 1;
        }

       if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1]))  || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
        {
            right = 1;
        }
        if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
        {
            up = 1;
        }
        if(block[i].coords[1] < ballPrev.coords[1] && ball
        {
            down = 1;
        }

        cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;

        if (left == 1)
        {
            ball.coords[0] = block[i].coords[0] - 18.0f;
            ball.coords[2] = block[i].coords[0] - 2.0f;
        }
        else if (right == 1)
        {
            ball.coords[0] = block[i].coords[2] + 2.0f;
            ball.coords[2] = block[i].coords[2] + 18.0f;
        }
        else if (down == 1)
        {
            ball.coords[1] = block[i].coords[3] + 4.0f;
            ball.coords[3] = block[i].coords[3] + 20.0f;
        }
        else if (up == 1)
        {
            ball.yspeed = 0.0f;
            ball.gravity = 0.0f;
            ball.coords[1] = block[i].coords[1] - 17.0f;
            ball.coords[3] = block[i].coords[1] - 1.0f;
        }
    }
    if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
    {
        ball.gravity = -0.5f;
    }
}
}

Để giải thích ý nghĩa của một số mã này:

Biến khối về cơ bản là một số nguyên đang lưu trữ số lượng khối hoặc nền tảng. Tôi đang kiểm tra tất cả các khối bằng vòng lặp for và số vòng lặp hiện đang được đại diện bởi số nguyên i. Hệ thống tọa độ có vẻ hơi lạ, vì vậy điều đó đáng để giải thích. coords [0] đại diện cho vị trí x (trái) của đối tượng (nơi nó bắt đầu trên trục x). coords [1] đại diện cho vị trí y (trên cùng) của đối tượng (nơi nó bắt đầu trên trục y). coords [2] đại diện cho chiều rộng của đối tượng cộng với coords [0] (phải). coords [3] đại diện cho chiều cao của đối tượng cộng với coords [1] (dưới cùng). de2dCheckCollision thực hiện phát hiện va chạm AABB. Lên là âm y và xuống là dương y, vì nó có trong hầu hết các trò chơi.

Hy vọng tôi đã cung cấp đủ thông tin cho ai đó để giúp tôi thành công. Nếu có điều gì đó tôi bỏ qua có thể rất quan trọng, hãy cho tôi biết và tôi sẽ cung cấp thông tin cần thiết. Cuối cùng, đối với bất kỳ ai có thể giúp đỡ, việc cung cấp mã sẽ rất hữu ích và được đánh giá cao.

Cảm ơn lần nữa vì sự giúp đỡ của bạn!

Chỉnh sửa : Tôi đã cập nhật mã của mình bằng một thuật toán mới để kiểm tra vị trí của quả bóng trước đó trước khi va chạm. Các trường hợp góc hoạt động chính xác trên nền tảng duy nhất đó, nhưng khi tôi có một bức tường của các vật thể, tôi giữ nó thực sự có thể trượt vào nó, nhưng nếu tôi di chuyển về phía bức tường trong khi trượt, tôi đi qua nó và về cơ bản là đứng trên đỉnh của một khối bên trong bức tường. Ngoài ra, có một hiệu ứng giật hình xảy ra khi tôi ở trên mặt đất, nơi bóng liên tục lên xuống.


Bạn đã giải quyết jitter của bạn? Nếu không, đó có thể là một vấn đề khi bạn di chuyển nhân vật của mình quá xa, thay vì TheirPos-ourSize +- 1xóa 1, nếu đó là những gì bạn đang làm. Nếu bạn không chắc chắn làm thế nào để tìm ra thuật toán đó, tôi sẵn sàng giúp đỡ, thì hiện tại tôi đang hoàn hảo =] (bạn cũng đang kiểm tra các đối tượng theo thứ tự nào?)
ultifinitus

Câu trả lời:


6

Nếu tôi hiểu mã của bạn một cách chính xác, bạn sẽ bù đắp cho sự va chạm bằng cách bù bóng bằng một lượng cố định mà không ảnh hưởng đến vận tốc của nó. Lý do quả bóng của bạn có hành động bồn chồn là vì mặc dù vị trí của nó được điều chỉnh dựa trên va chạm, vận tốc của nó vẫn nhắm vào vật va chạm. Do vận tốc này, quả bóng vẫn chuyển động về phía khối va chạm, và sẽ va chạm sau một vài khung hình bù lại.

Có lẽ giải pháp đơn giản nhất cho việc này là đảm bảo vận tốc được đặt lại khi va chạm, đảm bảo bóng sẽ không di chuyển về phía khối sau khi được bù.


5

Bạn không hiển thị bất kỳ mã nào xử lý chuyển động / vận tốc của quả bóng. Nếu bạn không dừng / nảy bóng, thì khung hình tiếp theo bóng của bạn sẽ di chuyển trở lại vào khối và bị "di chuyển" trở lại, do đó có thể nó sẽ bị "kẹt" ở bên cạnh khối.

Nếu đây không phải là nó, nếu bạn có thể cụ thể hơn về các vấn đề và / hoặc đăng thêm mã, ai đó có thể có thể giúp đỡ tốt hơn :-)


Nếu nó giúp, tôi đã cập nhật mã và thêm một thuật toán mới để kiểm tra xem bóng đã ở đâu trước khi va chạm xảy ra. Vấn đề duy nhất còn lại là có một hiệu ứng jitter nhỏ xảy ra khi tôi ở trên mặt đất, nơi quả bóng liên tục lên xuống như thể nó bị lực hấp dẫn kéo và sau đó quả bóng lại rơi vào vật thể.
hậu vệ-khu vực

@ hậu vệ-khu vực bạn không muốn đưa bóng trở lại vị trí trước đó. Thay vì tính toán sự chồng chéo của quả bóng và chướng ngại vật khi xảy ra va chạm và di chuyển quả bóng ra khỏi chướng ngại vật bằng số lượng tính toán (chồng chéo).
bummzack

4

Vâng, bạn luôn có thể làm những gì tôi đã làm, tuy nhiên thực hiện rất kém phần đó, tôi có một phương thức đơn giản trong lớp "Being" của tôi được gọi là update_prev_pose (), nó chỉ lưu trữ vị trí hiện tại của bạn trong một cấu trúc để xem xét một lát sau. Trong chức năng giải quyết va chạm của tôi, tôi nhìn vào vị trí của bên trong câu hỏi. Nếu bên đó trước đây nằm ngoài đối tượng, thì bên đó phải được sửa.

Tôi đang sử dụng phương pháp hai vượt qua để kiểm tra và giải quyết va chạm. Những gì tôi khuyên bạn nên làm là kiểm tra tất cả các va chạm trục x, sau đó tất cả các va chạm trục y, Bằng cách đó bạn sẽ không bị kẹt trên các đối tượng bạn không nên. hạnh phúc va chạm =)


1

Cảm ơn tất cả sự giúp đỡ, các bạn, và xin lỗi vì phản hồi muộn.

Tôi đã cân nhắc tất cả những ý tưởng này và chúng được tôi giúp khắc phục vấn đề. Nếu bất kỳ ai tò mò muốn biết tôi đã giải quyết vấn đề ban đầu và đầy đủ như thế nào, hãy xem tại đây trên Stack Overflow để biết câu trả lời đầy đủ (bao gồm các giải thích về xử lý va chạm đúng cách hơn). Người trả lời câu hỏi của tôi thực sự hào phóng và cung cấp một sơ đồ, vì vậy sẽ giúp những người cũng gặp vấn đề này.

Cảm ơn những người sau đã giúp tôi giải quyết vấn đề này:

  • DanTup - Daniel Tuppeny
  • bummzack
  • ghostonline
  • siêu âm

Tôi đánh giá cao nó rất nhiều!


5
Tôi nghĩ sẽ tốt hơn nếu bạn cung cấp tín dụng cho những người đã giúp bạn thay vì tạo câu trả lời của riêng bạn thay vì đánh dấu nó là câu trả lời. Ít nhất, hãy cho họ một upvote. Chỉ hai xu của tôi.
DMan

Đó là một ý kiến ​​hay; Tôi đã không nghĩ về nó. Tôi xin lỗi vì điều đó, nhưng tôi thậm chí không có đủ danh tiếng để nâng cao. Khi tôi nhận được nó, mặc dù, tôi sẽ làm như vậy.
khu vực phòng thủ

@ khu vực phòng thủ - Không có gì chống lại bạn. Tôi đã lấy tự do và nâng cao tất cả các câu trả lời cho bạn.
DMan

Cảm ơn bạn đã làm như vậy. Rõ ràng, chỉ cần bây giờ tôi đã nhận được đủ danh tiếng để nâng cao nhờ vào upvote của bạn , vì vậy tôi cũng đã làm như vậy. Tôi cũng đã công nhận những người đã giúp đỡ trong câu trả lời của tôi.
khu vực phòng thủ

@ khu vực phòng thủ - Haha, điều đó thật ngọt ngào. Tôi không nhớ đó là trường hợp!
DMan
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.