PDA

View Full Version : [AS3] Pong game: gotoAndStop causing Error #1009


60day
12-04-2008, 07:53 AM
Hi, I've been trying several forums to find an answer to this problem.

I'm building a pong game as a way of learning Flash and actionscript 3. and I'm using CS 4. Almost have it done.

The game consists of 4 frames: begin, play, win, and lose.

The code for begin works fine and the code for win and lose is the same so I will concentrate on the code for play and lose.

The actual game code in play works fine. Collision detection, score tracking, player paddle movement, AI paddle movment, etc. But there is one problem.

Problem: After the player or the computer gets to 5 points the game is supposed to go to the win or lose frame. I use gotoAndStop for this: gotoAndStop("lose"). This is where I get the "Error #1009: Cannot access a property or method of a null object reference."

From what I can tell it has to do with the gotoAndStop statements that are in the checkBoundaries function. One of the guys on the Adobe forum said this:

"in your code here the call is within the scope of 'ball' - you need to target the parent or main timeline - ie. parent.gotoAndStop("win"); "

It makes sense to me but I tried it and got a new error:

1061: Call to a possibly undefined method gotoAndStop through a reference with static type flash.display:DisplayObjectContainer.

Looking around it seemed like it might be the compiler not understanding the parent is a movieclip? To fix this I tried the code:

MovieClip(parent).gotoAndStop("lose");

The code compiled but I got a new error once I lost to the computer:

TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::Stage@b485b51 to flash.display.MovieClip.
at MethodInfo-9()
at pong3_fla::MainTimeline/fnBallEnterFrame()

I also trie MovieClip(root).gotoAndStop("lose"); which caused a 1009 error again.

My latest try is from a post on this site called "Trying (and Failing) to change things on the main time line (Root?)". The solution for this post made sense to me also. It said to have the movieclip dispatch an event, have the main timeline listen for the event, and then call the gotoAndStop function once the main timeline hears the event. Unfortunately, I couldn't get the code to work. Seems to be a common theme with me.

The attached zip has the full fla file. And below is the code from the play and lose frames.

Any thoughts?


//PLAY FRAME CODE

var playerScore:int = 0;
var computerScore:int = 0;
var relY:int;
var relPerc:Number;
var newDy:Number;

init();

function init(){
//turns off mouse pointer
Mouse.hide();

//gives ball initial direction
ball.dx = 15;
ball.dy = 6;

//Sets the speed of the computer's paddle. Higher speed equals a better
//opponent.
computerPaddle.speed = 8;
}

playerPaddle.addEventListener(Event.ENTER_FRAME, fnPlayerEnterFrame);
computerPaddle.addEventListener(Event.ENTER_FRAME, fnComputerEnterFrame);
ball.addEventListener(Event.ENTER_FRAME, fnBallEnterFrame);

function fnPlayerEnterFrame(event:Event):void{
//Player's paddle follows mouse
playerPaddle.y = stage.mouseY - (playerPaddle.height / 2);
}

function fnComputerEnterFrame(event:Event):void{
//Move the computer's paddle relative to the ball and difficulty
//setting (computerPaddle.speed)
if ((ball.y + (ball.height/2)) < (computerPaddle.y + (computerPaddle.height/2))){
computerPaddle.dy = -computerPaddle.speed;
} else {
computerPaddle.dy = computerPaddle.speed;
}
computerPaddle.y += computerPaddle.dy;
}

function fnBallEnterFrame(event:Event):void{
//move the ball
ball.move();

//check if it hit the top or bottom
ball.checkBoundaries();

//check if it hit a paddle
ball.checkPaddles();
}


ball.move = function(){
ball.x += ball.dx;
ball.y += ball.dy;
}

ball.checkBoundaries = function(){
if (ball.y < 0){
ball.dy = -ball.dy;
}
if (ball.y > stage.stageHeight){
ball.dy = -ball.dy;
}
if (ball.x < 0){
computerScore++;
computerScoreField.text = computerScore.toString();
if (computerScore >= 5){
gotoAndStop("lose");
}

ball.x = computerPaddle.x-50;
ball.y = computerPaddle.y + (computerPaddle.height / 2);

ball.dy = 0;
}

if (ball.x > stage.stageWidth){
playerScore++;
playerScoreField.text = playerScore.toString();

if (playerScore >= 5){
gotoAndStop("win");
}

ball.x = playerPaddle.x + 50;
ball.y = playerPaddle.y + (playerPaddle.height / 2);
ball.dy = 0;

}
}

ball.checkPaddles = function(){
if (ball.hitTestObject(playerPaddle)){
ball.dx = -ball.dx;
ball.dy = getDy(playerPaddle);
}
if (ball.hitTestObject(computerPaddle)){
ball.dx = -ball.dx;
ball.dy = getDy(computerPaddle);
}
}

function getDy(paddle){
relY = (ball.y + (ball.height/2)) - (paddle.y + (paddle.height/2));

relPerc = relY / paddle.height;

newDy = relPerc * 30;

return newDy;
}


//LOOSE FRAME CODE

Mouse.show();

btnPlay.addEventListener(MouseEvent.CLICK, fnPlay);

lsatdown
12-04-2008, 09:15 AM
Sorry I don't understand. When I play it, after 5 points from either me or the computer, it goes to win or lose???

