Xây dựng một Plattformer - Làm thế nào để xác định xem người chơi có được phép nhảy không?


16

Tôi đang xây dựng một trò chơi Plattformer Jump n 'Run Style đơn giản. Tôi không sử dụng gạch - thay vào đó tôi có hình dạng hình học cho các thực thể cấp độ của mình (và trình phát cũng là một). Tôi đã hoàn thành mã phát hiện va chạm của tôi và mọi thứ hoạt động tốt cho đến nay.

Tiếp theo, tôi muốn thực hiện nhảy. Chỉ cần kiểm tra nếu người chơi nhấn phím thích hợp và thêm một số vận tốc lên. Hoạt động tốt. Nhưng nó hoạt động ngay cả khi người chơi ở trên không, đó không phải là điều tôi muốn. ;-)

Vì vậy, tôi phải kiểm tra xem người chơi có đứng trên thứ gì không. Ý tưởng đầu tiên của tôi là kiểm tra xem có va chạm ở khung cuối không và đánh dấu người chơi là "có thể nhảy", nhưng điều này thậm chí sẽ kích hoạt nếu người chơi chạm tường trong không khí. Vì kỹ năng toán học của tôi không tốt lắm, tôi yêu cầu giúp đỡ - ngay cả những gợi ý cũng sẽ làm thế nào để thực hiện điều này.

Cảm ơn!

Câu trả lời:


14

Hai lựa chọn mùa xuân đến trong tâm trí:

  • Suy nghĩ đầu tiên là gắn thẻ hình học với ID và sau đó kiểm tra xem liệu xung đột có với hình học được gắn thẻ là sàn không. Điều này cung cấp khả năng kiểm soát nhiều nhất các bề mặt có thể nhảy nhưng với chi phí trong thời gian tạo cấp.
  • Thứ hai là kiểm tra mức độ bình thường của vụ va chạm, nếu nó hướng lên thì cho phép nhảy. Hoặc trong một số lề của lên, tùy thuộc vào nếu bạn có sàn nghiêng. Điều này rất linh hoạt và không yêu cầu gắn thẻ, nhưng nếu bạn có sàn và tường nghiêng, bạn có thể có một số bước nhảy mà bạn không muốn.

Kiểm tra bình thường có vẻ như là một ý tưởng tuyệt vời với tôi. Cảm ơn đã đăng bài đó.
Christopher Horenstein

+1 để kiểm tra bình thường. Điều này đảm bảo rằng một sàn có thể chuyển tiếp liền mạch vào tường mà không gây ra bất kỳ vấn đề nào.
Soviut

1
+1 Chắc chắn kiểm tra va chạm - bình thường. Có các loại hình học thế giới khác nhau là tốt và cho phép thiết kế mức độ linh hoạt hơn, nhưng nó không giải quyết được vấn đề chính của bạn. Một "bức tường" cũng có thể thuộc loại "mặt đất", tùy thuộc vào việc bạn đang chạy vào nó hay đứng trên nó. Đó là nơi va chạm - bình thường sẽ giúp ích.
bummzack

Tôi thấy giải pháp bình thường rất tốt và sẽ giải quyết vấn đề của tôi. Ngay cả câu trả lời được đánh giá cao khác cũng tốt và như vậy - nhưng câu trả lời này tốt hơn cho câu hỏi của tôi. Cảm ơn wkerslake của bạn!
Malax

8

Bạn chắc chắn nên thực hiện một số loại bề mặt. Hãy nghĩ về nó, bạn sẽ xoay sở thế nào nếu bạn có thể leo lên một cái thang nếu bạn không thể biết liệu nhân vật của bạn chỉ va vào tường hay thang? Bạn chỉ có thể sử dụng OOP để quản lý phân cấp loại bằng cách sử dụng di sản, nhưng tôi sẽ đề nghị bạn sử dụng "danh mục" được triển khai bằng loại liệt kê:

Đây là ý tưởng: Bảng liệt kê "Va chạm" có cờ cho mỗi danh mục. Ví dụ:

namespace Collisions
{
    enum Type
    {
        None   = 0,
        Floor  = 1 << 0,
        Ladder = 1 << 1,
        Enemy  = 1 << 2,
        ... // And whatever else you need.

        // Then, you can construct named groups of flags.
        Player = Floor | Ladder | Enemy
    };
}

Với phương pháp này, bạn sẽ có thể kiểm tra xem người chơi có va chạm bất cứ thứ gì bạn nên quản lý hay không, để động cơ của bạn có thể gọi Phương thức "Va chạm" của thực thể:

void Player::Collided( Collisions::Type group )
{
   if ( group & Collisions::Ladder )
   {
      // Manage Ladder Collision
   }
   if ( group & Collisions::Floor )
   {
      // Manage Floor Collision
   }
   if ( group & Collisions::Enemy )
   {
      // Manage Enemy Collision
   }
}

