AS3 - 太空射击敌人射击

时间:2016-03-24 10:23:35

标签: actionscript-3 flashdevelop

我对AS3非常陌生并且编程一般而且我在AS3中开发了太空射击游戏并且在敌人射击方面遇到了麻烦。敌人从屏幕顶部垂直向下飞行,一旦他们的y坐标等于玩家的坐标,就应该发射两次(一次向左,一次向右)。这工作正常,除了从30秒到2分钟之后,发生以下错误。

  

TypeError:错误#1009:无法访问空对象引用的属性或方法。       在EnemyShip2 / fireWeapon()[G:\ Games Related \ 1942 \ src \ EnemyShip2.as:78]       在EnemyShip2 / loop2()[G:\ Games Related \ 1942 \ src \ EnemyShip2.as:65]

     

TypeError:错误#1009:无法访问空对象引用的属性或方法。       在EnemyShot / removeSelf()[G:\ Games Related \ 1942 \ src \ EnemyShot.as:43]       在EnemyShot / loop()[G:\ Games Related \ 1942 \ src \ EnemyShot.as:36]

以下是相关代码,适用于敌舰类以及敌方射击类。

Enemy Ship

package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.utils.Timer;

    /**
     * ...
     * @author D Nelson
     */

    [Embed(source = "../assets/enemyship2.png")]
    //This enemy moves relatively slowly and fires horizontal shots
    public class EnemyShip2 extends Bitmap
    {
        private var vy:Number = 3;
        //private var ay:Number = .2;
        private var target:HeroShip;
        private var enemyShip2:EnemyShip2;
        private var enemyfireTimer:Timer;
        private var enemycanFire:Boolean = true;

        public function EnemyShip2(target:HeroShip):void
        {
            this.target = target;
            scaleX = 0.3;
            scaleY = 0.3;
            x = Math.floor(Math.random() * 550);
            y = -105;
            addEventListener(Event.ENTER_FRAME, loop2, false, 0, true);
            enemyfireTimer = new Timer(1000, 1);
            enemyfireTimer.addEventListener(TimerEvent.TIMER, handleenemyfireTimer, false, 0, true);
        }

        private function handleenemyfireTimer(e:TimerEvent) : void
        {
            //the timer runs, so a shot can be fired again
            enemycanFire = true;
        }


        private function removeSelf2():void 
        { 
            removeEventListener(Event.ENTER_FRAME, loop2);
            if (stage.contains(this))
            {
                stage.removeChild(this);
            }
        }   

        private function loop2 (e:Event):void
        {
            //vy += ay;
            y += vy;
            if (y > stage.stageHeight)
            {
                removeSelf2();
            }

            if (y >= target.y && (enemycanFire))
            {
                fireWeapon();
                enemycanFire = false;
                enemyfireTimer.start();
            }

            if (this.x > 540 || this.x < 10)
            {
                removeSelf2();
            }
        }

        private function fireWeapon():void
        {
            stage.addChild(new EnemyShot(target, x, y, -4));
            stage.addChild(new EnemyShot(target, x, y, +4));
        }
    }
}

敌人射击

package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.events.Event;
    import flash.display.Stage;

    /**
     * ...
     * @author D Nelson
     */

    [Embed(source="../assets/enemyshot.png")]
    public class EnemyShot extends Bitmap
    {
        private var speed:Number;
        private var target:HeroShip;
        private var vx:Number;

        public function EnemyShot(target:HeroShip, x:Number, y:Number, vx:Number) 
        {
            this.target = target;
            this.x = x;
            this.y = y;
            this.vx = vx;
            scaleX = 0.3;
            scaleY = 0.3; 
            addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
        }

        private function loop(e:Event) : void
        {
            x += vx;
            if (x >= 600 || x <= -50) 
            {               
                removeSelf();
            }
        }

        private function removeSelf():void 
        { 
            removeEventListener(Event.ENTER_FRAME, loop); 
            if (stage.contains(this))
            {
                stage.removeChild(this);
            }
        }    
    }
}

如果有任何帮助,还提供主要课程。

