0
votes

I am making a small game from a tutorial where you hit small tofu's with your cursor and gather up points and accuracy - I have implemented a start button that works and goes to frame(2), where the game starts.

I would like to create a stop button but when i make a button in the scene - the button does not function (cant click on it) and when i hit a tofu it gets the 1009 error? (Cannot access a property or method of a null object reference.)

The game works when i have no stop button but i can't exit the game.

How can i create a stop button or a menu inside the game that allows the user to go back to a previous scene or stop the game?

// define some global variables which let you track the player's statistics.
var hits:int = 0;
var misses:int = 0;
var shots:int = 0;
var cDepth:int = 100;
var level:int = 1;

// define some runtime variables which are used in calculations.
var xSpeed:Number = 3;
var stageWidth:Number = 480;
var stageHeight:Number = 580;

/* attach the crosshair_mc movie clip instance from the Library onto the Stage. 
   This clip is used as a custom mouse cursor. */
var crosshairClip:MovieClip = new crosshair_mc();
crosshairClip.mouseEnabled = false;
addChild(crosshairClip);

// hide the mouse cursor
Mouse.hide();

/* every time the mouse cursor moves within the SWF file, 
   update the position of the crosshair movie clip instance on the Stage. */
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
function mouseMoveHandler(event:MouseEvent):void {
    crosshairClip.x = event.stageX;
    crosshairClip.y = event.stageY;
};
/* when the mouse button is clicked, check to see if the cursor is within the boundaries of the Stage. 
   If so, increment the number of shots taken. */
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(event:MouseEvent):void {
    if (bg_mc.hitTestPoint(event.stageX, event.stageY, false)) {
        shots++;
        updateStats();
    }
};

// define a TextFormat which is used to format the stats_txt text field.
var my_fmt:TextFormat = new TextFormat();
my_fmt.bold = true;
my_fmt.font = "Arial";
my_fmt.size = 12;
my_fmt.color = 0xFFFFFF;
// create a text field to display the player's statistics.
var stats_txt:TextField = new TextField();
stats_txt.x = 10;
stats_txt.y = 0;
stats_txt.width = 530;
stats_txt.height = 22;
addChild(stats_txt);
// apply the TextFormat to the text field.
stats_txt.defaultTextFormat = my_fmt;
stats_txt.selectable = false;
updateStats();

// add an onEnterFrame event to the main timeline so new tofu is constantly added to the game.
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
function enterFrameHandler(event:Event):void {
    // randomly add new target's to the Stage.
    if (randRange(0, 20) == 0) {
        var thisMC:MovieClip;
        // attach a new instance of the tofu instance from the library onto the Stage, and give it a unique depth.
        var randomTofu:Number = randRange(1, 3);
        switch (randomTofu) {
            case 1:
                thisMC = new tofu1_mc();
                break;
            case 2:
                thisMC = new tofu2_mc();
                break;
            case 3:
                thisMC = new tofu3_mc();
                break;
            default:
                return;
                break;
        }

        cDepth++;
        // set the starting postition of the current target movie clip so it is just off to the left of the Stage.
        thisMC.x = -thisMC.width;
        /* create a random number between 80 and 100.
           This is used to set the current movie clip's scale, 
           alpha and speed that it moves across the Stage. */
        var scale:int = randRange(80, 100);
        /* set the _xscale and _yscale properties of the current movie clip. 
           This allows for some minor variations of the targets within the game. */
        thisMC.scaleX = scale / 100;
        thisMC.scaleY = scale / 100;
        thisMC.alpha = scale / 100;
        thisMC.speed = xSpeed + randRange(0, 3) + level;
        /* set a random _y value for the target. 
           Now, instead of all targets flying along the same path, 
           they vary their vertical position slightly. */
        thisMC.y = Math.round(Math.random() * 350) + 65;
        thisMC.name = "tofu" + cDepth;
        /* create an onEnterFrame handler that executes a couple dozen times per second. 
           Update the target's position on the Stage. */
        thisMC.addEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
        thisMC.addEventListener(MouseEvent.CLICK, tofuClickHandler);
        addChild(thisMC);
        // swap the custom cursor to the higher depth
        swapChildren(thisMC, crosshairClip);
    }
};
/* create a function to update the player's statistics on the Stage. 
   You're displaying number of shots taken, number of targets "hit",
   number of targets "missed", the percentage of hits vs misses, 
   overall accuracy (number of shots taken vs number of hit targets). */
