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 2012年

回答:


12

あなたは絶対に正しいです。XNAプラットフォーマーサンプルの衝突ルーチンに関する問題を共有しました。しかし、サンプルで提供されたコードから開始することに成功し、コードを少しでも変更して、あらゆるテストシナリオで一貫した結果が得られるようになりました。

特に、壁に沿って斜めに動かして壁に沿ってスライドさせようとしたときの問題がありました。変位の最小軸に基づいて衝突を解決するためにサンプルが想定しているため、壁に向かって何らかの方向に押したときにキャラクターが移動できなくなりました。たとえば、1つの記号を使用すると、天井を抱き締めて左から右に移動しようとすると、行き詰まってしまいます(詳細を思い出せません)。標識を切り替えるとその状況は解決しますが、反対のシナリオで問題が発生します。結論としては、提供された実装では、すべての方向およびすべての方向から正しく機能させることができず、少なくとも1つのケースで常に失敗するということです。

したがって、私が行った変更の中心は、すべて2つの別々のステップで、Y軸の動きとは無関係にX軸の動きを処理し始めることでした。私は以前にこの回答でそれについて書いたので、詳細についてはそこに向かいます。

そして、私が正しく覚えていれば、その実際の理由は次のようなものでした。

ここに画像の説明を入力してください


1
デイビッドは常にXNAを利用しています!
Gustavo Maciel

1
@ Gustavo-Gtoknu問題の図がまだ必要だと感じました:P
David Gouveia

1
ちょうどこの答えに出くわしました-素晴らしい仕事!デビッドに感謝します。
オースティンBrunkhorst 2013年

1

複数の衝突がある場合、関係する各長方形の中心から最も近いものから最も遠いものへの衝突を修正すると、「ハング」の問題は発生しません。

1)すべての衝突する長方形を見つける

2)複数ある場合(ユースケースに応じて、これは頻繁に発生する場合もあれば、発生頻度が低い場合もあります)、最も近いものを見つけます。

3)衝突を1つずつ解決し、他の衝突がまだ有効かどうかを確認します

受け入れられた回答では、衝突と入力ロジックは濁っています。見出しなどを決定するためのチェックがあります。上記の方法で実装することで、衝突ロジックを入力ロジックから分離し、必要に応じて距離を計算します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.