AS3 Frogger Pixel完美碰撞

时间:2015-10-14 23:30:18

标签: actionscript-3 flash

我创建了一个简单的AS3蛙式游戏并使用.hitTestObject来测试青蛙是否遇到任何障碍物。这是没有效果的,因为青蛙击中的物体完全不接触它。我是AS3的新手,不知道从哪里开始编码。任何帮助,将不胜感激!

包{

import flash.display.*;
import flash.events.*;
import flash.utils.*;
import flash.ui.*;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.utils.Timer;
import flash.display.BitmapData;
import flash.display.Bitmap;

    public class Main extends MovieClip 
    {
        //set variables
        public var frog_spriteInstance:frog_sprite;
        public var safeZoneInstance1 : safeZone;
        public var safeZoneInstance2: safeZone;
        public var safeZoneInstance3 : safeZone;
        public var whitecar : car1;
        public var whitecar1 : car1; 
        public var whitecar2 : car1; 
        public var truck1 : truck_sprite;
        public var truck2: truck_sprite;
        public var redcar : car_sprite;
        public var redcar2 : car_sprite;
        public var redcar3 : car_sprite;
        public var log1 : log_sprite;
        public var log2 : log_sprite;
        public var log3 : log_sprite;
        public var letters : Letters;
        public var letters2 : Letters_2;
        public var letters3 : Letters_3;
        public var letters4 : Letters_4;
        public var health : HealthBar;
        public var firstletter : firstLetter;
        public var secondletter : secondLetter;
        public var thirdletter : thirdLetter;
        public var fourthletter : fourthLetter;

        var mysound:Sound = new (mySound); 


        public function Main()
        {
            // constructor code
            safeZoneInstance1 = new safeZone();
            stage.addChild(safeZoneInstance1);
            safeZoneInstance1.x = 300;
            safeZoneInstance1.y=545

            safeZoneInstance2 = new safeZone();
            stage.addChild(safeZoneInstance2);
            safeZoneInstance2.x = 300;
            safeZoneInstance2.y=300

            safeZoneInstance3 = new safeZone();
            stage.addChild(safeZoneInstance3);
            safeZoneInstance3.x = 300;
            safeZoneInstance3.y=100

            whitecar = new car1();
            stage.addChild(whitecar);
            whitecar.x = 300;
            whitecar.y = 500

            whitecar1 = new car1();
            stage.addChild(whitecar1);
            whitecar1.x = 550;
            whitecar1.y = 480

            whitecar2 = new car1();
            stage.addChild(whitecar2);
            whitecar2.x = 50;
            whitecar2.y = 480

            truck1 = new truck_sprite();
            stage.addChild (truck1);
            truck1.x = 1000;
            truck1.y = 430

            truck2 = new truck_sprite();
            stage.addChild (truck2);
            truck2.x = 300;
            truck2.y = 430

            redcar = new car_sprite();
            stage.addChild (redcar);
            redcar.x = 300;
            redcar.y = 340

            redcar2 = new car_sprite();
            stage.addChild (redcar2);
            redcar2.x = 100;
            redcar2.y = 375

            redcar3 = new car_sprite();
            stage.addChild (redcar3);
            redcar3.x = 500;
            redcar3.y = 375

            log1 = new log_sprite();
            stage.addChild(log1);
            log1.x = 300;
            log1.y = 230

            log2 = new log_sprite();
            stage.addChild(log2);
            log2.x = 100;
            log2.y = 150


            log3 = new log_sprite();
            stage.addChild(log3);
            log3.x = 500;
            log3.y = 150

            letters = new Letters();
            letters.x = randomRange(100,500) ;
            letters.y = randomRange(100,500);
            stage.addChild(letters); 

            letters2 = new Letters_2();
            letters2.x = randomRange(100,500) ;
            letters2.y = randomRange(100,500);
            stage.addChild(letters2); 

            letters3 = new Letters_3();
            letters3.x = randomRange(100,500) ;
            letters3.y = randomRange(100,500);
            stage.addChild(letters3); 

            letters4 = new Letters_4();
            letters4.x = randomRange(100,500) ;
            letters4.y = randomRange(100,500);
            stage.addChild(letters4); 

            frog_spriteInstance = new frog_sprite();
            stage.addChild(frog_spriteInstance);  
            frog_spriteInstance.x=300; 
            frog_spriteInstance.y=550;

            health = new HealthBar();
            stage.addChild(health);
            health.x = 130;
            health.y = 20;
            health.width = 100;

            stage.addEventListener(KeyboardEvent.KEY_DOWN, moveFrog);

            stage.addEventListener(Event.ENTER_FRAME, movecars); 

            stage.addEventListener(Event.ENTER_FRAME, movetrucks);

            stage.addEventListener(Event.ENTER_FRAME, moveredcars);

            stage.addEventListener(Event.ENTER_FRAME, movelogs);

            stage.addEventListener(Event.ENTER_FRAME,checkforcollision);

            mysound.play();
        }

        public function moveFrog(e:KeyboardEvent)
        {   
           // get the key pressed and then move the player

            {
                if (e.keyCode == Keyboard.UP)
                {
                    frog_spriteInstance.rotation = 0;
                    frog_spriteInstance.y -= 50;
                }
                if (e.keyCode == Keyboard.DOWN)
                {
                    frog_spriteInstance.rotation = 180;
                    frog_spriteInstance.y += 50;
                }
                if (e.keyCode == Keyboard.LEFT)
                {
                    frog_spriteInstance.rotation = -90;
                    frog_spriteInstance.x -= 50;
                }
                if (e.keyCode == Keyboard.RIGHT)
                {
                    frog_spriteInstance.rotation = 90;
                    frog_spriteInstance.x += 50;
                }

            }
        }

        function movecars(event:Event)  
        {  
            //move cars across screen and when they disappear, reappear at the other side
            whitecar.x -= 3;  

            if (whitecar.x<-100){
            whitecar.x=650;
            }  
            whitecar1.x -= 3;  

            if (whitecar1.x<-100){
            whitecar1.x=650;
            } 
            whitecar2.x -= 3;  

            if (whitecar2.x<-100){
            whitecar2.x=650;
            } 
        }

        function movelogs(event:Event)  
        {  
            //move logs across screen and when they disappear, reappear at the other side
            log1.x -= 5;  

            if (log1.x<-100){
            log1.x=650;
            }  
            log2.x -= 5;  

            if (log2.x<-100){
            log2.x=650;
            } 
            log3.x -= 5;  

            if (log3.x<-100){
            log3.x=650;
            } 
        }

        function movetrucks(event:Event)
        {
            //move trucks across screen and when they disappear, reappear at the other side
            truck1.x +=3;

        if (truck1.x>650){
            truck1.x=-100;
            }
            truck2.x +=3;

        if (truck2.x>650){
            truck2.x=-100;
            }

        }

        function moveredcars(event:Event)
        {
            //move red cars across screen and when they disappear, reappear at the other side
            redcar.x +=3;

        if (redcar.x>650){
            redcar.x=-100;
            }
            redcar2.x +=3;

        if (redcar2.x>650){
            redcar2.x=-100;
            }
            redcar3.x +=3;

        if (redcar3.x>650){
            redcar3.x=-100;
            }
        }

        function checkforcollision(event:Event)
        {
            //check for collisions
            if (frog_spriteInstance.hitTestObject(log1) || (frog_spriteInstance.hitTestObject(log2) || (frog_spriteInstance.hitTestObject(log3) || (frog_spriteInstance.hitTestObject(whitecar) || (frog_spriteInstance.hitTestObject(whitecar1) || (frog_spriteInstance.hitTestObject(whitecar2) || (frog_spriteInstance.hitTestObject(log2) || (frog_spriteInstance.hitTestObject(truck1) || (frog_spriteInstance.hitTestObject(truck2) || (frog_spriteInstance.hitTestObject(redcar) || (frog_spriteInstance.hitTestObject(redcar2) || (frog_spriteInstance.hitTestObject(redcar3))))))))))))){
            //reset frog if hits an obstacle
            stage.addChild(frog_spriteInstance);  
            frog_spriteInstance.x=300; 
            frog_spriteInstance.y=550;
            //reduce health bar
            health.width -= 10;
            }
            //remove event listeners when health is empty
            if (health.width == 0){
            stage.removeEventListener(Event.ENTER_FRAME, movecars);
            stage.removeEventListener(KeyboardEvent.KEY_DOWN, moveFrog);
            stage.removeEventListener(Event.ENTER_FRAME, movetrucks);
            stage.removeEventListener(Event.ENTER_FRAME, moveredcars);
            stage.removeEventListener(Event.ENTER_FRAME, movelogs);
            }
            //add letters to bottom of screen when hit correctly
            if (frog_spriteInstance.hitTestObject(letters)){
                stage.addChild(frog_spriteInstance);  
                frog_spriteInstance.x=300; 
                frog_spriteInstance.y=550;
                stage.removeChild(letters);
                firstletter = new firstLetter();
                stage.addChild(firstletter);
                firstletter.x=345; 
                firstletter.y=600; 
            }
            if (frog_spriteInstance.hitTestObject(letters2)){
                stage.addChild(frog_spriteInstance);  
                frog_spriteInstance.x=300; 
                frog_spriteInstance.y=550;
                stage.removeChild(letters2);
                secondletter = new secondLetter();
                stage.addChild(secondletter);
                secondletter.x=206; 
                secondletter.y=600; 

            }
            if (frog_spriteInstance.hitTestObject(letters3)){
                stage.addChild(frog_spriteInstance);  
                frog_spriteInstance.x=300; 
                frog_spriteInstance.y=550;
                stage.removeChild(letters3);
                thirdletter = new thirdLetter();
                stage.addChild(thirdletter);
                thirdletter.x=273; 
                thirdletter.y=600; 

            }
            if (frog_spriteInstance.hitTestObject(letters4)){
                stage.addChild(frog_spriteInstance);  
                frog_spriteInstance.x=300; 
                frog_spriteInstance.y=550;
                stage.removeChild(letters4);
                health.width -= 10;
                fourthletter = new fourthLetter();
                stage.addChild(fourthletter);
                fourthletter.x=25; 
                fourthletter.y=620; 
            }
        }

        function randomRange(minNum:Number, maxNum:Number):Number 
        {
            //random generator for letter positioning
            return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
        }
   }

}

