Flash 基于平铺的环境中的碰撞检测

Flash 基于平铺的环境中的碰撞检测,flash,actionscript-3,actionscript,Flash,Actionscript 3,Actionscript,我的碰撞检测有问题。基本上,当我击中一个实心瓷砖时,我的角色的身体已经在瓷砖的一半了。这是我的密码 属性wY和wX是我的游戏世界定位。不是舞台定位。dx和dy是角色移动的速度。第一段代码在游戏循环中。我角色的焦点以x轴为中心 package com.objects { import flash.display.MovieClip; import com.eapi.EngineApi; import flash.events.Event; /** *

我的碰撞检测有问题。基本上,当我击中一个实心瓷砖时,我的角色的身体已经在瓷砖的一半了。这是我的密码

属性wY和wX是我的游戏世界定位。不是舞台定位。dx和dy是角色移动的速度。第一段代码在游戏循环中。我角色的焦点以x轴为中心

package com.objects 
{
    import flash.display.MovieClip;
    import com.eapi.EngineApi;
    import flash.events.Event;

    /**
     * ...
     * @author Anthony Gordon
     */
    public class Engine extends EngineApi
    {
        public var friction:Number =  0.93;
        protected var Heros:Array;

        public function Engine(w:Number = 540,h:Number = 360, tw:Number = 50, th:Number = 50) 
        {
            super(w, h, tw, th);
            Heros = new Array();
        }

        override protected function loop(e:Event):void
        {
            UpdateObjects();
            Rules();
            CheckHero();
            UpDateMap();
        }

        public function AddHero(g:GameObject):void
        {
            Heros.push(g);
        }

        protected function Rules():void
        {
            //Everything Has friction
            for (var i:Number = 0; i < gameObjects.length; i++)
            {
                var char:GameObject = GameObject(gameObjects[i]);
                char.dx *= friction;
                //char.dy *= friction;

                //Below is the tile positioning of my character
                var cgridx:Number = Math.floor(char.wX / tileW);
                var cgridy:Number = Math.floor(char.wY/ tileH);

                //This is the tile in front of the character
                var nextx:Number = Math.floor((char.wX + char.dx) / tileW);
                var nexty:Number = Math.floor((char.wY + char.dy) / tileH);

                //We assume the character is in the air before we figure it to be false
                char.onGround = false;

                //I am about to remove the vars from cgrid below. Keep a look out for issues in the future
                if (mapHolder[currentMap][nexty][cgridx] == 0 || mapHolder[currentMap][nexty][cgridx] == 2)
                {
                    //If character is falling down
                    if (char.dy > 0)
                    {
                        char.wY = (nexty * tileH) - 1;
                        cgridy = Math.floor(char.wY / tileH);
                        char.dy = 0;
                        char.onGround = true;
                    }
                    else if (char.dy < 0)//If character is going up
                    {
                        char.wY = (nexty * tileH) + (tileH + 1);
                        cgridy = Math.floor(char.wY / tileH);
                        char.dy = 0;
                    }
                }

                //mapHolder is a array that holds an array of maps and their tile numbers
                if (mapHolder[currentMap][cgridy][nextx] == 2)
                {
                    if (char.dx > 0)//if character is going right
                    {
                        char.wX = ((nextx * tileW) - 1);
                    }
                    else if (char.dx < 0)// if character is going left
                    {
                        char.wX = (nextx * tileW) + (tileW + 1);
                    }

                    char.dx = 0;
                }
                //if character is not on ground then keep faling
                if (char.onGround == false)
                {
                    char.dy += .9;
                    if (char.dy > 30) char.dy = 5;
                }
            }
        }

        protected function CheckHero():void
        {
            var char:Hero = Heros[0];
            char.x = char.wX - offsX;
            char.y = char.wY - offsY;

            if (char.wX < 0)
            {
                char.wX = 0;
                char.dx = 0;
            }

            if (char.wY < 0)
            {
                char.wY = 0;
                char.dy = 0;
            }

            offsX = char.wX - (vWidth/2);
            offsY = char.wY - (vHeight/2);

            if (offsX < 0)
            {
                offsX = 0;
            }

            if (offsY < 0)
            {
                offsY = 0;
            }

            //If screen hits the world END STOP!!!
            if ((offsX + vWidth) > wWidth)
            {
                offsX = (wWidth - vWidth);
            }

            if ((offsY + vHeight) > wHeight)
            {
                offsY = (wHeight - vHeight);
            }
            /////

            //If char hits the end, Stop!!
            if (char.wX > wWidth)
            {
                char.wX = char.wX - wWidth;
                char.wX = wWidth;
            }

        }


    }

}

好吧,这是一件很难调试的事情,但这里有一个突出的我

这两条线之间的差异让我感到奇怪:

谢谢你向右转

char.wX = ((nextx * tileW) - 1);
向左转

