2

我是 AS3 的新手,并且制作了一个简单"asteroids"的游戏,带有一个游戏结束屏幕和一个resetButton让用户再次玩的游戏。当用户点击重置按钮时,游戏结束屏幕和重置按钮会从舞台上移除,并且游戏本身会与 eventListeners 一起添加到舞台上。其中之一是MouseEvent.CLICK添加到的监听器stage,它调用一个fireBullet函数。此函数绘制一个子弹并将其添加到舞台(代码的其他部分然后使子弹在屏幕上移动)。

我遇到的问题是,当用户单击重置按钮时,游戏结束屏幕被正确删除,并且游戏本身(玩家、小行星、事件监听器)被正确添加到舞台,但同时也会bullet触发即使用户在点击reset button.

我的gameOver()功能是这样的:

stage.removeChild() all objects
stage.removeEventListener() all listeners
null out all objects

draw and add to the stage the game over text and resetButton
addEventListener(MouseEvent.CLICK, onReset) to the resetButton

然后,onReset()函数如下所示:

stage.removeChild() the gameover text and the resetButton
call gameStart();

gameStart()函数如下所示:

initialize variables
draw and add player and asteroids on the screen
add eventListeners including MouseEvent.Click, fireBullet

我在每个函数上添加了跟踪以查看发生了什么,这就是流程:

added fireBullet listener //this is gameStart() function being called from Main() and adding everything to the stage the first time
fired bullet //shooting at the asteroids
fired bullet
fired bullet
fireBullet listener should have been removed //this is gameOver() being called that removes everything from the stage and adds the resetButton
clicked on reset
added fireBullet listener //gameStart() being called again from onReset() function
fired bullet //I did not click a second time after clicking on reset

我在某处读到,无论是否有任何侦听器实际上在侦听它们,事件都会一直发送,所以我怀疑我的 MouseEvent.CLICK 侦听器从单击重置按钮时开始拾取鼠标按钮单击,甚至虽然这个听众后来被添加到舞台上。

我没有足够的 AS3 或编程经验来确定这是否真的是这种情况,我可以做些什么来确保MouseEvent.CLICK听众不会响应在它被添加到舞台之前发生的任何点击,所以任何帮助对此将不胜感激。

====

编辑

我假设我有一个逻辑问题或者对 AS3 和闪存一无所知,所以我只是使用了上面的伪代码。下面是完整的 .as 文件的链接,包括生成的 .swf 下面是完整的相关功能 https://www.dropbox.com/sh/a4rlasq8o0taw82/wP3rB6KPKS

private function startGame():void这是从 Main 调用的

{
        //initialize variables
        bulletArray = [];
        cleanupBullets = [];
        bulletSpeed = 10;
        score = 0;

        asteroid1Speed = 0;
        asteroid2Speed = 0;
        asteroid3Speed = 0;
        asteroid4Speed = 0;

        //draw player and asteroids
        ship = drawPlayer();
        asteroid1 = drawAsteroid();
        asteroid2 = drawAsteroid();
        asteroid3 = drawAsteroid();
        asteroid4 = drawAsteroid();

        //embarrasing and inefficient code to get random number between -5 and 5 without a 0
        asteroid1Speed = Math.ceil(Math.random() * 10 -5);
        if (asteroid1Speed == 0)
            asteroid1Speed = returnNonZero(asteroid1Speed);

        asteroid2Speed = Math.ceil(Math.random() * 10 -5);
        if (asteroid2Speed == 0)
            asteroid2Speed = returnNonZero(asteroid2Speed);

        asteroid3Speed = Math.ceil(Math.random() * 10 -5);
        if (asteroid3Speed == 0)
            asteroid3Speed = returnNonZero(asteroid3Speed);

        asteroid4Speed = Math.ceil(Math.random() * 10 -5);
        if (asteroid4Speed == 0)
            asteroid4Speed = returnNonZero(asteroid4Speed);

        //trace(asteroid1Speed, asteroid2Speed, asteroid3Speed, asteroid4Speed);

        //add asteroids to stage
        stage.addChild(asteroid1);
        stage.addChild(asteroid2);
        stage.addChild(asteroid3);
        stage.addChild(asteroid4);

        //position player and add to stage
        ship.x = 40;
        ship.y = 40;

        stage.addChild(ship);

        //add event listeners
        stage.addEventListener(Event.ENTER_FRAME, onFrame);
        stage.addEventListener(MouseEvent.CLICK, fireBullet);
        trace("added fireBullet listener");
}

private function gameOver():void这是从onFrame我不包括的(称为每一帧)函数中调用的(它太大并且不完全相关)。当所有小行星都被移除时调用它。