package 
{
    import flash.display.Sprite;
    import flash.display.MovieClip;
    import flash.display.DisplayObject;
    import flash.display.Stage;
    import flash.events.*;
    import flash.events.Event;  
    import flash.events.EventDispatcher;
    import flash.events.KeyboardEvent;
    import flash.events.TimerEvent;
    import flash.ui.Mouse;
    import flash.utils.*;
    import flash.utils.ByteArray;
    import flash.utils.Timer;
    import flash.text.*;
    import flash.media.Sound;
    import flash.media.SoundChannel;

    /**
     * ...
     * @author D Nelson
     */

    public class Main extends MovieClip
    {
        [Embed(source = "snd/gamemusic2.mp3")]
        private var MySound : Class;         
        private var mainsound : Sound;
        private var shootsound: Sound = new ShootSound;
        private var sndChannel:SoundChannel = new SoundChannel;
        public var heroShip:HeroShip;
        public var enemyShip1:EnemyShip1
        public var enemyShip2:EnemyShip2
        public var enemyShip3:EnemyShip3
        public var enemyShip4:EnemyShip4
        public var bossShip: BossShip
        public var enemyShot: EnemyShot;
        public var playerShot: PlayerShot;
        private var background1:Background1;
        private var background2:Background2;
        public static const scrollspeed:Number = 2;
        public var playerShotArray:Array = new Array()
        public var enemyShotArray:Array = new Array()
        public var enemies1Array:Array = new Array()
        public var enemies2Array:Array = new Array()
        private var fireTimer:Timer; //this creates a delay between each shot
        private var canFire:Boolean = true; //this checks if a shot can be fired                

        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
            mainsound = (new MySound) as Sound;
            shootsound = (new ShootSound) as Sound;
            mainsound.play();
            background1 = new Background1();
            background2 = new Background2();
            //setting the backgrounds one below another
            background1.y = 0;
            background2.y = background1.height;
            //add background at the lowest depth level
            stage.addChildAt(background1,0);
            stage.addChildAt(background2, 0);           
            //sets up the timer and its listener
            fireTimer = new Timer(250, 1);
            fireTimer.addEventListener(TimerEvent.TIMER, handlefireTimer, false, 0, true);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, handleCharacterShoot);
            //background scrolling effect
            stage.addEventListener(Event.ENTER_FRAME, backgroundScroll);
            //loop for enemy1 variety
            stage.addEventListener(Event.ENTER_FRAME, loop1, false, 0, true);
            //loop for enemy2 variety
            stage.addEventListener(Event.ENTER_FRAME, loop2, false, 0, true);
            //speed of player shots
            setInterval(playerShootMovement, 10);           
        }

        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            //entry point           
            heroShip = new HeroShip();
            stage.addChild(heroShip);

            //test values for enemies
            /*enemyShip1 = new EnemyShip1();
            stage.addChildAt(enemyShip1, 2);
            enemyShip1.y = stage.stageWidth * 0.3;
            enemyShip1.x = 300;

            enemyShip2 = new EnemyShip2();
            stage.addChildAt(enemyShip2, 2);
            enemyShip2.y = stage.stageWidth * 0.3;
            enemyShip2.x = 200;

            enemyShip3 = new EnemyShip3();
            stage.addChildAt(enemyShip3, 2);
            enemyShip3.y = stage.stageWidth * 0.3;
            enemyShip3.x = 100;

            enemyShip4 = new EnemyShip4();
            stage.addChildAt(enemyShip4, 2);
            enemyShip4.y = stage.stageWidth * 0.3;
            enemyShip4.x = 400;

            bossShip = new BossShip();
            stage.addChildAt(bossShip, 1);
            bossShip.y = 10;
            bossShip.x = 130;*/         

            Mouse.hide();           
        }

        private function handlefireTimer(e:TimerEvent) : void
        {
            //the timer runs, so a shot can be fired again
            canFire = true;
        }

        public function playerShoot():void
        {
            //if canFire is true, allow a shot to be fired, then set canFire to false and start the timer again
            //else, do nothing          
            if (canFire)
            {
                //Add new line to the array
                playerShotArray.push(playerShot = new PlayerShot);
                //Spawn missile in ship
                playerShot.y = heroShip.y;
                playerShot.x = heroShip.x+11;
                addChild(playerShot);
                canFire = false;
                fireTimer.start();              
                sndChannel = shootsound.play();
            }
        }

        public function playerShootMovement():void
        {
            //code adapted from the Pie Throw tutorial
            for (var i:int = 0; i < playerShotArray.length; i++) 
            {
                playerShotArray[i].y -= 10;

                if (playerShotArray[i].y == 850)
                {
                    playerShotArray.shift();
                }
            }           
        }

        public function handleCharacterShoot(e:KeyboardEvent):void
        {
            /** 
             * SpaceBar = 32
             */                                 
            if (e.keyCode == 32)
            {
                playerShoot();
            }           
        }       

        public function backgroundScroll (evt:Event):void
        {
            background1.y += scrollspeed;
            background2.y += scrollspeed;
            if (background1.y >= stage.stageHeight)
            {
                //the background is below the visible stage area, put it above the other background       
                background1.y = background2.y - background2.height;
            }
            else if (background2.y >= stage.stageHeight)
            {

                background2.y = background1.y - background2.height;
            }           
        }

        //EnemyShip 1 spawning
        private function loop1(e:Event):void
        {
            //generates probability for the ship to spawn (lower number to increase odds, decrease it to decrease odds)
            if (Math.floor(Math.random() * 55) == 5)
            {
                var enemyShip1:EnemyShip1 = new EnemyShip1(heroShip); 
                enemyShip1.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy1, false, 0, true);
                enemies1Array.push(enemyShip1); 
                stage.addChild(enemyShip1);
            }
        }

        private function removeEnemy1(e:Event):void
        {
            //removes the enemy that most recently left the screen from the array
            enemies1Array.splice(enemies1Array.indexOf(e.currentTarget), 1);
        }

        //EnemyShip2 spawning
        private function loop2(e:Event):void
        {
            if (Math.floor(Math.random() * 40) == 5)
            {
                var enemyShip2:EnemyShip2 = new EnemyShip2(heroShip); 
                enemyShip2.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemy2, false, 0, true);
                enemies2Array.push(enemyShip2); 
                stage.addChild(enemyShip2);
            }
        }

        private function removeEnemy2(e:Event):void
        {
            enemies2Array.splice(enemies2Array.indexOf(e.currentTarget), 1);
        }
    }
}