此外,我的代码非常狡猾,因此任何有关改进的建议都非常受欢迎。

1 个答案:

答案 0 :(得分:2)

要从两个任意显示对象执行像素完美命中测试,您必须将它们绘制到位图并使用BitmapData/hitTest()

这是一个执行此操作的通用函数:

function hitTestShapes(object1:DisplayObject, object2:DisplayObject, threshold:uint = 1):Boolean {

    var bounds1:Rectangle = object1.getBounds(object1.parent);
    var matrix1:Matrix = object1.transform.matrix;
    matrix1.tx = object1.x - bounds1.x;
    matrix1.ty = object1.y - bounds1.y;
    var bmp1:BitmapData = new BitmapData(bounds1.width, bounds1.height, true, 0);
    bmp1.draw(object1, matrix1);

    var bounds2:Rectangle = object2.getBounds(object2.parent);
    var matrix2:Matrix = object2.transform.matrix;
    matrix2.tx = object2.x - bounds2.x;
    matrix2.ty = object2.y - bounds2.y;
    var bmp2:BitmapData = new BitmapData(bounds2.width, bounds2.height, true, 0);
    bmp2.draw(object2, matrix2);

    return bmp1.hitTest(bounds1.topLeft, threshold, bmp2, bounds2.topLeft, threshold);
}

