AS3 - MouseEvent.CLICK会在添加侦听器之前触发鼠标单击

时间:2013-06-05 14:41:58

标签: actionscript-3

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

我遇到的问题是,当用户点击重置按钮时,游戏切换屏幕会被正确删除,并且正确的游戏(玩家,小行星,eventListeners)会被正确地添加到舞台上,但同时也是如此即使用户在点击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

我已经读过某个地方一直调度事件,无论是否有任何侦听器正在侦听它们,所以我怀疑我的MouseEvent.CLICK侦听器是从重置按钮的时间开始点击鼠标按钮单击,即使之后将此侦听器添加到舞台中。

我没有足够的AS3或编程经验来确定是否真的如此,我该怎么做才能确保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 监听器不响应之前发生的任何点击加入舞台,所以对此的任何帮助将不胜感激。

====

修改

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

MouseEvent.CLICK这是从Main

调用的
private function startGame():void

{ //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

2 个答案:

答案 0 :(得分:3)

正在发生的事情是MouseEvent.CLICKbubbling event。在Flash中,事件有三个阶段:“捕获阶段”,“目标”阶段和“冒泡阶段”。您可以在此Adobe article中阅读相关内容。

您的重置按钮的点击事件处理程序发生在“目标”阶段。如果您在重置按钮单击处理程序中跟踪事件的阶段,它将显示event.phase为2.每docs,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(); 
} 

答案 1 :(得分:0)

听起来像你之前的游戏迭代没有移除MOUSE.CLICK事件监听器。即使游戏被移除,MOUSE.CLICK事件也会继续触发您添加到其中的任何处理程序,例如; addEventListener(MOUSE.ClICK,)。删除游戏后,您还需要删除EventListener(MOUSE.CLICK,)。