最初,我认为这是与敌人开枪射击同时距离屏幕两侧太远,但事实似乎并非如此。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

每当删除对象时,您都需要确保删除ENTER_FRAME个侦听器。

实际上,我的建议是在整个游戏对象中添加ENTER_FRAME个处理程序。这很难管理,并导致你遇到的错误。相反,添加一个ENTER_FRAME作为核心游戏循环,并通过在主游戏类中维护的游戏对象列表上调用update()函数来更新对象。删除对象后,您将无法再调用update()。只需删除ENTER_FRAME处理程序,就可以轻松暂停游戏。

例如,这是我喜欢用于简单游戏的模式:

interface IGameObject {
    update():void;
}

class Enemy extends Sprite implements IGameObject {
    public update():void {
        // move, fire, etc
    }
}

class Player extends Sprite implements IGameObject {
    public update():void {
        // move, fire, etc
    }
}

class Bullet extends Bitmap implements IGameObject {
    public update():void {
        // move, collide, etc
    }
}

class Main extends Sprite {
    private objects:Vector.<IGameObject> = new <IGameObject>[];

    public start():void {
        addEventListener(Event.ENTER_FRAME, update);
    }

    public stopGame():void {
        removeEventListener(Event.ENTER_FRAME, update);
    }

    private function update(e:Event):void {
        for each (var object:IGameObject in objects) {
            object.update();
        }
    }

    public addObject(object:IGameObject):void {
        objects.push(object);
        addChild(object as DisplayObject);
    }

    public removeObject(object:IGameObject):void {
        objects.splice(objects.indexOf(object), 1);
        removeChild(object as DisplayObject);
    }
}

使用addObjectremoveObject添加和删除对象。您可以通过对Main的引用或通过从对象发送的事件处理程序来调用它们。