请注意,绘制到位图的速度相当慢,因此请注意不要过度使用此类功能,否则会出现性能问题。实际上,最好先使用hitTestObject(),这非常快,并检测边界框交叉点,然后只调用hitTestShapes()来优化您的检查。换句话说:

if (frog_spriteInstance.hitTestObject(log1) && hitTestShapes(frog_spriteInstance, log1)) { }

对于代码的建议,通过数组,循环和函数进行重复数据删除的可能性很大。例如,不是将所有对象定义为单独的变量,而是将它们全部存储在数组(或向量)中:

public var safeZones:Array = [];
public var obstacles:Array = [];
public var letters:Array = [];

要填充数组,您可以将值推入它们并使用函数合并所有重复的对象设置代码:

(代码约定注释:使用&#34; UpperCamelCase&#34;用于类名。)

public function Main(){
    addSafeZone(300, 545);
    addSafeZone(300, 300);
    addSafeZone(300, 100);

    addObstacle(WhiteCar, 300, 500);
    addObstacle(WhiteCar, 550, 480);
    addObstacle(WhiteCar, 50, 480);

    addObstacle(Truck, 1000, 430);
    addObstacle(Truck, 300, 430);

    addObstacle(RedCar, 300, 340);
    addObstacle(RedCar, 100, 375);
    addObstacle(RedCar, 500, 375);

    addObstacle(Log, 300, 230);
    addObstacle(Log, 100, 150);
    addObstacle(Log, 500, 150);

    addRandomLetters(Letters_1);
    addRandomLetters(Letters_2);
    addRandomLetters(Letters_3);
    addRandomLetters(Letters_4);
}

private function addSafeZone(x:Number, y:Number):void {
    var safeZone:SafeZone = new SafeZone();
    stage.addChild(safeZone);
    safeZone.x = x;
    safeZone.y = y
    safeZones.push(safeZone);
}

private function addObstacle(spriteClass:Class, x:Number, y:Number):void {
    var obstacle:Sprite = new spriteClass();
    stage.addChild(obstacle);
    obstacle.x = x;
    obstacle.y = y
    obstacles.push(obstacle);
}

private function addRandomLetters(lettersClass:Class):void {
    var lettersSprite:Sprite = new lettersClass();
    lettersSprite.x = randomRange(100, 500);
    lettersSprite.y = randomRange(100, 500);
    stage.addChild(lettersSprite); 
    letters.push(lettersSprite);
}

现在,您可以遍历数组以执行所有操作。例如,要检查是否遇到任何障碍:

for each(var obstacle:DisplayObject in obstacles){
    if(frog.hitTestObject(obstacle) && hitTestShapes(frog, obstacle)){
        // The frog hit an obstacle!
    }
}

您还可以结合我们所有的&#34;移动&#34;函数合为一,根据类型移动每个障碍:

private function moveObstacles(e:Event):void {
    for each(var obstacle in obstacles){
        if(obstacle is WhiteCar){
            obstacle.x -= 3;
        }
        else if(obstacle is RedCar){
            obstacle.x += 3;
        }
        else if(obstacle is Truck){
            obstacle.x += 3;
        }
        else if(obstacle is Log){
            obstacle.x -= 5;
        }

        if(obstacle.x < -100){
            obstacle.x = 650;
        }
        else if(obstacle.x > 650){
            obstacle.x = -100;
        }

    }
}

最后,你真的只需要一个ENTER_FRAME处理程序。只需在那里调用你想要的任何功能。添加多个ENTER_FRAME处理程序可能会给管理带来麻烦。例如,只需执行此操作:

addEventListener(Event.ENTER_FRAME, update);

private function update(e:Event):void {
    moveObstacles();
    doOtherStuff();
    anythingYouNeedToDo();
}

这样你只需要removeEventListener(Event.ENTER_FRAME, update)来停止游戏,而不是一大堆ENTER_FRAME处理程序。

我还没有对这些代码进行测试,但是你得到了一般的想法。如果您对此有任何疑问,请告诉我,我可以提供帮助。