Mazoonist
12-04-2008, 02:26 PM
I know what the problem is but I was unable to fix it completely just now. You have all these enter_frame functions running and they never get turned off. When you move to another frame they are still running, and they refer to objects that aren't there anymore. I tried adding a cleanup function:
function cleanup():void {
playerPaddle.removeEventListener(Event.ENTER_FRAME , fnPlayerEnterFrame);
computerPaddle.removeEventListener(Event.ENTER_FRA ME, fnComputerEnterFrame);
ball.removeEventListener(Event.ENTER_FRAME, fnBallEnterFrame);
}
And then calling it just before your gotoAndStop() calls. I still get the null object reference error, though. But I know I'm on the right track. I think the problem is that there is still a ball in play at that point. A little more debugging would solve it, I'm sure, but I don't have time at the moment. Maybe this will give you a push in the right direction, though.

60day
12-04-2008, 07:31 PM
Ahh, thanks for the help. I didn't know you had to do that. Complete newb to Flash programming. I'll try going down that path and see if I can find the issue. Thanks!

For lsatdown, there is a counter in the program that keeps track of how many times the player scored and how many times the computer scored. Once one of the counters reachs 5, the program should move to the "win" )if the player's counter is 5) or "lose" (if the computer's counter is 5) frame. This is what seems to be causing me trouble.

60day
12-04-2008, 10:16 PM
Mazoonist,

This definitely helps. Previously the 1009 error repeated itself indefinitely until I closed the app. Now it only happens once.

I looked for another enter_frame call that should be closed but these are the only 3 I could find. Is there another type of object I shouls close before calling gotoAndStop()?

I ask because my assumption is, like you said, I'm referring to something that is no longer there. For example, would I need to close the ball and paddle objects? If so, not sure how to do that.


var playerScore:int = 0;
var computerScore:int = 0;
var relY:int;
var relPerc:Number;
var newDy:Number;

init();

function init(){
//turns off mouse pointer
Mouse.hide();

//gives ball initial direction
ball.dx = 15;
ball.dy = 6;

//Sets the speed of the computer's paddle. Higher speed equals a better
//opponent.
computerPaddle.speed = 8;
}

playerPaddle.addEventListener(Event.ENTER_FRAME, fnPlayerEnterFrame);
computerPaddle.addEventListener(Event.ENTER_FRAME, fnComputerEnterFrame);
ball.addEventListener(Event.ENTER_FRAME, fnBallEnterFrame);

function fnPlayerEnterFrame(event:Event):void{
//Player's paddle follows mouse
playerPaddle.y = stage.mouseY - (playerPaddle.height / 2);
}

function fnComputerEnterFrame(event:Event):void{
//Move the computer's paddle relative to the ball and difficulty
//setting (computerPaddle.speed)
if ((ball.y + (ball.height/2)) < (computerPaddle.y + (computerPaddle.height/2))){
computerPaddle.dy = -computerPaddle.speed;
} else {
computerPaddle.dy = computerPaddle.speed;
}
computerPaddle.y += computerPaddle.dy;
}

function fnBallEnterFrame(event:Event):void{
//move the ball
ball.move();

//check if it hit the top or bottom
ball.checkBoundaries();

//check if it hit a paddle
ball.checkPaddles();
}


ball.move = function(){
ball.x += ball.dx;
ball.y += ball.dy;
}

ball.checkBoundaries = function(){
if (ball.y < 0){
ball.dy = -ball.dy;
}
if (ball.y > stage.stageHeight){
ball.dy = -ball.dy;
}
if (ball.x < 0){
computerScore++;
computerScoreField.text = computerScore.toString();
if (computerScore >= 5){
fnCleanUp();
gotoAndStop("lose");
}

ball.x = computerPaddle.x-50;
ball.y = computerPaddle.y + (computerPaddle.height / 2);

ball.dy = 0;
}

if (ball.x > stage.stageWidth){
playerScore++;
playerScoreField.text = playerScore.toString();

if (playerScore >= 5){
fnCleanUp();
gotoAndStop("win");
}

ball.x = playerPaddle.x + 50;
ball.y = playerPaddle.y + (playerPaddle.height / 2);
ball.dy = 0;

}
}

ball.checkPaddles = function(){
if (ball.hitTestObject(playerPaddle)){
ball.dx = -ball.dx;
ball.dy = getDy(playerPaddle);
}
if (ball.hitTestObject(computerPaddle)){
ball.dx = -ball.dx;
ball.dy = getDy(computerPaddle);
}
}

function getDy(paddle){
relY = (ball.y + (ball.height/2)) - (paddle.y + (paddle.height/2));

relPerc = relY / paddle.height;

newDy = relPerc * 30;

return newDy;
}

function fnCleanUp():void {
playerPaddle.removeEventListener(Event.ENTER_FRAME , fnPlayerEnterFrame);
computerPaddle.removeEventListener(Event.ENTER_FRA ME, fnComputerEnterFrame);
ball.removeEventListener(Event.ENTER_FRAME, fnBallEnterFrame);
}

fitz
12-05-2008, 03:33 PM
I d/led the fla and removed the event listeners too, and I'm getting just that 1 error as well. Can't figure out why though. Stange one. Be interested in finding out why when the solution surfaces.

60day
12-05-2008, 06:17 PM
I finally got it working. I took Mazoonist thoughts and looked for other objects I needed to remove. The code for the cleanup function now looks like this:


function fnCleanUp():void {
playerPaddle.removeEventListener(Event.ENTER_FRAME , fnPlayerEnterFrame);
computerPaddle.removeEventListener(Event.ENTER_FRA ME, fnComputerEnterFrame);
ball.removeEventListener(Event.ENTER_FRAME, fnBallEnterFrame);
removeChild(playerPaddle);
removeChild(computerPaddle);
removeChild(ball);
}