Javascript 碰撞检测&x27;不要让物体传送起来

Javascript 碰撞检测&x27;不要让物体传送起来,javascript,algorithm,2d,collision-detection,game-physics,Javascript,Algorithm,2d,Collision Detection,Game Physics,已解决,有关最终算法,请参见文章底部 背景:我正在使用JS和HTML画布元素开发2D平台。关卡地图是基于平铺的,但玩家不会被夹在平铺上。我正在使用中概述的碰撞检测算法。除了一个边缘情况(或“壁架”情况)外,它基本上可以工作 问题: 球员摔倒了,也向右移动,撞到了墙上。当它落下时,它会传送到壁架的高度。相反,玩家应该在不进行远程传送的情况下正常下落 有没有办法改变算法来防止这种行为?如果不是,你能建议一种替代的碰撞检测算法吗?理想情况下,任何修正都不会假设玩家总是摔倒,因为在游戏中,玩家的摔倒方

已解决,有关最终算法,请参见文章底部

背景:我正在使用JS和HTML画布元素开发2D平台。关卡地图是基于平铺的,但玩家不会被夹在平铺上。我正在使用中概述的碰撞检测算法。除了一个边缘情况(或“壁架”情况)外,它基本上可以工作

问题:

球员摔倒了,也向右移动,撞到了墙上。当它落下时,它会传送到壁架的高度。相反,玩家应该在不进行远程传送的情况下正常下落

有没有办法改变算法来防止这种行为?如果不是,你能建议一种替代的碰撞检测算法吗?理想情况下,任何修正都不会假设玩家总是摔倒,因为在游戏中,玩家的摔倒方向在上/下/左/右之间切换