{
        //remove any remaining bullets off the screen
        for each (var item:Sprite in bulletArray)
        {
            stage.removeChild(item);
        }
        //null out objects and remove listeners
        bulletArray = null;
        stage.removeEventListener(Event.ENTER_FRAME, onFrame);
        stage.removeEventListener(MouseEvent.CLICK, fireBullet);
        //check if the listener has actually been removed
        if (!(stage.hasEventListener(MouseEvent.CLICK))) {
            trace("fireBullet listener should have been removed");
        }

        stage.removeChild(ship);
        ship = null

        //graphic for resetButton
        resetButton = new Sprite();
        resetButton.graphics.beginFill(0xFFFFFF);
        resetButton.graphics.drawRect(0, 0, 100, 50);
        resetButton.graphics.endFill();

        //position for resetButton
        resetButton.x = 250;
        resetButton.y = 300;

        //text for resetButton
        resetTextField = new TextField();
        var resetTextFormat:TextFormat = new TextFormat();
        resetTextFormat.size = 30;
        resetTextFormat.color = 0x000000;
        resetTextField.defaultTextFormat = resetTextFormat;
        resetTextField.selectable = false;
        resetTextField.text = "RESET";
        resetButton.addChild(resetTextField);

        //add resetButton and listener
        stage.addChild(resetButton);
        resetButton.addEventListener(MouseEvent.CLICK, onReset);

        //gameover text
        gameOverTxtField = new TextField();
        gameOverFormat = new TextFormat();
        gameOverFormat.size = 50;
        gameOverFormat.color = 0xFFFFFF; 
        gameOverFormat.align = "center";
        gameOverTxtField.defaultTextFormat = gameOverFormat;
        gameOverTxtField.selectable = false;
        gameOverTxtField.text = "GAME OVER";
        gameOverTxtField.width = 660;
        gameOverTxtField.height = 200;
        gameOverTxtField.x = -10;
        gameOverTxtField.y = 20;

        stage.addChild(gameOverTxtField);
}

private function onReset(e:MouseEvent):void

{
        trace("clicked on reset");
        //remove gameover objects and null them
        resetButton.removeEventListener(MouseEvent.CLICK, onReset);
        stage.removeChild(gameOverTxtField);
        stage.removeChild(resetButton);
        resetButton = null;
        gameOverTxtField = null;

        //restart the game
        startGame();
}
4

2 回答 2

3

正在发生的事情MouseEvent.CLICK是一个冒泡事件。在 Flash 中,事件具有三个阶段:“捕获阶段”、“到达目标”阶段和“冒泡阶段”。您可以在这篇Adob​​e 文章中了解它。

您的重置按钮的单击事件处理程序发生在“目标”阶段。如果您在重置按钮单击处理程序中跟踪事件的阶段,它将显示event.phase为 2。根据文档,1 =“捕获阶段”,2 =“目标”,3 =“冒泡阶段”。

在重置按钮单击处理程序完成其工作后,该事件然后通过显示列表重新冒泡。由于 位于stage显示列表的顶部,因此单击事件“冒泡”到舞台。到那时,您已经重新开始游戏并添加了舞台的点击事件处理程序。所以舞台的点击处理程序也会被触发。

event.phase您可以通过跟踪方法中的值来确认这一点bulletFired()

private function fireBullet(e:MouseEvent):void 
{ 
    // most of this time it will trace out 2 for the phase
    // except when you click on an asteroid when firing or
    // click the reset button
    trace("fired bullet, event phase: " + e.eventPhase);
    bullet = drawBullet(); 
    bullet.y = ship.y; 
    bullet.x = ship.x + (ship.width / 2); 
    bulletArray.push(bullet); 
    stage.addChild(bullet); 
} 

要解决此问题,您可以在您的方法中阻止事件冒泡onReset()

private function onReset(e:MouseEvent):void 
{
    // prevent this event from bubbling
    e.stopPropagation();
    trace("clicked on reset"); 
    //remove gameover objects and null them 
    resetButton.removeEventListener(MouseEvent.CLICK, onReset); 
    stage.removeChild(gameOverTxtField); 
    stage.removeChild(resetButton); 
    resetButton = null; 
    gameOverTxtField = null; 
    //restart the game 
    startGame(); 
} 
于 2013-06-05T18:53:16.363 回答
0

在我看来,您的游戏的上一次迭代没有删除 MOUSE.CLICK 事件侦听器。即使游戏被移除,MOUSE.CLICK 事件将继续触发您添加到其中的任何处理程序,例如;添加事件监听器(鼠标单击,)。当游戏被移除时,您还需要 removeEventListener(MOUSE.CLICK, )。

于 2013-06-05T15:10:27.007 回答