方块之间的 2D 碰撞检测,简单但比布尔 + 更具体不受大空间跳跃的影响

发布于 2024-09-29 12:54:07 字数 2998 浏览 0 评论 0原文

想知道玩家从哪个方向击中地形图块(只是简单的上/下、左/右)。我发现的所有东西要么太简单,要么复杂得多,而且看起来对于我需要的东西来说太多了,就像 AABB 一样(当然很难说,我的大脑很难消化相当于很长的方程的东西)。到目前为止,我所得到的是今天花费大部分时间阅读和实验的结果:

public int move(double toX, double toY) {

    int col = COLLISION_NONE; //these are bit flags, in case I collide with a block to my right as well as below me

    double nextX = mX+(toX*main.getDelta()); //delta regulates speed
    double nextY = mY+(toY*main.getDelta());

    if(mTerrainCollision){

        int w = GameView.GameLoop.TILE_WIDTH;
        int h = GameView.GameLoop.TILE_HEIGHT;

        for(int i = -2; i <= 2; i++) //broad tile picking will be optimized later, better trace around players path
            for(int j = -2; j <= 2; j++) {
                GameTerrain.Block block = main.mTerrain.get(((int)Math.round(mX)/w)+i,((int)Math.round(mY)/h)+j);
                if(block.type != GameTerrain.BLOCK_TYPE_NONE) {

                    if(nextX+w >= block.x() && mX+w <= block.x()){ //COLLISION ON THE RIGHT?
                        if(mY+h > block.y() && mY < block.y()+h) { //<THIS is a problem line, see below
                            nextX = block.x() - w;
                            xMomentum = 0;

                            col |= COLLISION_RIGHT;
                        }
                    }

                    else if(nextX < block.x()+w && mX >= block.x()+w){ //COLLISION ON THE LEFT?
                        if(mY+h > block.y() && mY < block.y()+h) { //same as above, make sure were on the same plane
                            nextX = block.x() + w;
                            xMomentum = 0;

                            col |= COLLISION_LEFT;
                        }
                    }


                    if(nextY+h >= block.y() && mY+h <= block.y()){ //COLLISION ON THE BOTTOM?
                        if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
                            nextY = block.y() - h;
                            yMomentum = 0;

                            col |= COLLISION_DOWN;
                        }
                    }

                    else if(nextY < block.y()+h && mY >= block.y()+h){ //COLLISION ON THE TOP?
                        if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
                            nextY = block.y() + h;
                            yMomentum = 0;

                            col |= COLLISION_UP;
                        }
                    }
                }
            }
    }

    mX = nextX;
    mY = nextY; 

    return col;

}

它有效......大部分。即使在长时间睡眠后,玩家也不会逐步穿过区块,从而使增量飙升。除非玩家之前的位置 (mX/mY) 与我们正在检查的方块不在同一平面上,否则碰撞检测本身就会起作用(请参阅带有“THIS...”的注释行)。假设我们与一个方块完全成对角线并笔直朝它移动,玩家就会直接穿过。我已经挠头有一段时间了,试图找出如何解决最后一个问题,最好不要对所有内容进行重大修改,但如果必须做到这一点,那么好吧!我只对简单的碰撞数据感兴趣,例如“我在这一帧中接触到地板了吗?好吧,我可以跳跃”,“我现在接触到墙壁了吗?好吧,我可以跳墙,但如果我也接触了地板,则不行“, ETC。

Would like to know which direction player hits terrain tile from (just a simple up/down, left/right). Everything I find is either too simple, or is much more complex and seemingly way too much for what I need, like with AABB (granted it's hard to tell, my brain has trouble digesting what amounts to really long equations). What I've got so far is the result of spending better part of today reading and experimenting:

public int move(double toX, double toY) {

    int col = COLLISION_NONE; //these are bit flags, in case I collide with a block to my right as well as below me

    double nextX = mX+(toX*main.getDelta()); //delta regulates speed
    double nextY = mY+(toY*main.getDelta());

    if(mTerrainCollision){

        int w = GameView.GameLoop.TILE_WIDTH;
        int h = GameView.GameLoop.TILE_HEIGHT;

        for(int i = -2; i <= 2; i++) //broad tile picking will be optimized later, better trace around players path
            for(int j = -2; j <= 2; j++) {
                GameTerrain.Block block = main.mTerrain.get(((int)Math.round(mX)/w)+i,((int)Math.round(mY)/h)+j);
                if(block.type != GameTerrain.BLOCK_TYPE_NONE) {

                    if(nextX+w >= block.x() && mX+w <= block.x()){ //COLLISION ON THE RIGHT?
                        if(mY+h > block.y() && mY < block.y()+h) { //<THIS is a problem line, see below
                            nextX = block.x() - w;
                            xMomentum = 0;

                            col |= COLLISION_RIGHT;
                        }
                    }

                    else if(nextX < block.x()+w && mX >= block.x()+w){ //COLLISION ON THE LEFT?
                        if(mY+h > block.y() && mY < block.y()+h) { //same as above, make sure were on the same plane
                            nextX = block.x() + w;
                            xMomentum = 0;

                            col |= COLLISION_LEFT;
                        }
                    }


                    if(nextY+h >= block.y() && mY+h <= block.y()){ //COLLISION ON THE BOTTOM?
                        if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
                            nextY = block.y() - h;
                            yMomentum = 0;

                            col |= COLLISION_DOWN;
                        }
                    }

                    else if(nextY < block.y()+h && mY >= block.y()+h){ //COLLISION ON THE TOP?
                        if(mX+w > block.x() && mX < block.x()+w) { //make sure were on the same plane
                            nextY = block.y() + h;
                            yMomentum = 0;

                            col |= COLLISION_UP;
                        }
                    }
                }
            }
    }

    mX = nextX;
    mY = nextY; 

    return col;

}

It works... mostly. Player won't phase through blocks even after long sleeps making the delta skyrocket. The collision detection itself works unless the player's previous position (mX/mY) are not on the same plane as the block we're checking (see commented line with "THIS..."). Say we're perfectly diagonal to a block and moving straight for it, player will zip right through. I've been scratching my head for a while now trying to figure out how to go about solving this last issue, preferably without a major rehaul of everything, but if it had to come to that oh well! I'm only interested in simple collision data for things like "Did I touch a floor this frame? Ok I can jump", "Am I touching a wall right now? Ok I can wall jump, but not if I also touched a floor", etc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜味拾荒者 2024-10-06 12:54:07

将墙壁的 AABB 增大到对象 AABB 的大小(保持墙壁 AABB 的中心固定),从对象的 beforeafter 位置构造一条线段(使用对象 AABB 的中心),然后进行线段-AABB 相交测试。

Grow the wall's AABB by the size of the object's AABB (keeping the center of the wall's AABB fixed), construct a line segment from the object's before and after positions (use the center of the object's AABB), then do a segment-AABB intersection test.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文