Phương thức sử dụng cờ bitwise và toán tử "Hoặc" bitwise để đảm bảo mỗi nhóm có một giá trị khác nhau, dựa trên giá trị nhị phân của danh mục. Phương pháp này hoạt động tốt và có thể dễ dàng mở rộng để bạn có thể tạo các nhóm va chạm hải quan. Mỗi Thực thể (Người chơi, Kẻ thù, v.v.) trong trò chơi của bạn có một số bit được gọi là "bộ lọc", được sử dụng để xác định những gì nó có thể va chạm với. Mã va chạm của bạn nên kiểm tra xem các bit có khớp hay không và phản ứng tương ứng, với một số mã có thể trông như sau:

void PhysicEngine::OnCollision(...)
{
    mPhysics.AddContact( body1, body1.GetFilter(), body2, body2.GetFilter() );
}

Có một lý do để sử dụng const int thay vì enum? Trong trường hợp suy biến của một cờ đơn hoặc nhóm được đặt tên, kiểu liệt kê sẽ dễ đọc hơn và bạn có thêm khả năng kiểm tra kiểu trong hầu hết các trình biên dịch.

Vâng, enum không thể (tôi nghĩ) sử dụng các toán tử nhị phân để tạo các nhóm tùy chỉnh mới. Lý do tại sao tôi thực hiện luận điểm là vì tôi sử dụng lớp Cấu hình với các thành viên tĩnh công khai vì lý do dễ đọc, giữ an toàn cho các tham số cấu hình.
Frédérick Imbeault

Nó có thể. Phép tính "giá trị" có thể là các phép toán bitwise trên các giá trị không đổi khác (tôi nghĩ rằng nó thực sự có thể là bất kỳ biểu thức hằng nào, nhưng tôi quá lười để kiểm tra tiêu chuẩn). Các giá trị không tĩnh được thực hiện theo cách chính xác như ví dụ của bạn, nhưng được nhập chính xác hơn. Tôi không biết ý của bạn là "bảo mật", nhưng chính xác cùng một cú pháp mà không có chi phí liên kết với một lớp có thể đạt được với một không gian tên.

Tôi đã cập nhật các ví dụ mã của bạn để sử dụng một kiểu liệt kê.

Có lẽ nó làm cho suy nghĩ dễ đọc hơn. Tôi chấp nhận các thay đổi bạn đã thực hiện, phương pháp tôi đã sử dụng là chính xác nhưng tôi đã không điều chỉnh mã cho enouph giải thích, cảm ơn bạn đã sửa chữa. Đối với không gian tên, bạn hoàn toàn đúng, nhưng điều này không đúng với tất cả các ngôn ngữ (Ngôn ngữ kịch bản cho ví dụ). "Bảo mật" là các tùy chọn cấu hình của tôi là tĩnh nên chúng không thể được sửa đổi nhưng sử dụng enum cũng ngăn chặn điều này.
Frédérick Imbeault

1

Nếu bạn coi chân nhân vật của mình cách nhân vật ở một khoảng cách nhất định và nếu bạn không di chuyển khỏi bề mặt thì nhân vật của bạn sẽ ở trên mặt đất.

Trong mã giả thô:

bool isOnGround(Character& chr)
{
   // down vector is opposite from your characters current up vector.
   // if you want to support wall jumps, animate the vecToFoot as appropriate.
   vec vecToFoot = -chr.up * chr.footDistanceFromCentre;

// if feet are moving away from any surface, can't be on the ground if (dot(chr.velocity, down) < 0.0f) return false;

// generate line from character centre to the foot position vec linePos0 = chr.position; vec linePos1 = chr.position + vecToFoot;

// test line against world. If it returns a hit surface, we're on the ground if (testLineAgainstWorld(line0, line1, &surface) return true;

return false; }


Điều này sẽ không hoạt động nếu bạn muốn thêm các tính năng như nhảy đôi hoặc nhảy tường tôi nghĩ sao?
Frédérick Imbeault

Tôi không tin OP đã đề cập đến cú nhảy đôi hoặc cú nhảy tường, phải không?
jpaver

Tôi đã sửa đổi mã để hiển thị cách trừu tượng vectơ đến chân của bạn từ trung tâm nhân vật. Nếu bạn làm động tác này, và chân đứng sang một bên và đập vào tường, bạn sẽ có thể hỗ trợ nhảy tường.
jpaver

Đây về cơ bản là một cách kém linh hoạt để kiểm tra va chạm bình thường. (Ít linh hoạt hơn vì bạn có thể phân biệt một cách tầm thường một bước nhảy tường với bước nhảy sàn từ bước nhảy trần chỉ bằng cách kiểm tra hướng bình thường.)

2
Không bao giờ gọi một biến char, ngay cả trong mã giả.
đúng
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.