char.wX = (nextx * tileW) + (tileW + 1);
为什么在第二个末尾有(tileW+1)?我认为这两条线是一样的。我也不确定为什么第一行上有-1,但我认为这些行至少应该是相同的


还有,既然这是一个基于平铺的东西,而且这个人只能以我看到的一个平铺增量移动,那么为什么你首先要搞乱dx和dy呢。你这样做对我来说似乎很奇怪。

好吧,这是一件很难调试的事情,如果不在那里的话,但是这里有一件事让我很感兴趣

这两条线之间的差异让我感到奇怪:

谢谢你向右转

char.wX = ((nextx * tileW) - 1);
向左转

char.wX = (nextx * tileW) + (tileW + 1);
为什么在第二个末尾有(tileW+1)?我认为这两条线是一样的。我也不确定为什么第一行上有-1,但我认为这些行至少应该是相同的


还有,既然这是一个基于平铺的东西,而且这个人只能以我看到的一个平铺增量移动,那么为什么你首先要搞乱dx和dy呢。你这样做对我来说很奇怪。

你应该在行动前进行测试。

从上面的代码中我可以分析,您正在移动播放器,然后测试冲突。如果是这样的话,那么你需要做好准备,如果它碰到任何东西(这不是一件有趣的事,也不是调试)就退出

更简单地说,您可以调用IsBlocked()方法,该方法只需查看位于玩家将要移动的方向上的磁贴

if (!player.IsBlocked())
{
    player.Move();
}
else
{
    player.HandleCollision();
}

您应该在移动前进行测试。

从上面的代码中我可以分析,您正在移动播放器,然后测试冲突。如果是这样的话,那么你需要做好准备,如果它碰到任何东西(这不是一件有趣的事,也不是调试)就退出

更简单地说,您可以调用IsBlocked()方法,该方法只需查看位于玩家将要移动的方向上的磁贴

if (!player.IsBlocked())
{
    player.Move();
}
else
{
    player.HandleCollision();
}

我不能真正理解你的代码,但通过制作我的Mega Man引擎,我学到了一些可以分享的东西。我处理碰撞的方法是尝试移动,然后以必要的数量后退。你还需要知道你从哪个方向接近这个街区,这不是小事

1) 尝试这个动作<代码>玩家位置+=玩家速度

2) 使用边界框交点检查碰撞

2a)找到玩家和区块边界矩形的交点。我不会给出一个公式,这几乎是微不足道的。 关键点:你必须考虑一个0的高度或0的宽度(但不是两个)相交作为一个碰撞!否则,您的播放器将在碰撞表面上“振动”

3) 使用相交矩形,算出进近方向。该算法涉及比较接近速度的斜率和相交矩形的对角线

4) 根据进近方向(水平或垂直)决定是否退出运动的x或y分量。使用交叉点的高度或宽度作为要还原的量

5) 存储你的玩家现在在该方向被阻挡的事实。请注意,您现在正在触摸块,但未嵌入其中。这就是为什么一个0大小的交叉口仍然是一个碰撞-如果不是,那么下一帧他会认为他没有碰撞并再次摔倒,导致“振动”效果


至于“已经在磁贴的一半了”-你是不是无意中比较了玩家的中心点和磁贴的边缘?

我不能真正理解你的代码,但通过制作Mega Man引擎,我学到了一些可以分享的东西。我处理碰撞的方法是尝试移动,然后以必要的数量后退。你还需要知道你从哪个方向接近这个街区,这不是小事

1) 尝试这个动作<代码>玩家位置+=玩家速度

2) 使用边界框交点检查碰撞

2a)找到玩家和区块边界矩形的交点。我不会给出一个公式,这几乎是微不足道的。 关键点:你必须考虑一个0的高度或0的宽度(但不是两个)相交作为一个碰撞!否则,您的播放器将在碰撞表面上“振动”

3) 使用相交矩形,算出进近方向。该算法涉及比较接近速度的斜率和相交矩形的对角线

4) 根据进近方向(水平或垂直)决定是否退出运动的x或y分量。使用交叉点的高度或宽度作为要还原的量

5) 存储你的玩家现在在该方向被阻挡的事实。请注意,您现在正在触摸块,但未嵌入其中。这就是为什么一个0大小的交叉口仍然是一个碰撞-如果不是,那么下一帧他会认为他没有碰撞并再次摔倒,导致“振动”效果


至于“已经在瓷砖中间了”-你是不是无意中将玩家的中心点与瓷砖边缘进行了比较?

我解决了这个问题。它不是最伟大的,但却是十倍的
if (mapHolder[currentMap][cgridy][left] == 2)
                {
                    char.wX = (left + 1) * (tileW) + (tileW / 2);
                    char.dx = 0;
                }

                if (mapHolder[currentMap][cgridy][right] == 2)
                {
                    char.wX = right * (tileW) - (tileW / 2);
                    char.dx = 0;
                }