算法:

  • 玩家的新位置是在假设没有碰撞的情况下计算的。(以下代码中未显示)

  • 一个名为
    getBorderTiles
    的函数获取一个对象(玩家)并返回与玩家的4个角中的每一个相接触的tiles。由于玩家的大小不超过一块瓷砖,因此这些边界瓷砖必然是玩家触摸的唯一瓷砖。请注意,其中一些瓷砖可能是相同的。例如,如果玩家仅占用一列,左上/右上分幅将与左下/右下分幅相同。如果发生这种情况,
    getBorderTiles
    仍然返回所有四个tile,但其中一些将是相同的

  • 它会检查标高贴图(二维阵列)中的这些边界平铺,以查看它们是否为实心。如果平铺是实心的,则对象与该平铺发生碰撞

  • 它测试上/下/左/右碰撞。如果玩家向下移动并与向下瓦片碰撞,但未与相应的向上瓦片碰撞,则玩家向下碰撞。如果玩家向左移动并与左侧互动程序发生碰撞,但未与相应的右侧互动程序发生碰撞,则该互动程序是向左碰撞。等。在左/右检查之前执行上/下检查。如果在执行左/右检查之前发生上/下碰撞,则会调整存储边框平铺的变量。例如,如果玩家向下碰撞,它将被推入向上的瓷砖中,因此BL/BR瓷砖现在与TL/TR瓷砖相同

  • 玩家的x、y和速度根据其碰撞方向进行调整

  • 算法失败的原因:

    右下角的平铺是实心的,但右上角不是,因此(步骤4)玩家向下碰撞(步骤5)将其向上推。此外,它与BR磁贴碰撞,但与BL不碰撞,因此它会向右碰撞并向左推动。最后,玩家被渲染到窗台的正上方和左侧。事实上,它是被传送上去的

    尝试解决方案:我试图修复此问题,但它只会造成另一个问题。我添加了一个复选框,这样玩家只会在一个磁贴距离内(比如3px)与该磁贴发生碰撞。如果玩家仅仅在BR磁贴中,算法将不会记录向下碰撞,因此玩家不会向上传送。然而,如果玩家在另一个场景中摔倒在地,它不会确认碰撞,直到玩家离地相当远。当球稍微掉到地上,被推回地面顶部,再次摔倒时,球员会感到不安

    谢谢你读到这里。我真的很感谢你的反馈

    当前算法代码:
    var borderTiles=getBorderTiles(object),//如果一个tile不在该级别内,则返回0(一个falsy值)
    tileTL=borderTiles.topLeft,
    tileTR=borderTiles.topRight,
    tileBL=borderTiles.bottomLeft,
    tileBR=borderTiles.bottomRight,
    coordsBR=getTopleftxyCoordinationFTile(tileBR),//(x,y)坐标指的是tile的左上角
    xRight=coordsBR.x,//x的右分幅(用于调整对象的位置,因为它落在4个分幅的中间)
    yBottom=coordsBR.y,//y底部瓷砖(用于调整对象的位置,因为它落在4块瓷砖的中间)
    typeTL=tileTL?level.map[tileTL.row][tileTL.col]:-1,//如果tileTL在该级别中,则获取其类型,否则为-1
    typeTR=tileTR?level.map[tileTR.row][tileTR.col]:-1,
    typeBL=tileBL?level.map[tileBL.row][tileBL.col]:-1,
    typeBR=tileBR?level.map[tileBR.row][tileBR.col]:-1,
    CollizeSTL=typeTL==TILETYPE.SOLID,//如果平铺为实心,则为true
    collidesTR=typeTR==TILETYPE.SOLID,
    collidesBL=typeBL==TILETYPE.SOLID,
    collizesbr=typeBR==TILETYPE.SOLID,
    collide sup=false,
    CollipsDown=false,
    collipsleft=false,
    碰撞右=假;
    //上下
    如果(object.vy<0&((collidesTL&&!collidesBL)| |(collidesTR&&!collidesBR))){
    collide sup=true;
    /*对象被推出底行,因此底行现在是顶行。更改碰撞__
    变量,因为这会影响碰撞测试,但无需更改平铺变量*/
    collidesTL=collidesBL;
    collizestr=collizesbr;
    }如果(object.vy>0&((collidesBL&&!collidesTL)| |(collidesBR&&!collidesTR)),则为else{
    CollipsDown=真;
    /*对象被推出底行,因此底行现在是顶行。更改碰撞__
    变量,因为这会影响碰撞测试,但无需更改平铺变量*/
    collidesBL=collidesTL;
    collizesbr=collizestr;
    }
    //左右
    如果(object.vx<0&((collidesTL&&!collidesTR)| |(collidesBL&&!collidesBR))){
    collizesleft=true;
    }否则如果(obj
    
    sizes: sTile = 50, sPlayer = 20
    old position (fine, top-left corner): oX = 27, oY = 35
    speeds: vX = 7, vY = 10
    new position: x = oX + vX = 34, y = oY + vY = 45  =>  (34, 45)
    solid: tile at (50, 50)
    
    1.1. Checking x-direction, relevant points for positive vX are the ones to the right:
         (54, 45) and (54, 65). The latter gives a conflict and we need to correct the
         position to p1 = (30, 45) and speed v1 = (0, 10).
    
    2.1. Checking y-direction based on previous position, relevant points: (30, 65) and
         (50, 65). There is no conflict, p1 and v1 remain unchanged.
    
    3.1. There was a conflict in step 1.1. so we cannot return the current result
         immediately and have to calculate the distance d1 = 4 + 0 = 4.
    
    1.2. Checking y-direction first this time, relevant points: (34, 65) and (54, 65).
         Because the latter gives a conflict we calculate p2 = (34, 30) and v2 = (7, 0).
    
    2.2. Checking x-direction based on step 1.2., relevant points: (54, 30) and (54, 50).
         There is no conflict, p2 and v2 remain unchanged.
    
    3.2. Because there was a conflict in step 1.2. we calculate the distance d2 = 15.
    
    5.   Change position and speed to p1 and v1 because d1 is smaller than d2.