actionscript-3flashcollision-detectionhittestflash-cs3

Wall collision problems AS3


I'm making a game where a character walks around different rooms, but I want to keep it from going through the walls. I tried making a barrier symbol to stop it, but since the four walls enclose the character, hitTestObject returns true every time, not just when it hits the solid parts of the walls. My problem with simply using hero.x < 0 is that there are items that the character can equip that cause the hero's symbol to extend below 0. All of the symbols have been resized so I can't just get the width of the symbol within the hero's symbol. Any ideas for a better method of detecting collision? Possibly hitTestPoint, but not really sure how that would work without a huge array of points to test . . .


Solution

  • Here is a quick demo showing the ideas I mentioned in the comment:

    package {
    
        import flash.geom.Rectangle;
    
        import flash.geom.Point;
    
        import flash.utils.Proxy;
    
        import flash.external.ExternalInterface;
    
        import flash.text.TextField;
    
        import flash.ui.Keyboard;
    
        import flash.utils.Dictionary;
    
        import flash.events.KeyboardEvent;
    
        import flash.display.DisplayObject;
    
        import flash.events.Event;
    
        import flash.display.Sprite;
    
        public class HitTestShapeTest extends Sprite {
    
    
    
            private var player:Player;
    
            private var vx:Number = 0,vy:Number = 0;
    
            private var speed:Number = 2;
    
            private var previousValidPos:Point = new Point();
    
            private var maze:DisplayObject;
    
            private var keys:Dictionary = new Dictionary();
    
            private var t:TextField;
    
            public function HitTestShapeTest() {
    
                addEventListener(Event.ADDED_TO_STAGE,init);
    
            }
    
            private function init(e:Event):void{
    
                maze = addChild(new Maze());
    
                player = addChild(new Player()) as Player;
    
                player.x = stage.stageWidth * .5;
    
                player.y = stage.stageHeight * .5;
    
                previousValidPos.x = player.x;previousValidPos.y = player.y;
    
                stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
    
                stage.addEventListener(KeyboardEvent.KEY_UP,onKeyUp);
    
                this.addEventListener(Event.ENTER_FRAME,update);     
    
                t = addChild(new TextField()) as TextField;   t.text = "oi";
    
                ExternalInterface.call("alert('ready');");
    
            }
    
            private function onKeyDown(e:KeyboardEvent):void{
    
                keys[e.keyCode] = true;//this key is pressed, make that available for the update call
    
                t.text = ""+e.keyCode;
    
            }
    
    
    
            private function onKeyUp(e:KeyboardEvent):void{
    
                keys[e.keyCode] = null;//clear the hash map entry for the released key
    
                vx = vy = 0;
    
            }
    
    
    
            private function update(e:Event):void{
    
                //move player
    
                if(keys[Keyboard.LEFT] != undefined)  vx = -speed;
    
                if(keys[Keyboard.RIGHT] != undefined) vx =  speed;
    
                if(keys[Keyboard.UP] != undefined)    vy = -speed;
    
                if(keys[Keyboard.DOWN] != undefined)  vy =  speed;
    
                //update positions
    
                player.x += vx;
    
                player.y += vy;
    
    
    
                //get the boundary point in the direction of movement
    
                var bounds:Rectangle = player.getBounds(this);     //beg the character's bounds
    
                var testPoint:Point = new Point();
                //check which point is at the edge of the character in the direction of movement
                if(vx != 0 || vy != 0){
    
                    if(vx < 0) testPoint.x = bounds.x;//left
    
                    else       testPoint.x = bounds.x+bounds.width;//right
    
                    if(vy < 0) testPoint.y = bounds.y;//top
    
                    else       testPoint.y = bounds.y+bounds.height;//bottom
    
                    if(vy == 0) testPoint.y = bounds.y + bounds.height * .5;//moving on x axis only, use the vertical centre on y 
                    if(vx == 0) testPoint.x = bounds.x + bounds.width * .5;//moving on y axis only, use the vertical centre on x 
                }
    
                //check collisions
    
                var isHit:Boolean = maze.hitTestPoint(testPoint.x,testPoint.y,true);//check for collisions
    
                if(!isHit){//didn't hit anything, remember this valid position
    
                    previousValidPos.x = player.x;
    
                    previousValidPos.y = player.y;
    
                }else{//restore position because we just hit something
    
                    player.x = previousValidPos.x;
    
                    player.y = previousValidPos.y;
    
                }
    
                //debug graphics
    
                graphics.clear();
    
                graphics.lineStyle(1,0x990000);
    
                graphics.drawRect(bounds.x,bounds.y,bounds.width,bounds.height);
    
                graphics.drawCircle(testPoint.x,testPoint.y,5);
    
                player.alpha = isHit ? .5 : 1;
    
            }
    
        }
    
    }
    import flash.display.BlendMode;
    
    import flash.events.Event;
    
    import flash.display.Shape;
    
    class Player extends Shape{
    
        public function Player(){
    
            init(); 
    
        }
    
        private function init():void{
    
            graphics.lineStyle(10);
    
            graphics.drawCircle(0,0,10);
    
            graphics.moveTo(0,10);
    
            graphics.lineTo(0,20);
    
            graphics.lineTo(-10,20);
    
            graphics.moveTo(0,20);
    
            graphics.lineTo(10,20);
    
            graphics.moveTo(0,20);
    
            graphics.lineTo(0,30);
    
            graphics.lineTo(-10,40);
    
            graphics.moveTo(0,30);
    
            graphics.lineTo(10,40);
            blendMode = BlendMode.LAYER;
        }
    
    }
    
    class Maze extends Shape{
    
        private var size:Number = 50;
    
        public function Maze(){
    
            addEventListener(Event.ADDED_TO_STAGE,init);
    
        }
    
        private function init(e:Event):void{
    
            graphics.beginFill(0);
    
            graphics.lineTo(stage.stageWidth,0);
    
            graphics.lineTo(stage.stageWidth,size);
    
            graphics.lineTo(size*4,size);
    
            graphics.lineTo(size*4,size*3);
    
            graphics.lineTo(size*3,size*3);
    
            graphics.lineTo(size*3,size);
    
            graphics.lineTo(size,size);
    
            graphics.lineTo(size,size*8);
    
            graphics.lineTo(stage.stageWidth,size*8);
    
            graphics.lineTo(stage.stageWidth,stage.stageHeight);
    
            graphics.lineTo(0,stage.stageHeight);
    
            graphics.lineTo(0,0);
    
            graphics.endFill();
    
        }
    
    }
    

    Save this as HitTestShapeTest.as and set it as the Document Class for a new .fla file to run the code, or try this Also check out the maze tutorial on the adobe website