0
votes

I'm making a top down shooter for a college assignment. When I press the left mouse button to shoot bullets they freeze when they colide with the enemy movie clips that follow the player movie clip, when this happens the player movie clips can still be moved using the arrow keys so the SWF hasn't crashed.

The enemy and bullet movie clips are placed in an array and are both supposed to be removed upon collision with eachother.

In the output window I get this error message when the bullet movie clip enters the stage

bullet hit baddie 0

TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::Stage@2862e041 to flash.display.MovieClip.

at Bullet/removeSelf()

at Bullet/loop()

at Main/loop()

The bullet hit baddie 0 is there due to it being traced in the code.

Main.as

package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;

public class Main extends MovieClip
{
    public var player:Player;
    public var enemy:Enemy;

    public var bulletList:Array = [];

    public var mousePressed:Boolean = false; //keeps track of whether the mouse is currently pressed down
    public var delayCounter:int = 0; //this adds delay between the shots
    public var delayMax:int = 7; //change this number to shoot more or less rapidly
     
    var enemies:Array =  [];

    public function Main():void
    {
        player = new Player(stage, 320, 240);
        stage.addChild(player);

        //stage.addEventListener(MouseEvent.CLICK, shootBullet, false, 0, true); //remove this
        stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true);
        stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);

        stage.addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
        for(var numBaddies=0; numBaddies<6;numBaddies++){
            var enemy:Enemy = new Enemy(null);
            enemy.x = numBaddies*50;
            enemy.y = numBaddies*50
            stage.addChild(enemy);
            enemies.push(enemy);
        }
    }

    public function loop(e:Event):void
    {
        if(mousePressed) // as long as the mouse is pressed...
        {
            delayCounter++; //increase the delayCounter by 1
            if(delayCounter == delayMax) //if it reaches the max...
            {
                shootBullet(); //shoot a bullet
                delayCounter = 0; //reset the delay counter so there is a pause between bullets
                
           }
        }

        if(bulletList.length > 0)
        {
            for(var i:int = bulletList.length-1; i >= 0; i--)
            {
                bulletList[i].loop();
            }
        }
        
        for(var h = 0; h<bulletList.length; ++h)
        {
            if(bulletList[h].hitTestObject(this)){
              trace("player hit by baddie " + h);
               }
        }
        
        for(var u:int=0; u<enemies.length; u++) {
        Enemy(enemies[u]).moveTowards(player.x, player.y);
        }
    }
    

    public function mouseDownHandler(e:MouseEvent):void //add this function
    {
        mousePressed = true; //set mousePressed to true
    }

    public function mouseUpHandler(e:MouseEvent):void //add this function
    {
        mousePressed = false; //reset this to false
    }

    public function shootBullet():void //delete the "e:MouseEvent" parameter
    {
        var bullet:Bullet = new Bullet(stage, player.x, player.y, player.rotation, enemies);
        bullet.addEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved, false, 0, true);
        bulletList.push(bullet);
        stage.addChild(bullet);
    }

    public function bulletRemoved(e:Event):void
    {
        e.currentTarget.removeEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved);
        bulletList.splice(bulletList.indexOf(e.currentTarget),1);
    }
}
}

Enemy.as

package  {

import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;

public class Enemy extends MovieClip {
    
    public var bullets:Array;
    public var stageRef:Stage;

    private var enemyPositionX, enemyPositionY,xDistance,yDistance,myRotation:int;
    public function Enemy(bulletList:Array) {
        // constructor code
        bullets = bulletList;
    }
    
    public function moveTowards(playerX:int, playerY:int){
        xDistance = this.x - playerX;
        yDistance = this.y - playerY;


        myRotation = Math.atan2(yDistance, xDistance);

        this.x -= 3 * Math.cos(myRotation);
        this.y -= 3 * Math.sin(myRotation);
        
        
    }

    public function loopE():void{
    
    for(var i=0; i<bullets.length; ++i)
        {
            if(bullets[i].hitTestObject(this)){
               trace("you killed enemy " + i);
               removeSelf();
               }
        }
    }
    
    private function removeSelf()
    {
        removeEventListener(Event.ENTER_FRAME, loopE);
        if (stageRef.contains(this))
        stageRef.removeChild(this);
    }
}

}

Bullet.as

package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;

public class Bullet extends MovieClip
{
    private var stageRef:Stage; //checks if the bullet leaves the screen borders
    private var speed:Number = 10; //speed that the bullet will travel at
    private var xVel:Number = 0; //current x velocity
    private var yVel:Number = 0; //current y velocity
    private var rotationInRadians = 0; //convenient to store our rotation in radians instead of degrees
    private var allBaddies:Array;
    //our constructor requires: the stage, the position of the bullet, and the direction the bullet should be facing
    public function Bullet(stageRef:Stage, X:int, Y:int, rotationInDegrees:Number, enemies:Array):void
    {
        this.stageRef = stageRef;
        this.x = X;
        this.y = Y;
        this.rotation = rotationInDegrees;
        this.rotationInRadians = rotationInDegrees * Math.PI / 180; //convert degrees to radians, for trigonometry
        allBaddies = enemies;
    }
    
    public function loop():void //we don't need to include the "e:Event" because we aren't using an EventListener
    {
        for(var b=0; b<allBaddies.length; ++b)
        {
            if(allBaddies[b].hitTestObject(this)){
               trace("bullet hit baddie " + b);
               removeSelf();
               }
        }
        
        xVel = Math.cos(rotationInRadians) * speed; //uses the cosine to get the xVel from the speed and rotation
        yVel = Math.sin(rotationInRadians) * speed; //uses the sine to get the yVel

        x += xVel; //updates the position
        y += yVel;

        //if the bullet goes off the edge of the screen...
        if(x > stageRef.stageWidth || x < 0 || y > stageRef.stageHeight || y < 0)
        {
            this.parent.removeChild(this); //remove the bullet
        }
    }
    
    private function removeSelf()
    {
        removeEventListener(Event.ENTER_FRAME, loop);
        if (MovieClip(root).stageRef.contains(this))
        MovieClip(root).stageRef.removeChild(this);
    }
}
}

All help is appreciated, many thanks in advanced.

1

1 Answers

0
votes

You're getting the TypeError because the cast of root to a MovieClip fails. When you surround a variable in parentheses with a type name in front, you're asserting that the object is of that type (or extends that type). In the Bullet.removeSelf() function you have: MovieClip(root) - but in this case, root is of the type Stage, which does not extend MovieClip, resulting in the error.*

It is true that the Stage type has both contains and removeChild methods though, so you can just remove the cast. And in fact the Bullet class already has a reference to the stage in the form of stageRef, so you can just reuse that. Try changing the removeSelf() function to:

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

*(More info: the specific type of the root property varies depending on the context. Sometimes it will in fact be a MovieClip; other times Bitmap; in your case, as the error shows, it's a Stage - but the only guaranteed type is DisplayObject, which is the lowest common denominator type, from which the above types all inherit. Here's the Adobe documentation on the root property: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#root)