碰撞检测仅适用于具有特定瓦片xna的2面

时间:2016-12-29 18:56:26

标签: c# xna geometry collision-detection

这可能很简单,但它给了我很多的悲伤,我想知道你们是否能够对它有所了解。基本上我有一个瓦片地图,它以64 * 64绘制瓦片并且效果非常好,它们在game1类中以2D数组绘制。

TileMap tileMap = new TileMap(new int[,]
    {
        { 2,2,2,2,2,2,2,2,2,2 },
        { 2,2,2,2,2,2,2,2,2,2 },
        { 0,0,0,0,0,0,4,4,4,4 },
        { 0,0,0,0,0,0,1,1,4,4 },
        { 1,1,1,1,1,1,1,1,1,1,},
        { 1,1,1,1,1,1,1,1,1,1,}
    });

现在出现了问题。基本上我想确定玩家从哪个方面击中了牌。但是,使用下面的算法,碰撞仅适用于底部和左侧。如果玩家从顶部击中了瓷砖,它将说明它是从底部击中的。如果玩家从右侧击中它将指定左侧被击中。如果玩家从顶部或右侧击中,它将显示碰撞已经发生,但是说它发生在它的底部或左侧。 它将输出图块的顶部已被命中,但仅当玩家完全位于图块时。

当它显示右侧被击中时(玩家向上移动的位置比上图略高),发生了同样的事情。

enter image description here

tilemap的

        int left = (int)Math.Floor((float)player.playerBounds.Left / TILE_WIDTH);
        int top = (int)Math.Floor((float)player.playerBounds.Top / TILE_HEIGHT);
        int right = (int)Math.Ceiling((float)player.playerBounds.Right / TILE_WIDTH) - 1;
        int bottom = (int)Math.Ceiling((float)player.playerBounds.Bottom / TILE_HEIGHT) - 1;

        Rectangle tileBounds = new Rectangle((int)tilePosX, (int)tilePosY, TILE_WIDTH, TILE_HEIGHT);
        Rectangle playerBounds = player.playerBounds;

        float WidthOfRects = 0.5f * (playerBounds.Width + tileBounds.Width);
        float heightOfRects = 0.5f * (playerBounds.Height + tileBounds.Height);

        int centerX = (playerBounds.Left + playerBounds.Width / 2) - (tileBounds.Left + tileBounds.Width / 2);
        int centerY = (playerBounds.Top + playerBounds.Height / 2) - (tileBounds.Top + tileBounds.Height / 2);

        for (int y = top; y <= bottom; ++y)
        {
            for (int x = left; x <= right; ++x)
            {

                if (mapCell[y, x].TileID == 1)
                {
                    //minkowski sum
                    if (Math.Abs(centerX) <= WidthOfRects && Math.Abs(centerY) <= heightOfRects)
                    {
                        double wy = WidthOfRects * centerY;
                        double hx = heightOfRects * centerX;
                        if (wy > hx)
                        {
                            if (wy > -hx)
                            {
                                Console.WriteLine("bottom");
                                //newPos.Y = tileCollision.Bottom;
                            }
                            else
                            {
                                Console.WriteLine("right");
                                //newPos.X = tileCollision.Right;

                            }
                        }
                        if (wy > -hx)
                        {
                            Console.WriteLine("left ");
                            //newPos.X = tileCollision.Left - playerBounds.Width;
                        }
                        else
                        {
                            Console.WriteLine("top");
                            //newPos.Y = tileCollision.Top - playerBounds.Height;
                        }
                    }
                    // player.Position = newPos;
                }
            }
        }

映射单元格

public class MapCell
{

    public int TileID { get; set; }

    public MapCell(int tileID) 
    {
        TileID = tileID;
    }

玩家界限位于玩家类更新方法中,该方法继承自精灵类。

public override void Update(GameTime gameTime)
    {
        playerBounds = new Rectangle((int)Position.X, (int)Position.Y, 50, 50);
    }

该职位继承自精灵课程

    protected Vector2 position;
    public Vector2 Position
    {
        get { return position; }
        set { position = value; }
    }

非常感谢任何帮助。

谢谢。

1 个答案:

答案 0 :(得分:0)

我们的坐标系是OY轴从上到下,玩家的中心位置为PX,PY,半宽PW,半高PH,方向矢量DX,DY。

以TX,TY,半宽TW,半高TH为中心的平铺矩形。

当玩家的中心点在第一次遇到Minkowski的总和矩形时(t是时间参数),玩家会触摸平铺

CX = PX + DX * t
CY = PX + DY * t

if DY >= 0 then  //moving down
  t1 = (TY - TH - PH - PY) / DY   //time to meet horizontal edge
else  //moving up
  t1 = (TY + TH + PH - PY) / DY  

if DX >= 0 then //moving right
  t2 = (TX - TW - PW - PX) / DX    //time to meet vertical edge
else  //moving left
  t2 = (TX + TW + PW - PX) / DX  

if t1 <= t2 then
  if DY >= 0 then
    touches top edge first
  else
    touches bottom edge first
else
  if DX >= 0 then
    touches left edge first
  else
    touches right edge first

//you can consider corner touches (t1=t2) separately