Microsoft XNA Platformer 예, 충돌 감지가 정확하게 구현 되었습니까?


11

Microsoft가 제공 한 예는 충돌 감지 (내가 볼 수있는 것)에 작은 오류가있는 것처럼 보입니다. 사용자가 통과 할 수없는 타일과 충돌하면 교차 깊이가 계산됩니다. 더 작은 깊이 값 X 및 Y는 더 이상 타일과 충돌하지 않도록 사용자의 위치를 ​​고정하는 데 사용됩니다. 그러나 사용자가 대각선으로 여행하는 경우 캐릭터가 타일과 처음 충돌하는 지점에서 사용자가 정확하게 끝나지 않을 수 있습니까?

아마 틀렸을 지 모르지만 그것은 내가 보는 방식 일뿐입니다.

   private void HandleCollisions()
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = BoundingRectangle;
            int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
            int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
            int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
            int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;

            // Reset flag to search for ground collision.
            isOnGround = false;

            // For each potentially colliding tile,
            for (int y = topTile; y <= bottomTile; ++y)
            {
                for (int x = leftTile; x <= rightTile; ++x)
                {
                    // If this tile is collidable,
                    TileCollision collision = Level.GetCollision(x, y);
                    if (collision != TileCollision.Passable)
                    {
                        // Determine collision depth (with direction) and magnitude.
                        Rectangle tileBounds = Level.GetBounds(x, y);
                        Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
                        if (depth != Vector2.Zero)
                        {
                            float absDepthX = Math.Abs(depth.X);
                            float absDepthY = Math.Abs(depth.Y);

                            // Resolve the collision along the shallow axis.
                            if (absDepthY < absDepthX || collision == TileCollision.Platform)
                            {
                                // If we crossed the top of a tile, we are on the ground.
                                if (previousBottom <= tileBounds.Top)
                                    isOnGround = true;

                                // Ignore platforms, unless we are on the ground.
                                if (collision == TileCollision.Impassable || IsOnGround)
                                {
                                    // Resolve the collision along the Y axis.
                                    Position = new Vector2(Position.X, Position.Y + depth.Y);

                                    // Perform further collisions with the new bounds.
                                    bounds = BoundingRectangle;
                                }
                            }
                            else if (collision == TileCollision.Impassable) // Ignore platforms.
                            {
                                // Resolve the collision along the X axis.
                                Position = new Vector2(Position.X + depth.X, Position.Y);

                                // Perform further collisions with the new bounds.
                                bounds = BoundingRectangle;
                            }
                        }
                    }
                }
            }

            // Save the new bounds bottom.
            previousBottom = bounds.Bottom;
        }

3
왜 마이너스 1, ppl입니까? 질문은 나에게 유효합니다. 그러나 짧은 대답은 다음과 같습니다. XNA와 함께 제공되는 플랫 포머 데모는 예제 일뿐입니다. 게임 모델로 엄격하게 따르지 않아야합니다. 게임이 끝날 수 있음을 보여주는 것입니다. 구현이 최고가 아닌 경우 귀찮게해서는 안됩니다.
Gustavo Maciel

고맙게도, 나는 그들이 한 일이 최선의 방법이며 내가 뭔가를 놓치고 있다고 예를 들었습니다. 정리해 주셔서 감사합니다.
PriestVallon

답변:


12

당신은 절대적으로 맞습니다 . XNA 플랫 포머 샘플의 충돌 루틴과 관련된 문제가 있습니다. 그러나 샘플에 제공된 코드에서 시작하여 처리 할 수있는 모든 테스트 시나리오에서 일관된 결과를 얻을 때까지 약간 수정했습니다.

특히, 내가 겪고있는 문제는 벽을 향해 대각선으로 움직여 벽을 따라 미끄러지려고 할 때였습니다. 가장 작은 변위 축을 기준으로 충돌을 해결하기 위해 샘플이 가정한다는 가정 때문에, 이것은 벽에 대해 어떤 방향으로 밀 때 캐릭터가 움직일 수 없었습니다 . 예를 들어, 하나의 표지판을 사용하면 천장을 껴안고 왼쪽에서 오른쪽으로 움직일 때 멈출 것입니다 (구체적으로 기억할 수 없음). 부호를 바꾸면 상황이 해결되지만 반대 시나리오에서는 문제가 나타납니다. 결론은 제공된 구현으로 모든면에서 모든 방향에서 올바르게 작동 할 수 없다는 것입니다. 적어도 하나의 경우에는 실패합니다.

그래서 내가 한 변경의 핵심은 Y 축의 움직임과 독립적으로 두 개의 별도 단계에서 X 축의 움직임을 처리하기 시작하는 것입니다. 나는 이 답변 에서 전에 그것에 대해 썼 으므로 자세한 내용은 거기로 향하십시오.

그리고 내가 올바르게 기억한다면, 그 이유는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


1
데이비드는 항상 XNA에 p!
Gustavo Maciel

1
@ Gustavo-Gtoknu 나는 아직도 문제의 그림이 필요하다고 느꼈다 : P
David Gouveia

1
이 답변을 보았습니다-훌륭합니다! 고마워 데이빗.
Austin Brunkhorst

1

여러 개의 충돌이 발생하면 관련된 각 사각형의 중심에서 가장 가까운 곳에서 가장 가까운 곳으로 충돌을 수정하면 "매달려"문제가 발생하지 않습니다.

1) 모든 충돌 사각형 찾기

2) 사용 사례에 따라 빈번하거나 드물게 둘 이상이있을 경우 가장 가까운 것을 찾으십시오.

3) 한 번에 하나씩 충돌을 해결하고 다른 충돌이 여전히 유효한 충돌인지 확인

허용 된 답변에서 충돌과 입력 로직은 흐릿합니다. 기술 된 방식으로 구현하는 것은 필요할 때 거리를 계산하는 비용으로 충돌 로직을 입력 로직과 분리시킨다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.