AABB 충돌로 인한 플랫폼 점프 문제


9

먼저 다이어그램을 참조하십시오.

AABB 물리 엔진이 교차점을 해석 할 때 관통이 작은 축을 찾아 해당 축의 엔티티를 "밀어 내기"하면됩니다.

"왼쪽으로 점프 이동"예를 고려하십시오.

  • velocityX가 velocityY보다 큰 경우 AABB는 엔티티를 Y 축으로 밀어내어 점프를 효과적으로 중지합니다 (결과 : 공중에서 멈춤).
  • velocityX가 속도보다 작 으면 (그림에 표시되지 않음) AABB가 엔티티를 X 축으로 밀어 내므로 프로그램이 의도 한대로 작동합니다.

이 문제를 어떻게 해결할 수 있습니까?

소스 코드:

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;
}

답변:


2

방금 잘못된 위치를 증명하려고 시도하지 않은 코드를 보았습니다.

나는 코드를 보았고이 두 줄은 이상하게 보였다.

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

당신은 간격을 확인한 다음 이질을 확인합니까? 나는 틀릴 수도 있지만 (둥근 반올림이있을 수 있습니다) 문제가 발생할 수 있습니다.


0

다른 사람들의 코드를 읽기는 어렵지만 테스트 할 수는 없지만 이것이 가능한 (완전히 브레인 스토밍 된) 해결 방법이라고 생각합니다.

  1. 충돌 감지가 발생하기 전에 플레이어 속도를 임시 변수에 저장하십시오.
  2. 충돌 응답을 마친 후 플레이어 X 또는 Y 위치가 수정되었는지 확인하십시오
  3. X 위치가 변경된 경우 플레이어 Y 속도를 응답 이전의 속도로 수동으로 재설정합니다 ( "안전 재설정").

그런데 플레이어가 점프하는 동안 지붕에 닿으면 현재 코드는 어떻게됩니까?


속도는 충돌 응답의 영향을받지 않기 때문에 속도를 변경해도 아무 것도 해결되지 않습니다. 응답은 단순히 플레이어의 위치를 ​​변경하고 벨로 시티는 변경되지 않습니다. 플레이어가 지붕에 부딪히면 잠시 동안 뜬 다음 다시 내려옵니다. 천장에 닿을 때 Velocity를 0으로 설정하지 않았기 때문에 의도되었습니다.
Vittorio Romeo

GetOverlapVector 메서드에서 결과 벡터 구성 요소 중 하나를 0으로 설정하는 코드를 제거하면 어떻게됩니까?
TravisG

개체가 대각선으로 튀어 나와서 때로는 제대로 작동하지 않으며, 그렇지 않으면 그리드에있는 것처럼 스냅됩니다.
Vittorio Romeo

지금은 이해할 수 없습니다. 엔티티가 푸시되는 방식은 충돌하는 바디와의 거리에 따라 달라 지지만 알고리즘은 이미 그렇게합니다. 내일 다시 한번 살펴 보겠습니다.
TravisG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.