2D AS3平台游戏中的碰撞检测

时间:2014-06-30 10:01:44

标签: actionscript-3 2d collision-detection

这是我的代码:

package {
    import players.*;
    import physics.Engine;
    import flash.display.MovieClip;

    public class Mission extends MovieClip {
        public function Mission() {
            var player1:Player1 = new Player1();
            player1.playerWeight = 2;
            player1.walkingSpeed = 5;

            stage.addEventListener(KeyboardEvent.KEY_DOWN, player1.keyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, player1.keyUp);

            Engine.addPlayer(player1);
        }
    }

}

引擎类:

package physics {
    import animation.Player;
    import flash.events.Event;
    import scene.Mission;

    public class Engine {
        private static var _players:Array = new Array();

        public static function addPlayer(player:*):void{
            _players.push(player);
        }

        public static function update(e:Event):void{
            for(var i:String in _players){
                _gravity(_players[i]);
            }
        }

        private static function _gravity(player:*):void{
            if(solidBelow(player)){
                player.jumps = 0;
                player.jumping = false;
                player.gravity = 0;
            } else{
                player.gravity += player.playerWeight;
            }

            if(player.gravity < 0 && player.currentLabel != 'jumping'){ 
                player.gotoAndStop('jumping');
                player.jumping = true;
            }                   

            if(player.gravity > 5 && player.currentLabel != 'falling' && solidBelow(player) == false){ 
                player.gotoAndStop('falling');          
            }

            if(player.gravity > -10 && player.gravity < 0 && player.jumping == true){
                player.jumps++;
                player.jumping = false;
            }

            if(player.currentLabel == 'falling' && solidBelow(player) == true){ 
                player.gotoAndStop('still');
            }

            if(player.gravity > 100){
                player.die();
            }

            player.y += player.gravity;
        }

        public static function solidBelow(object:*):Boolean{
            for(var i:String in Mission.solidArray){ //contains all the solid blocks
                if(Mission.solidArray[i].hitTestPoint(object.x + object.bottomBumpPoint.x, object.y + object.bottomBumpPoint.y, true)){
                object.y = Mission.solidArray[i].y;
                return true;
            }
            }
            return false;
        }

        public static function solidLeft(object:*):Boolean{
            for(var i:String in Mission.solidArray){
                if(
                    Mission.solidArray[i].hitTestPoint(object.x + object.leftBumpPoint.x, object.y + object.leftBumpPoint.y, true)){
                    return true;
                }
            }
            return false;
        }

        public static function solidRight(object:*):Boolean{
            for(var i:String in Mission.solidArray){
                if(
                    Mission.solidArray[i].hitTestPoint(object.x + object.rightBumpPoint.x, object.y + object.rightBumpPoint.y, true)){
                    return true;
                }
            }
            return false;
        }

        public static function moveLeft(object:*):void{
            if(solidBelow(object) == true && object.currentLabel != 'walking'){ 
                object.gotoAndStop('walking'); 
            }

            if(!solidLeft(object)){
                object.scaleX = object.scaleX > 0 ? object.scaleX * -1 : object.scaleX * 1;
                object.x -= object.walkingSpeed;
            }
        }

        public static function moveRight(object:*):void{
            if(solidBelow(object) == true && object.currentLabel != 'walking'){ 
                object.gotoAndStop('walking'); 
            }

            if(!solidRight(object)){
                object.scaleX = object.scaleX < 0 ? object.scaleX * -1 : object.scaleX * 1;
                object.x += object.walkingSpeed;
            }
        }

        public static function jump(object:*, jumpHeight:int):void{         
            object.gotoAndStop('still');
            object.gravity = jumpHeight;                
            object.y--;
        }

    }   
}

玩家类:

package animation {
    import flash.display.MovieClip;
    import flash.events.KeyboardEvent;
    import flash.geom.Point;
    import physics.Engine;
        import flash.Events.Event;

    public class Player extends MovieClip{
        public var gravity:int = 0;
        public var jumping:Boolean = false;
        public var jumps:int = 0;
        public var walkingSpeed:int = 5;
        public var movingLeft:Boolean = false;
        public var movingRight:Boolean = false;

        public var leftBumpPoint:Point = new Point(-19, -80);
        public var rightBumpPoint:Point = new Point(20, -80);
        public var topBumpPoint:Point = new Point(0, 170);
        public var bottomBumpPoint:Point = new Point(0, 0);

        public const DIED:String  = 'died';

        public function Player() {

        }

        public function keyDown(e:KeyboardEvent){
            var keyCode:int = e.keyCode;

            //w = 87
            //a = 65
            //s = 83
            //d = 68

            //up = 38
            //left = 37
            //down = 40
            //right = 39

            //space = 32

            if(keyCode == 37 || keyCode == 65) { 
                addEventListener(Event.ENTER_FRAME, moveLeft, false, 0, true);
                movingLeft = true;
                if(movingRight == true){
                    movingRight = false;
                    removeEventListener(Event.ENTER_FRAME, moveRight);
                }
            } //left

            if(keyCode == 39 || keyCode == 68) {
                addEventListener(Event.ENTER_FRAME, moveRight, false, 0, true);
                movingRight = true;
                if(movingLeft == true){
                    movingLeft = false;
                    removeEventListener(Event.ENTER_FRAME, moveLeft);
                }
            }//right

            if((keyCode == 38 || keyCode == 87 || keyCode == 32) && jumping == false && jumps < 2) {
                switch (jumps){
                    case 0:
                        var jumpHeight:int = -20;
                        break;

                    case 1:
                        var jumpHeight:int = -25;
                        break;
                }

                jump(jumpHeight);
            } //up

            if(keyCode == 40 || keyCode == 83) {  } //down
        }

        public function keyUp(e:KeyboardEvent){
            var keyCode:uint = e.keyCode;

            //w = 87
            //a = 65
            //s = 83
            //d = 68

            //up = 38
            //left = 37
            //down = 40
            //right = 39

            //space = 32

            if(keyCode == 37 || keyCode == 65) { 
                gotoAndStop('still');
                removeEventListener(Event.ENTER_FRAME, moveLeft);
            } //left

            if(keyCode == 39 || keyCode == 68) { 
                gotoAndStop('still');
                removeEventListener(Event.ENTER_FRAME, moveRight);
            }//right

            if(keyCode == 40 || keyCode == 83) {  } //down
        }

        public function moveLeft(e:Event):void{
            Engine.moveLeft(this);
        }

        public function moveRight(e:Event):void{
            Engine.moveRight(this);
        }

        public function jump(jumpHeight:int):void{
            Engine.jump(this, jumpHeight);
        }

        public function respawn(xPos, yPos){
            gravity = 0;
            x = xPos;
            y = yPos;
        }

        public function die():void{
            var event:Event = new Event(DIED);
            dispatchEvent(event);
        }

    }

}

我从此页面获得了碰撞检测的代码:http://as3gametuts.com/2012/01/08/platformer-3/。但是代码中仍然存在很多错误:例如,如果向左移动而有一个实体对象,但它低于左碰撞点,则会直接通过它。此外,如果您正在高速移动,则可以移动对象。有没有人知道一个正确的教程,甚至更好:任何人都可以给我一些开始的提示吗?

提前致谢

修改 如果有帮助,这里有一个游戏链接:http://host.undeadzone.net/stackoverflow.php

另一个编辑: 这不是基于平铺的游戏!

1 个答案:

答案 0 :(得分:1)

嗯,好的,对当前代码的评论很少:
我不喜欢在按键上添加/删除eventlisteners。您已经将moveLeft / moveRight状态存储为bools,因此我只需要一次“移动”即可。检查那些的功能,例如

addEventListener(Event.ENTER_FRAME, move, false, 0, true); 

public function move(e:Event):void{
    if(moveLeft) Engine.moveLeft(this);
    else if(moveRight) Engine.moveRight(this);
}

之后更容易清理......事实上,在你目前的代码中,我并没有看到你在死亡时删除了听众(也许它已经在其他地方完成了,但这正是我和#39; d避免经常创建事件监听器,它很难跟踪,如果它们没有全部被删除,那么该对象永远不会被垃圾收集)

高速穿过物体的问题称为隧道效应。可能有更好的方法,但我所做的是从旧位置到新位置生成一条线并检查其上的碰撞。当你的碰撞器是简单的矩形时不是太难,但如果它们是不规则的形状,我认为你必须更进一步:创建一个包含字符所经过的所有位置并检查多边形的多边形(玩家路径) - 多边形(障碍物)碰撞。