二维 AABB 碰撞解决多角问题 C#

问题描述

我已经研究了几天,但似乎无法做到完美。我正在制作一个自上而下的程序生成冒险游戏,我的碰撞解决系统有一些不足之处。

问题:

尝试在 2 个通常不允许您进入的碰撞箱之间移动,如果您正在对角移动,则可以进入,这可能导致无限循环,其中碰撞永远不会从碰撞解决列表中删除(罕见),或暂时允许您在实体碰撞箱内自由走动(最常见的效果)。

奇怪的部分是其他角落情况正确解决,即如果没有间隙,您不会剪辑,并且您可以沿着任何固体hitbox向任何方向滑动而不会“抓住”或任何东西,如果旁边有2彼此。 事实上这似乎只发生在你试图通过的间隙比你的hitbox小一个像素时,所以我猜发生的是当碰撞在帧的开头,只有 2 个碰撞箱中的一个被添加,当它解决时,它会将您推入另一个。我不知道如何解决这个问题,因此非常感谢您的帮助。

演示问题的视频:

https://youtu.be/jARoEfy9u2Q

冲突解决代码:

public void Collide(float newX,float newY,List<GameObject> colObj,int seed,GraphicsDeviceManager graphics,Player p) {

            //newx is intermediatePosition + float value of controller left stick X
            //newy "                                                            " Y
            //colObj is a list of gameobjects that are collidable that are within a certain distance to the player (possible collisions)

            var fr = new Rectangle((int)Math.Round(newX) + p.bbofsx,(int)Math.Round(newY) + p.bbofsy,p.boundingBox.Width,p.boundingBox.Height);

            for (int i = 0; i < colObj.Count; i++) {
                if (fr.Intersects(colObj[i].boundingBox)) {
                    colObj[i].distanceToPlayer = (int)AABB.GetDistanceSquared(fr,colObj[i].boundingBox);
                    p.collisionsToResolve.Add(colObj[i]);
                }
            }

            //order list
            p.collisionsToResolve = p.collisionsToResolve.OrderBy(o => o.distanceToPlayer).ToList();

            for (int w = 0; w < p.collisionsToResolve.Count; w++) {

                //overworld collision code
                    var side = AABB.GetCollisionSide(p.boundingBox,p.collisionsToResolve[w].boundingBox,new Vector2((float)Math.Round(newX) - p.worldPosition.X,(float)Math.Round(newY) - p.worldPosition.Y));

                    switch (side) {
                        case CollisionSide.Left:
                            while (fr.Intersects(p.collisionsToResolve[w].boundingBox)) {
                                newX--;
                                p.intermediateWorldPosition.X = p.worldPosition.X;
                                fr = new Rectangle(p.boundingBox.X + (int)((float)Math.Round(newX) - p.worldPosition.X),p.boundingBox.Y + (int)((float)Math.Round(newY) - p.worldPosition.Y),p.boundingBox.Height);
                            }
                            break;
                        case CollisionSide.Right:
                            while (fr.Intersects(p.collisionsToResolve[w].boundingBox)) {
                                newX++;
                                p.intermediateWorldPosition.X = p.worldPosition.X;
                                fr = new Rectangle(p.boundingBox.X + (int)((float)Math.Round(newX) - p.worldPosition.X),p.boundingBox.Height);
                            }
                            break;
                        case CollisionSide.Top:
                            while (fr.Intersects(p.collisionsToResolve[w].boundingBox)) {
                                newY--;
                                p.intermediateWorldPosition.Y = p.worldPosition.Y;
                                fr = new Rectangle(p.boundingBox.X + (int)((float)Math.Round(newX) - p.worldPosition.X),p.boundingBox.Height);
                            }
                            break;
                        case CollisionSide.Bottom:
                            while (fr.Intersects(p.collisionsToResolve[w].boundingBox)) {
                                newY++;
                                p.intermediateWorldPosition.Y = p.worldPosition.Y;
                                fr = new Rectangle(p.boundingBox.X + (int)((float)Math.Round(newX) - p.worldPosition.X),p.boundingBox.Height);
                            }
                            break;
                    }

                p.UpdateBoundingBox();

                for (int i = 0; i < colObj.Count; i++) {
                    if (fr.Intersects(colObj[i].boundingBox)) {
                        p.collisionsToResolve.RemoveAt(w);
                        colObj[i].distanceToPlayer = (int)AABB.GetDistanceSquared(p.boundingBox,colObj[i].boundingBox);
                        p.collisionsToResolve.Add(colObj[i]);
                        p.collisionsToResolve = p.collisionsToResolve.OrderBy(o => o.distanceToPlayer).ToList();
                        w = 0;
                    }
                }

                var done = true;
                for (int i = 0; i < p.collisionsToResolve.Count; i++) {
                    if (fr.Intersects(p.collisionsToResolve[i].boundingBox)) {
                        done = false;
                        break;
                    }
                }

                if (done) {
                    break;
                }
            }
            //move player and update bounding box

            p.worldPosition.X = (float)Math.Round(newX);
            p.worldPosition.Y = (float)Math.Round(newY);

            p.UpdateBoundingBox();
        }

解决方法

如果这对其他人有帮助,我想出了解决它的方法,而不是尝试解决新位置(x 和 y)的碰撞,首先解决新的 x 位置,然后是 y 位置(或反之亦然)。您可以根据 2 个边界框的位置动态选择首先解析哪个轴。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...