AS3 - 游戏计时器无法正确计算开始时间

时间:2011-06-22 10:31:47

标签: actionscript-3 timer

我正在根据Gary Rosenzweig最新的Actionscript 3书在AS3中构建游戏。它有一个游戏计时器问题,不仅是我的,还有他的演示,我无法弄明白。

游戏就像小行星一样,在开始时将四块岩石放置在舞台的角落,然后开始在舞台周围随机移动。问题是所使用的计时器是在Flash文件启动的那一刻启动的,而不是玩家点击开始按钮的那一刻。因此,如果你在开始屏幕上持续5秒钟,然后在游戏实际开始时单击游戏,那么它们将在5秒的游戏之后出现,这可能就在玩家身上了。

我发布了我认为适用的代码部分。有人可以告诉我如何修改这个,以便当玩家真正开始游戏时,岩石开始在适当的位置。我很确定这是我所包含的最后一个功能就是问题,但我已经包含了其他相关部分,以便为您提供更完整的图片。

package {
import flash.display.*;
import flash.events.*;
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import flash.text.*;
import flash.utils.getTimer;
import flash.utils.Timer;
import flash.geom.Point;
import flash.net.SharedObject;
import flash.media.Sound;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.media.SoundChannel;

Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

public class VirusDefender extends MovieClip {
    static const shipRotationSpeed:Number = .1;
    static const rockSpeedStart:Number = .03;
    static const rockSpeedIncrease:Number = .01;
    static const missileSpeed:Number = .2;
    static const thrustPower:Number = .15;
    static const shipRadius:Number = 20;
    static const startingShips:uint = 3;

    // game objects
    private var ship:Ship;
    private var rocks:Array;
    private var missiles:Array;

    // animation timer
    private var lastTime:uint;

    // arrow keys
    private var rightArrow:Boolean = false;
    private var leftArrow:Boolean = false;
    private var upArrow:Boolean = false;

    // ship velocity
    private var shipMoveX:Number;
    private var shipMoveY:Number;

    // timers
    private var delayTimer:Timer;
    private var shieldTimer:Timer;

    // game mode
    private var gameMode:String;
    private var shieldOn:Boolean;

    // ships and shields
    private var shipsLeft:uint;
    private var shieldsLeft:uint;
    private var shipIcons:Array;
    private var shieldIcons:Array;
    private var scoreDisplay:TextField;

    // score and level
    private var gameScore:Number;
    private var gameLevel:uint;

    // sprites
    private var gameObjects:Sprite;
    private var scoreObjects:Sprite;
    var gameBackground:GameBackground = new GameBackground();

    // sounds
    var sndFire:fire_sound;
    var sndFireChannel:SoundChannel;
    var sndThruster:thruster_sound;
    var sndThrusterChannel:SoundChannel;
    var sndShield:shield_sound;
    var sndShieldChannel:SoundChannel;
    var sndExplosion:explosion_sound;
    var sndExplosionChannel:SoundChannel;
    var sndBubble:bubble_sound;
    var sndBubbleChannel:SoundChannel;


    // start the game
    public function startSpaceRocks() {

        // set up sprites
        addChild(gameBackground);
        setChildIndex(gameBackground,0); // I added this
        gameObjects = new Sprite();
        addChild(gameObjects);
        scoreObjects = new Sprite();
        addChild(scoreObjects);

        // reset score objects
        gameLevel = 1;
        shipsLeft = startingShips;
        gameScore = 0;
        createShipIcons();
        createScoreDisplay();

        // set up listeners
        trace("add moveGameObjects event listener");
        addEventListener(Event.ENTER_FRAME,moveGameObjects);

        leftButton.addEventListener(TouchEvent.TOUCH_OVER,leftPress);
        leftButton.addEventListener(TouchEvent.TOUCH_OUT,leftRelease);

        rightButton.addEventListener(TouchEvent.TOUCH_OVER,rightPress);
        rightButton.addEventListener(TouchEvent.TOUCH_OUT,rightRelease);

        thrusterButton.addEventListener(TouchEvent.TOUCH_OVER,thrusterPress);
        thrusterButton.addEventListener(TouchEvent.TOUCH_OUT,thrusterRelease);

        shieldButton.addEventListener(TouchEvent.TOUCH_OVER,shieldPress);

        fireButton.addEventListener(TouchEvent.TOUCH_OVER,firePress);



        // Left Button
        function leftPress(event:TouchEvent):void{
            leftArrow = true;
        }           
        function leftRelease(event:TouchEvent):void{
            leftArrow = false;
        }

        // Right button
        function rightPress(event:TouchEvent):void{
            rightArrow = true;
        }
        function rightRelease(event:TouchEvent):void{
            rightArrow = false;
        }

        // Thruster button
        function thrusterPress(event:TouchEvent):void{
            sndThruster=new thruster_sound();
            sndThrusterChannel=sndThruster.play();
            upArrow = true;
            if (gameMode == "play") ship.gotoAndStop(2);
        }
        function thrusterRelease(event:TouchEvent):void{
            sndThrusterChannel.stop();
            upArrow = false;
            if (gameMode == "play") ship.gotoAndStop(1);
        }

        // Fire button
        function firePress(event:TouchEvent):void{
            sndFire=new fire_sound();
            sndFireChannel=sndFire.play();
            newMissile();
        }

        // Shield button
        function shieldPress(event:TouchEvent):void{
            startShield(false);
        }


        // start 
        gameMode = "delay";
        trace("gameMode - delay");
        shieldOn = false;
        missiles = new Array();
        trace("nextRockWave fired");
        nextRockWave(null);
        newShip(null);
    }


    // SCORE OBJECTS

    // draw number of ships left
    public function createShipIcons() {
        shipIcons = new Array();
        for(var i:uint=0;i<shipsLeft;i++) {
            var newShip:ShipIcon = new ShipIcon();
            newShip.x = 165+i*25; //165
            newShip.y = 273; //273
            scoreObjects.addChild(newShip);
            shipIcons.push(newShip);
        }
    }

    // draw number of shields left
    public function createShieldIcons() {
        shieldIcons = new Array();
        for(var i:uint=0;i<shieldsLeft;i++) {
            var newShield:ShieldIcon = new ShieldIcon();
            newShield.x = 310-i*25; //530
            newShield.y = 273; //15
            scoreObjects.addChild(newShield);
            shieldIcons.push(newShield);
        }
    }

    // put the numerical score at the upper right
    public function createScoreDisplay() {
        updateScore();
    }

    // new score to show
    public function updateScore() {
        score.text = addCommaInNumber(gameScore);
    }

    // remove a ship icon
    public function removeShipIcon() {
        scoreObjects.removeChild(shipIcons.pop());
    }

    // remove a shield icon
    public function removeShieldIcon() {
        scoreObjects.removeChild(shieldIcons.pop());
    }

    // remove the rest of the ship icons
    public function removeAllShipIcons() {
        while (shipIcons.length > 0) {
            removeShipIcon();
        }
    }

    // remove the rest of the shield icons
    public function removeAllShieldIcons() {
        while (shieldIcons.length > 0) {
            removeShieldIcon();
        }
    }


    // SHIP CREATION AND MOVEMENT

    // create a new ship
    public function newShip(event:TimerEvent) {
        // if ship exists, remove it
        if (ship != null) {
            gameObjects.removeChild(ship);
            ship = null;
        }

        // no more ships
        if (shipsLeft < 1) {
            endGame();
            return;
        }

        // create, position, and add new ship
        ship = new Ship();
        ship.gotoAndStop(1);
        ship.x = 240; //275
        ship.y = 160; //200
        ship.rotation = -90;
        ship.shield.visible = false;
        gameObjects.addChild(ship);

        // set up ship properties
        shipMoveX = 0.0;
        shipMoveY = 0.0;
        gameMode = "play";

        // set up shields
        shieldsLeft = 3;
        createShieldIcons();

        // all lives but the first start with a free shield
        if (shipsLeft != startingShips) {
            startShield(true);
            sndShield=new shield_sound();
            sndShieldChannel=sndShield.play();
        }
    }

    // animate ship
    public function moveShip(timeDiff:uint) {

        // rotate and thrust
        if (leftArrow) {
            ship.rotation -= shipRotationSpeed*timeDiff;
        } else if (rightArrow) {
            ship.rotation += shipRotationSpeed*timeDiff;
        } else if (upArrow) {
            shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower;
            shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower;
        }

        // move
        ship.x += shipMoveX;
        ship.y += shipMoveY;

        // wrap around screen
        if ((shipMoveX > 0) && (ship.x > 470)) {
            ship.x -= 490;
        }
        if ((shipMoveX < 0) && (ship.x < -20)) {
            ship.x += 500;
        }
        if ((shipMoveY > 0) && (ship.y > 320)) {
            ship.y -= 340;
        }
        if ((shipMoveY < 0) && (ship.y < -20)) {
            ship.y += 340;
        }
    }

    // remove ship
    public function shipHit() {
        gameMode = "delay";
        ship.gotoAndPlay("explode");
        sndExplosion=new explosion_sound();
        sndExplosionChannel=sndExplosion.play();
        removeAllShieldIcons();
        delayTimer = new Timer(2000,1);
        delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,newShip);
        delayTimer.start();
        removeShipIcon();
        shipsLeft--;
    }

    // turn on shield for 3 seconds
    public function startShield(freeShield:Boolean) {
        if (shieldsLeft < 1) return; // no shields left
        if (shieldOn) return; // shield already on

        // turn on shield and set timer to turn off
        ship.shield.visible = true;
        sndShield=new shield_sound();
        sndShieldChannel=sndShield.play();
        shieldTimer = new Timer(3000,1);
        shieldTimer.addEventListener(TimerEvent.TIMER_COMPLETE,endShield);
        shieldTimer.start();

        // update shields remaining
        if (!freeShield) {
            removeShieldIcon();
            shieldsLeft--;
        }
        shieldOn = true;
    }

    // turn off shield
    public function endShield(event:TimerEvent) {
        ship.shield.visible = false;
        shieldOn = false;
    }

    // ROCKS        

    // create a single rock of a specific size
    public function newRock(x,y:int, rockType:String) {
        trace("newRock fired");
        // create appropriate new class
        var newRock:MovieClip;
        var rockRadius:Number;
        if (rockType == "Big") {
            newRock = new Rock_Big();
            rockRadius = 35;
        } else if (rockType == "Medium") {
            newRock = new Rock_Medium();
            rockRadius = 20;
        } else if (rockType == "Small") {
            newRock = new Rock_Small();
            rockRadius = 10;
        }


        // choose a random look
        newRock.gotoAndStop(Math.ceil(Math.random()*3));

        // set start position
        newRock.x = x;
        newRock.y = y;

        // set random movement and rotation
        var dx:Number = Math.random()*2.0-1.0;
        var dy:Number = Math.random()*2.0-1.0;
        var dr:Number = Math.random();

        // add to stage and to rocks list
        gameObjects.addChild(newRock);
        setChildIndex(gameObjects,1); // I added this
        rocks.push({rock:newRock, dx:dx, dy:dy, dr:dr, rockType:rockType, rockRadius: rockRadius});
    }

    // create four rocks
    public function nextRockWave(event:TimerEvent) {
        rocks = new Array();
        newRock(30,30,"Big"); //100 100
        newRock(30,290,"Big"); // 100 300
        newRock(450,30,"Big"); // 450 100
        newRock(450,290,"Big"); // 450 300
        gameMode = "play";
    }

    // animate all rocks
    public function moveRocks(timeDiff:uint) {
        for(var i:int=rocks.length-1;i>=0;i--) {

            // move the rocks
            var rockSpeed:Number = rockSpeedStart + rockSpeedIncrease*gameLevel;
            rocks[i].rock.x += rocks[i].dx*timeDiff*rockSpeed;
            rocks[i].rock.y += rocks[i].dy*timeDiff*rockSpeed;

            // rotate rocks
            rocks[i].rock.rotation += rocks[i].dr*timeDiff*rockSpeed;

            // wrap rocks
            if ((rocks[i].dx > 0) && (rocks[i].rock.x > 470)) {
                rocks[i].rock.x -= 490;
            }
            if ((rocks[i].dx < 0) && (rocks[i].rock.x < -20)) {
                rocks[i].rock.x += 490;
            }
            if ((rocks[i].dy > 0) && (rocks[i].rock.y > 325)) {
                rocks[i].rock.y -= 345;
            }
            if ((rocks[i].dy < 0) && (rocks[i].rock.y < -25)) {
                rocks[i].rock.y += 345;
            }
        }
    }

    public function rockHit(rockNum:uint) {
        // create two smaller rocks
        sndBubble=new bubble_sound();
        sndBubbleChannel=sndBubble.play();
        if (rocks[rockNum].rockType == "Big") {
            newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium");
            newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Medium");
        } else if (rocks[rockNum].rockType == "Medium") {
            newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small");
            newRock(rocks[rockNum].rock.x,rocks[rockNum].rock.y,"Small");
        }
        // remove original rock
        gameObjects.removeChild(rocks[rockNum].rock);
        rocks.splice(rockNum,1);
    }


    // MISSILES

    // create a new Missile
    public function newMissile() {
        // create
        var newMissile:Missile = new Missile();

        // set direction
        newMissile.dx = Math.cos(Math.PI*ship.rotation/180);
        newMissile.dy = Math.sin(Math.PI*ship.rotation/180);

        // placement
        newMissile.x = ship.x + newMissile.dx*shipRadius;
        newMissile.y = ship.y + newMissile.dy*shipRadius;

        // add to stage and array
        gameObjects.addChild(newMissile);
        missiles.push(newMissile);
    }

    // animate missiles
    public function moveMissiles(timeDiff:uint) {
        for(var i:int=missiles.length-1;i>=0;i--) {
            // move
            missiles[i].x += missiles[i].dx*missileSpeed*timeDiff;
            missiles[i].y += missiles[i].dy*missileSpeed*timeDiff;
            // moved off screen
            if ((missiles[i].x < 0) || (missiles[i].x > 485) || (missiles[i].y < 0) || (missiles[i].y > 325)) {
                gameObjects.removeChild(missiles[i]);
                delete missiles[i];
                missiles.splice(i,1);
            }
        }
    }

    // remove a missile
    public function missileHit(missileNum:uint) {
        gameObjects.removeChild(missiles[missileNum]);
        missiles.splice(missileNum,1);
    }

    // GAME INTERACTION AND CONTROL
    public function moveGameObjects(event:Event) {
        // get timer difference and animate
        var timePassed:uint = getTimer() - lastTime;
        lastTime += timePassed;
        moveRocks(timePassed);

        if (gameMode != "delay") {
            moveShip(timePassed);
        }
        moveMissiles(timePassed);
        checkCollisions();
    }

    // look for missiles colliding with rocks
    public function checkCollisions() {
        // loop through rocks
        rockloop: for(var j:int=rocks.length-1;j>=0;j--) {
            // loop through missiles
            missileloop: for(var i:int=missiles.length-1;i>=0;i--) {
                // collision detection 
                if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y),
                        new Point(missiles[i].x,missiles[i].y))
                            < rocks[j].rockRadius) {

                    // remove rock and missile
                    rockHit(j);
                    missileHit(i);

                    // add score
                    gameScore += 10;
                    updateScore();

                    // break out of this loop and continue next one
                    continue rockloop;
                }
            }

            // check for rock hitting ship
            if (gameMode == "play") {
                if (shieldOn == false) { // only if shield is off
                    if (Point.distance(new Point(rocks[j].rock.x,rocks[j].rock.y),
                            new Point(ship.x,ship.y))
                                < rocks[j].rockRadius+shipRadius) {

                        // remove ship and rock
                        shipHit();
                        rockHit(j);
                    }
                }
            }
        }

        // all out of rocks, change game mode and trigger more
        if ((rocks.length == 0) && (gameMode == "play")) {
            gameMode = "betweenlevels";
            gameLevel++; // advance a level
            levelTextBox.text = "Infection: " + gameLevel;
            delayTimer = new Timer(2000,1);
            delayTimer.addEventListener(TimerEvent.TIMER_COMPLETE,nextRockWave);
            delayTimer.start();
        }
    }

    public function endGame() {
        // remove all objects and listeners
        removeChild(gameObjects);
        removeChild(scoreObjects);
        removeChild(gameBackground);
        gameObjects = null;
        scoreObjects = null;
        removeEventListener(Event.ENTER_FRAME,moveGameObjects);
        gameMode = "gameOver";
        gotoAndStop("gameover");
    }

    /***** ADD COMMAS TO NUMBERS *******/
    function addCommaInNumber (number : Number) : String
    {
        var integer : String = "" ;
        var fraction : String = "" ;
        var string : String = number.toString();
        var array : Array = string.split(".");
        var regex : RegExp = /(\d+)(\d{3})/;

        integer = array[0];

        while( regex.test(integer) )
        {
            integer = integer.replace(regex,'$1' + ',' + '$2');
        }

        if (array[1])
        { fraction = integer.length > 0 ? '.' + array[1] : ''; }

        return integer + fraction;
    }


}

}

