title: AS3 - Space Shooter Enemy Shots
body: <p>I'm very new to AS3 and programming in general and I've been developing a space shooter game in AS3 and have run into trouble regarding the enemy shots. The enemies fly vertically down from the top of the screen and should fire two shots (one going left and one going right) once their y coordinates equal that of the player. This works fine, except after anything from 30 seconds to 2 minutes, the following errors occur. </p>
  
  <blockquote>
    <p>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]</p>
    
    <p>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]</p>
  </blockquote>
  
  <p>Below is the relevant code, for the enemy ship class as well as the enemy shot class.</p>
  
  <p>Enemy Ship</p>
  
  <pre><code>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 &gt; stage.stageHeight)
              {
                  removeSelf2();
              }
  
              if (y &gt;= target.y &amp;&amp; (enemycanFire))
              {
                  fireWeapon();
                  enemycanFire = false;
                  enemyfireTimer.start();
              }
  
              if (this.x &gt; 540 || this.x &lt; 10)
              {
                  removeSelf2();
              }
          }
  
          private function fireWeapon():void
          {
              stage.addChild(new EnemyShot(target, x, y, -4));
              stage.addChild(new EnemyShot(target, x, y, +4));
          }
      }
  }
  </code></pre>
  
  <p>Enemy Shot</p>
  
  <pre><code>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 &gt;= 600 || x &lt;= -50) 
              {               
                  removeSelf();
              }
          }
  
          private function removeSelf():void 
          { 
              removeEventListener(Event.ENTER_FRAME, loop); 
              if (stage.contains(this))
              {
                  stage.removeChild(this);
              }
          }    
      }
  }
  </code></pre>
  
  <p>Also provided is the main class, in case that is of any help.</p>
  
  <pre><code>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 &lt; 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 &gt;= 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 &gt;= 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);
          }
      }
  }
  </code></pre>
  
  <p>Initially I thought it was to do with enemies firing shots while being too far to either side of the screen, but that doesn't seem to be the case. Any help would be greatly appreciated. </p>