Sự cố nhảy nền tảng với va chạm AABB


9

Xem sơ đồ trước:

Khi động cơ vật lý AABB của tôi giải quyết một giao lộ, nó sẽ làm như vậy bằng cách tìm trục có độ xuyên nhỏ hơn, sau đó "đẩy" thực thể trên trục đó.

Xem xét ví dụ "nhảy di chuyển sang trái":

  • Nếu velocityX lớn hơn velocityY, AABB sẽ đẩy thực thể ra trên trục Y, dừng bước nhảy một cách hiệu quả (kết quả: người chơi dừng giữa không trung).
  • Nếu velocityX nhỏ hơn velocitY (không được hiển thị trong sơ đồ), chương trình hoạt động như dự định, vì AABB đẩy thực thể ra trên trục X.

Làm thế nào tôi có thể giải quyết vấn đề này?

Mã nguồn:

public void Update()
{
    Position += Velocity;
    Velocity += World.Gravity;

    List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);

    for (int i = 0; i < toCheck.Count; i++)
    {
        SSSPBody body = toCheck[i];
        body.Test.Color = Color.White;

        if (body != this && body.Static)
        {                   
            float left = (body.CornerMin.X - CornerMax.X);
            float right = (body.CornerMax.X - CornerMin.X);
            float top = (body.CornerMin.Y - CornerMax.Y);
            float bottom = (body.CornerMax.Y - CornerMin.Y);

            if (SSSPUtils.AABBIsOverlapping(this, body))
            {
                body.Test.Color = Color.Yellow;

                Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);

                Position += overlapVector;
            }

            if (SSSPUtils.AABBIsCollidingTop(this, body))
            {                      
                if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
                    (Position.Y + Height/2f == body.Position.Y - body.Height/2f))
                {
                    body.Test.Color = Color.Red;
                    Velocity = new Vector2(Velocity.X, 0);

                }
            }
        }               
    }
}

public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
{
    if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
        return false;

    return true;
}
public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
{
    if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
        return false;

    return true;
}
public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
{
    if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
        return false;

    if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
        return true;

    return false;
}
public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
{
    Vector2 result = new Vector2(0, 0);

    if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
        return result;

    if (Math.Abs(mLeft) < mRight)
        result.X = mLeft;
    else
        result.X = mRight;

    if (Math.Abs(mTop) < mBottom)
        result.Y = mTop;
    else
        result.Y = mBottom;

    if (Math.Abs(result.X) < Math.Abs(result.Y))
        result.Y = 0;
    else
        result.X = 0;

    return result;
}

Câu trả lời:


2
  • Kiểm tra tất cả các chức năng hỗ trợ của bạn (trong danh sách mã thứ hai) nếu bạn chưa thực hiện.
  • Hình dung hoặc in ra đầu ra tiêu chuẩn những gì các đối tượng này làm. Hãy chắc chắn Bạn biết mỗi mã làm gì và nó thực hiện hoàn hảo.
  • Có rất nhiều cái nhìn sâu sắc về các vụ va chạm http://www.flipcode.com/archives/Theory_Practice-Issue_01_Collision_Detection.shtml .

Tôi chỉ nhìn vào đoạn mã mà tôi chưa thử chứng minh nó sai ở đâu.

Tôi nhìn mã và 2 dòng này có vẻ lạ:

if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
(Position.Y + Height/2f == body.Position.Y - body.Height/2f))

Bạn kiểm tra khoảng thời gian và sau đó Bạn kiểm tra tính hiệu quả? Tôi có thể sai, (có thể có một số vòng đang diễn ra) nhưng có vẻ như nó có thể gây rắc rối.


0

Thật khó để đọc mã của người khác, nhưng tôi nghĩ rằng đây là một cách giải quyết có thể (hoàn toàn động não), mặc dù tất nhiên tôi không thể kiểm tra nó:

  1. Trước khi phát hiện va chạm xảy ra, hãy lưu tốc độ của người chơi vào một số biến tạm thời.
  2. Sau khi bạn thực hiện phản ứng va chạm của mình, hãy kiểm tra xem vị trí X hoặc Y của người chơi đã được sửa chưa
  3. Nếu vị trí X đã được thay đổi, hãy đặt lại thủ công (như một loại "thiết lập lại an toàn"), vận tốc Y của người chơi đến vị trí mà anh ta có trước khi phản hồi.

Nhân tiện, điều gì xảy ra với mã hiện tại của bạn khi người chơi của bạn chạm vào mái nhà trong khi nhảy?


Thay đổi vận tốc sẽ không giải quyết được gì, vì vận tốc không bị ảnh hưởng bởi phản ứng va chạm. Phản hồi chỉ đơn giản là thay đổi Vị trí của người chơi, giữ cho Vận tốc không thay đổi. Khi người chơi chạm vào mái nhà, nó trôi nổi một lúc rồi quay xuống. Đó là dự định vì tôi không đặt Vận tốc về 0 khi nó chạm trần.
Vittorio Romeo

Điều gì xảy ra nếu bạn loại bỏ mã đặt một trong các thành phần vectơ kết quả về 0 trong phương thức GetOverlapVector?
TravisG

Thực thể bị đẩy ra theo đường chéo, đôi khi nó thậm chí không hoạt động chính xác, lần khác nó chỉ chộp lấy nó như thể nó nằm trên lưới.
Vittorio Romeo

Tôi không thể hiểu ý nghĩa của nó ngay bây giờ. Cách thức thực thể của bạn bị đẩy ra sẽ phụ thuộc vào khoảng cách của nó với cơ thể mà nó va chạm, nhưng thuật toán của bạn đã làm điều đó. Tôi sẽ có cái nhìn khác vào ngày mai.
TravisG
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.