function updateStats() {
    var targetsHit:Number = Math.round(hits/(hits+misses)*100);
    var accuracy:Number = Math.round((hits/shots)*100);
    if (isNaN(targetsHit)) {
        targetsHit = 0;
    }
    if (isNaN(accuracy)) {
        accuracy = 0;
    }
    stats_txt.text = "shots:"+shots+"\t"+"hits: "+hits+"\t"+"misses: "+misses+"\t"+"targets hit: "+targetsHit+"%"+"\t"+"accuracy: "+accuracy+"%"+"\t"+"level:"+level;
}

/* create a function that returns a random integer between two specified numbers. 
   This allows you to add some subtle differences in size and speed for the movie clips on the Stage. */
function randRange(minNum:Number, maxNum:Number):Number {
    return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}


function tofuEnterFrameHandler(event:Event):void {
    var tofuMC:MovieClip = event.currentTarget as MovieClip;
    /* move the target horizontally along the Stage. 
       Currently all targets will move from left to right. */
    tofuMC.x += tofuMC.speed;
    /* slightly decrement the _y position of the current target movie clip. 
    This makes it appear like the targets are flying slightly higher as they move across the Stage. */
    tofuMC.y -= 0.4;
    /* if the current position of the target is no longer on the Stage, 
       count the target as a "miss" and delete the instance. 
       If the instance wasn't deleted from the Stage, 
       the user's computer would eventually slow to a crawl. */
    if (tofuMC.x > stageWidth) {
        misses++;
        updateStats();
        removeChild(tofuMC);
        tofuMC.removeEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
    }
}

// when the target movie clip instance is pressed, count it as a "hit".
function tofuClickHandler(event:MouseEvent):void {
    var tofuMC:MovieClip = event.currentTarget as MovieClip
    // update the player's stats
    hits++;
    if ((hits%40) == 0) {
        level++;
    }
    updateStats();
    /* go to the movie clip's label named "hit" 
      (which allows you to show a clever animation when the instance is hit.) */
    tofuMC.gotoAndPlay("hit");
    // create an onEnterFrame event for the current movie clip instance.
    tofuMC.addEventListener(Event.ENTER_FRAME, tofuHitEnterFrameHandler);
    /* delete the onPress event handler. 
       This makes it so the target cannot continually be clicked while it is falling from the sky. */
    tofuMC.removeEventListener(MouseEvent.CLICK, tofuClickHandler);
    tofuMC.removeEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
}

function tofuHitEnterFrameHandler(event:Event):void {
    var tofuMC:MovieClip = event.currentTarget as MovieClip;
    // set some local variables that you'll use to animate the target falling from the sky.
    var gravity:int = 20;
    var ymov:int = tofuMC.y + gravity;
    // ***** xmov *= 0.5;
    // increment the rotation of the current movie clip clock-wise by 5 degrees.
    tofuMC.rotation += 5;
    /* set the _x and _y properties of the movie clip on the Stage, 
       this allows us to make the target look like it is semi-realistically 
       falling from the sky instead of just dropping straight down. */
    tofuMC.x += xSpeed;
    tofuMC.y = ymov;
    /* after the _y position is off of the Stage, 
       remove the movie clip so that the coordinates aren't continually calculated */
    if (tofuMC.y > stageHeight) {
        removeChild(tofuMC);
        tofuMC.removeEventListener(Event.ENTER_FRAME, tofuHitEnterFrameHandler);
    }
}
1
Apparently you need to learn how to do proper cleanup of a running game. You have a decent set of tofu flying downwards, and a click listener - you need to carefully remove all the flying tofu off stage, strip them off listeners, remove all other listeners and then go back to frame 1 with start button. This is a general idea.Vesper
Thanks Vesper! I am a bit of a noob at AS3 but basically i need to removeEventListener for the stage objects and i can imagine i also need to remove the Mouse.Hide function. I thought maybe one could change the stage width/height and add a menu where the stage is not present..KevinDasman
Changing stage's width and height is not an easy task (it's doable, but via external calls), but placing the menu somewhere outside the visible area of the stage is one of the common ways to handle menu hide/show. Make sure to disable tab jumping to the menu from elsewhere, otherwise a player can reach the menu via tabs and cause undesired game behavior.Vesper

1 Answers

0
votes

The stage is confused, because some objects don't exist when you change frames, so you have to remove all of your events from the stage:

stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);

And then you can call the gotoAndStop() function to whatever frame you want...