首页 > 解决方案 > 2D AABB 碰撞解决多角案例问题 C#

问题描述

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

问题:

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

奇怪的是,其他角落案例正确解决,即如果没有间隙,您不会剪辑,并且您可以沿任何方向沿任何实心碰撞盒滑动而不会“捕捉”或任何其他情况(如果有 2 个彼此相邻)。事实上,这似乎只发生在你试图通过的间隙恰好比你的命中框小一个像素时,所以我猜正在发生的是,当在帧开始时检查碰撞时,只有一个正在添加 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.Width, 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.Y + (int)((float)Math.Round(newY) - p.worldPosition.Y), p.boundingBox.Width, 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.Y + (int)((float)Math.Round(newY) - p.worldPosition.Y), p.boundingBox.Width, 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.Y + (int)((float)Math.Round(newY) - p.worldPosition.Y), p.boundingBox.Width, 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();
        }

标签: c#xnacollisionmonogameaabb

解决方案


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


推荐阅读