(C#/XNA)无论如何,碰撞都不会起作用

(C#/XNA)无论如何,碰撞都不会起作用,c#,xna,collision-detection,C#,Xna,Collision Detection,这件事我已经绞尽脑汁好几天了。更新实体时,我会检查碰撞,如果它们根据下面的代码发生碰撞,它们相应的运动值将设置为0。除某些原因外,此代码不适用于检查右侧的碰撞。如果实体前面有一堵2米高的墙,它将忽略它。然而,如果我在下面检查它,它似乎工作正常,但随后它将完全停止 冲突代码: public static bool CollidesRight(Level level, Vector2 position, Vector2 motion, int width, int height) {

这件事我已经绞尽脑汁好几天了。更新实体时,我会检查碰撞,如果它们根据下面的代码发生碰撞,它们相应的运动值将设置为0。除某些原因外,此代码不适用于检查右侧的碰撞。如果实体前面有一堵2米高的墙,它将忽略它。然而,如果我在下面检查它,它似乎工作正常,但随后它将完全停止

冲突代码:

    public static bool CollidesRight(Level level, Vector2 position, Vector2 motion, int width, int height)
    {
        Vector2 result = position + motion;
        int x1 = (int)(result.X / (float)Tile.TILE_WIDTH);
        int x2 = (int)((result.X + (float)width) / (float)Tile.TILE_WIDTH) + 1;
        int y1 = (int)(result.Y / (float)Tile.TILE_HEIGHT);
        int y2 = (int)((result.Y + (float)height) / (float)Tile.TILE_HEIGHT);
        AABB resultBB = new AABB(result, width, height);
        for (int i = x1; i < x2; i++)
        {
            for (int j = y1; j < y2; j++)
            {
                if (level.GetTileAt(i, j) != 0 && (Tile.TileList[level.GetTileAt(i, j)].IsSolid() || Tile.TileList[level.GetTileAt(i, j)].HasSolidTop()))
                {
                    AABB tile = new AABB(new Vector2(i * 64f, j * 64f), 64, 64);
                    Console.WriteLine(tile);
                    return resultBB.Intersects(tile);
                }
            }
        }
        return false;
    }
public static bool collipsright(级别、矢量2位置、矢量2运动、整数宽度、整数高度)
{
矢量2结果=位置+运动;
int x1=(int)(结果X/(浮动)平铺宽度);
intx2=(int)((result.X+(float)width)/(float)Tile.Tile_width)+1;
int y1=(int)(结果Y/(浮动)平铺高度);
int y2=(int)((result.Y+(float)height)/(float)Tile.Tile\u height);
AABB resultBB=新的AABB(结果、宽度、高度);
对于(int i=x1;i
以下是我的实体的更新代码:

    public virtual void Tick()
    {
        lastMotion = motion;
        lastPosition = position;
        if (Collision.CollidesBottom(level, position, motion, width, height))
        {
            onGround = true;
        }
        else if(!Collision.CollidesBottom(level, position, motion, width, height))
        {
            onGround = false;
        }

        if (onGround && !isJumping)
        {
            motion.Y = 0f;
            fallDistance = 0;
        }
        else if(!onGround)
        {
            fallDistance++;
            motion.Y += gravity * (fallDistance * 0.005f);
        }

        if (isJumping)
        {
            timeJumping++;
            if (timeJumping > 32)
            {
                timeJumping = 0;
                isJumping = false;
            }
            else
            {
                motion.Y = -2.25f;
            }
        }

        position.Y += motion.Y;

        if (motion.X != 0)
        {
            if (motion.X < 0)
            {
                motion.X += friction;
            }
            if (motion.X > 0)
            {
                motion.X -= friction;
            }
        }

        if ((motion.X > 0 && Collision.CollidesRight(level, position, motion, width, height)) || (motion.X < 0 && Collision.CollidesLeft(level, position, motion, width, height)))
        {
            motion.X = 0f;
        }

        position.X += motion.X;



        //MoveEntity(motion);
    }
public虚拟空勾()
{
lastMotion=运动;
最后位置=位置;
if(碰撞。碰撞底部(水平、位置、运动、宽度、高度))
{
onGround=正确;
}
如果(!Collision.collisdsbottom(水平、位置、运动、宽度、高度))
{
onGround=假;
}
如果(onGround&!正在跳跃)
{
运动Y=0f;
下降距离=0;
}
否则如果(!onGround)
{
坠落距离++;
运动Y+=重力*(下落距离*0.005f);
}
如果(正在跳跃)
{
时间跳跃++;
如果(时间跳跃>32)
{
时间跳跃=0;
isJumping=false;
}
其他的
{
运动Y=-2.25f;
}
}
位置Y+=运动Y;
if(motion.X!=0)
{
if(运动X<0)
{
运动X+=摩擦力;
}
如果(运动X>0)
{
运动X-=摩擦力;
}
}
if((motion.X>0&&Collision.CollidesRight(级别、位置、运动、宽度、高度))| |(motion.X<0&&Collision.CollidesLeft(级别、位置、运动、宽度、高度)))
{
运动X=0f;
}
位置X+=运动X;
//运动实体(运动);
}

我有3个选项供您选择

首先,编辑-不管这一点,我误读了您的代码我认为您应该在执行碰撞检查之前添加X运动,因为碰撞检查使用它来工作。如果不想将其添加到实际的玩家运动中,至少要将潜在运动传递到函数中。单凭这一点就可以解决一切问题。但还有一个问题

其次,我很确定是这一个,,我怀疑在设置OnGround bool时,您的position.Y经常被截断为Int。这意味着它的最小值将是一个完整的单位,下一个单位将是一个完整的单位。在pastebin的AABB代码中:

if (bb.max.Y <= min.Y || bb.min.Y >= max.Y)
    {
        return false;
    }
if(bb.max.Y=max.Y)
{
返回false;
}
即使X坐标相关代码检测到碰撞,此代码也将返回false。您应该修改此处的逻辑,以便在发生冲突时函数返回true,而不是在两次独立检查时返回false

第三,假设你的宽度是1个单位,你的瓷砖也是1个单位宽,一个块在x=2,位置为.x=0.5,还有一个非常小的x运动(或者一个尚未添加的运动,请参见答案1):

(占用块0的一些和块1的一些,像这样)[.][[X]

[.][ ][X] 当你点击x=1时,你想停下来,因为那样你就会碰到障碍物。但是:

x1=(int)(0.5)=0
x2=(int)(0.5+1)+1=2

所以你的循环:

for (int i = x1; i < x2; i++)
for(int i=x1;i
检查块0(它是空的),然后检查块1(它是空的),然后停止(因为i==x2),并且从不检查块2。因此,您关心的块永远不会得到其碰撞检查。我认为如果您将其更改为

for (int i = x1; i <= x2; i++)

for(int i=x1;我想知道更多关于
AABB
;这是你自己做的吗?如果是,请发布实现。看看
Level.GetTileAt>是什么(int,int)
确实也会很有趣。因为现在我觉得,只要找到任何实心或硬顶的平铺,就会返回
resultBB.Intersects(tile)
这是AABB,Level.GetTileAt(int x,int y)。平铺有一个IsSolid()和一个HasSolidTop()声明,草和空气砖分别为实心和非实心。