1

基本的な (今のところ) 衝突検出をプラットフォーマーに実装しようとしています。サイズがそれぞれ 16 x 16 のタイルがあります。キャラクターのサイズは 32 x 32 ピクセルで、独自のバウンディング ボックスがあります。さて、Tile クラスには bool の isSolid があります。配列内のこれらの各タイルには、それぞれの境界ボックスの四角形もあります。

次のようにして、プレーヤーとタイルの間に交差があるかどうかを確認しています。

if (player.GetBoundingBox().Intersects(map.tiles[(int)player.position.Y / 16,
(int)player.position.X / 16].bounds) && map.tiles[(int)player.position.Y / 16,  
(int)player.position.X / 16].isSolid) 
{
...
}

さて、私の問題は、位置を四捨五入しているため、これが非常に不正確であることです。私は今とても疲れていて、私の人生では、これを適切に行う方法がわかりません. この問題にアプローチする最善の方法は何ですか?

4

1 に答える 1

1

これは正確には「基本」ではないかもしれません。X 軸と Y 軸を別々に計算するため、非常にうまく機能し、問題はありません。この衝突構造は後で役立ちます。(私は古いプラットフォーマー スターター キット コードからこれに切り替えましたが、これは非常にグリッチでした)

重力のメソッドが既にあると仮定して、始めましょう。

これは、落下および速度ロジックの後にある必要があります。チェックする必要がある軸が表示されます。

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; //If you havent already, get the elapsed time
            if (velocity.X != 0f)
            {
                Position += velocity.X * Vector2.UnitX * elapsed;
                HandleCollisions(CollisionDirection.Horizontal);
            }
            if (velocity.Y != 0f)
            {
                Position += velocity.Y * Vector2.UnitY * elapsed;
                HandleCollisions(CollisionDirection.Vertical);
            }

次に、非常に重要な HandleCollisons メソッドについて説明します

        private void HandleCollisions(CollisionDirection direction)
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = player.GetBoundingBox();
            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)
                {
                   Rectangle tileBounds = Level.GetBounds(x, y);
                    // If this tile is collidable,
                    bool IsSolid = map.tiles[x,y].IsSolid;
                    Vector2 depth;
                    if (isSolid && TileIntersectsPlayer(BoundingRectangle, tileBounds, direction, out depth))
                    {

                            if ((collision == ItemCollision.Platform && movement.Y > 0))
                                continue;
                            isOnGround = true;
                            if (isSolid || isOnGround)
                            {
                                if (direction == CollisionDirection.Horizontal)
                                {
                                    position.X += depth.X;
                                }
                                else
                                {

                                    isOnGround = true;
                                    position.Y += depth.Y;
                                }
                            }


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

        }
        public static bool TileIntersectsPlayer(Rectangle player, Rectangle block, CollisionDirection direction, out Vector2 depth)
        {
            depth = direction == CollisionDirection.Vertical ? new Vector2(0, player.GetVerticalIntersectionDepth(block)) : new Vector2(player.GetHorizontalIntersectionDepth(block), 0);
            return depth.Y != 0 || depth.X != 0;
        }

それだけです!衝突を検出しますが、衝突したらプレイヤーをどれだけ押し戻すかを判断できるようにする必要があります。これら 2 つの拡張メソッドが必要になります。

public static float GetHorizontalIntersectionDepth(this Rectangle rectA, Rectangle rectB)
        {
            // Calculate half sizes.
            float halfWidthA = rectA.Width / 2.0f;
            float halfWidthB = rectB.Width / 2.0f;

            // Calculate centers.
            float centerA = rectA.Left + halfWidthA;
            float centerB = rectB.Left + halfWidthB;

            // Calculate current and minimum-non-intersecting distances between centers.
            float distanceX = centerA - centerB;
            float minDistanceX = halfWidthA + halfWidthB;

            // If we are not intersecting at all, return (0, 0).
            if (Math.Abs(distanceX) >= minDistanceX)
                return 0f;

            // Calculate and return intersection depths.
            return distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
        }

        public static float GetVerticalIntersectionDepth(this Rectangle rectA, Rectangle rectB)
        {
            // Calculate half sizes.
            float halfHeightA = rectA.Height / 2.0f;
            float halfHeightB = rectB.Height / 2.0f;

            // Calculate centers.
            float centerA = rectA.Top + halfHeightA;
            float centerB = rectB.Top + halfHeightB;

            // Calculate current and minimum-non-intersecting distances between centers.
            float distanceY = centerA - centerB;
            float minDistanceY = halfHeightA + halfHeightB;

            // If we are not intersecting at all, return (0, 0).
            if (Math.Abs(distanceY) >= minDistanceY)
                return 0f;

            // Calculate and return intersection depths.
            return distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
        }

プレーヤーの位置は左下であるため、これを少し変更する必要がある場合があることに注意してください。また、垂直方向と水平方向の衝突列挙型も必要です。これに欠けているものがあれば教えてください。

于 2012-12-29T14:30:19.630 に答える