2016-03-24 41 views
-1

我對AS3和編程一般都很陌生,我一直在AS3開發太空射擊遊戲,並且在敵方射擊時遇到麻煩。敵人從屏幕頂部向下垂直飛行,並且一旦他們的y座標與玩家的座標相同,就應該發射兩發(一個向左,一個向右)。這工作正常,除了從30秒到2分鐘之後,發生以下錯誤。AS3 - 太空射擊敵人射擊

TypeError: Error #1009: Cannot access a property or method of a null object reference. at EnemyShip2/fireWeapon()[G:\Games Related\1942\src\EnemyShip2.as:78] at EnemyShip2/loop2()[G:\Games Related\1942\src\EnemyShip2.as:65]

TypeError: Error #1009: Cannot access a property or method of a null object reference. at EnemyShot/removeSelf()[G:\Games Related\1942\src\EnemyShot.as:43] at EnemyShot/loop()[G:\Games Related\1942\src\EnemyShot.as:36]

下面是相關的代碼,對於敵方的船隻類以及敵方的射擊類。

敵艦

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); 
     } 
    } 
} 

起初,我以爲是敵人開槍而被太遠屏幕兩側的事,但是這似乎並不如此。任何幫助將不勝感激。

+0

我猜你的元素沒有被添加到舞臺或舞臺上,而不是你的類中的東西。自從我使用AS3以來,一直都不知道。 – putvande

+0

是的,fireWeapon()中唯一可以爲null的是舞臺。聽起來像你的船沒有加入舞臺? – Philarmon

+0

[Actionscript error#1009]的可能重複(http://stackoverflow.com/questions/1287770/actionscript-error-1009) – Brian

回答

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或通過您從對象派發的事件處理程序來調用它們。