2

私は AS3 を初めて使用"asteroids"し、ゲームオーバー画面とresetButtonユーザーが再びプレイできるシンプルなゲームを作成しました。ユーザーがリセット ボタンをクリックすると、ゲーム オーバー画面とリセット ボタンがステージから削除され、ゲーム自体がイベント リスナーと共にステージに追加されます。これらの 1 つは、関数を呼び出す にMouseEvent.CLICK追加されたリスナーです。この関数は弾丸を描画し、それをステージに追加します (コードの他の部分が弾丸を画面上で動かします)。stagefireBullet

bullet私が抱えている問題は、ユーザーがリセットボタンをクリックすると、ゲームオーバー画面が正しく削除され、適切なゲーム (プレーヤー、小惑星、 eventListeners ) がステージに正しく追加されると同時に、ユーザーが をクリックした後にクリックしていなくても、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 とフラッシュについて何も知らないと思っていたので、上記の疑似コードを使用しました。以下は、生成された .swf を含む完全な .as ファイルへのリンクです。以下は、完全な関連関数です https://www.dropbox.com/sh/a4rlasq8o0taw82/wP3rB6KPKS

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

{
        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 では、イベントには「キャプチャ フェーズ」、「ターゲット」フェーズ、「バブリング フェーズ」の 3 つのフェーズがあります。これについては、このアドビの記事で読むことができます。

リセット ボタンのクリック イベント ハンドラーは、「ターゲット」フェーズで発生します。リセット ボタンのクリック ハンドラーでイベントのフェーズをトレースすると、event.phase2 であることがわかります。ドキュメントによると、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 に答える