2 个答案:

答案 0 :(得分:1)

根据您发布的代码,我无法安全地回答您的问题,但您应该在第一次调用startSpaceRocks()时进行检查。这应该在您的开始按钮的点击处理程序中。

除此之外,您的问题标题并未反映出问题。完全没有定时器的问题,当“定时器”启动时出现问题。

答案 1 :(得分:1)

您认为应用于问题的代码部分不正确。

计时器可以和它的声明一起启动:

private var myTimer:Timer = new Timer(delay, repeat);

但是因为你在声明时没有启动计时器(如你的片段所示)

// timers
private var delayTimer:Timer;
private var shieldTimer:Timer;

必须有一些其他功能才能启动。将启动计时器的操作移动到您想要启动计时器的任何位置。例如:进入 startspacerocks()功能

如果不是问题,请发布适用于您的问题的相关代码。


修改

我认为你的答案在于 moveGameObjects 功能。

尝试按如下方式修改功能:

  // GAME INTERACTION AND CONTROL
  public function moveGameObjects(event:Event) {

        //Current Time
        var currentTime:uint = getTimer();

        //Initiate lastTime
        if(lastTime == 0) lastTime = currentTime;

        // get timer difference and animate
        var timePassed:uint = currentTime - lastTime;
        lastTime += timePassed;

        moveRocks(timePassed);

        if (gameMode != "delay") {
            moveShip(timePassed);
        }
        moveMissiles(timePassed);
        checkCollisions();
  }