0


似乎我在 cancelAnimationFrame 和 clearTimeout 之间迷失了自己。不知道如何停止 Snake 游戏。这是我启动动画的代码片段:

window.addEventListener( "load", function gameLoop() {
  globalTimer = setTimeout( function() {
    snakeObj.update();
    requestAnimationFrame( gameLoop );
  }, 100 );
 });

通过这种方式,我试图停止我的游戏:

if ( parseInt(this.snakeHead.style.top) == fieldObj.h ||
         parseInt(this.snakeHead.style.left) == fieldObj.w ) {
        gameObj.stopGame();// stop game message
        clearTimeout(globalTimer);
    }

但它不起作用 - 出现停止游戏消息,但动画仍在继续。

这是我所有的代码:

// field object
var globalTimer;
var fieldObj = {
  field: document.getElementById( "field" ),
  w: 480,
  h: 580
},
gameObj = {
  pastCoord: [],
  getRandomCoord: function( num ) { // 20 is width of one body segment
    return  Math.round( Math.floor(( Math.random() * num)) / 20 ) * 20;
  },
  createSnakeTarget: function() {
  var t = document.createElement( "div" );
      t.id = "snake-target";
      t.style.top = this.getRandomCoord( fieldObj.h ) + "px";
      t.style.left = this.getRandomCoord( fieldObj.w ) + "px";

      fieldObj.field.appendChild( t );
  },
  stopGame: function() {
    var stopMessage = document.createElement("div");
        stopMessage.className = "stop-message";
        stopMessage.style.background = "white";

        fieldObj.field.appendChild( stopMessage );
        //TODO: write message to stopGame
  }
};

gameObj.createSnakeTarget();

// snake object
snakeObj = {
  snakeHead: document.getElementById("head"),
  snakeBody: document.getElementsByClassName( "snake-body" ),// there must be one element
  p: {
    x: 0, // position x 
    y: 0  // position y
  },
  v: {
    x: 20, // velocity ( one loop move one unit of snake body)
    y: 20
  },
  keys: {
    up: null,
    l: null,
    r: null,
    down: null
  },
  stepInSnakeBody: 0,// go through snakeBody
  stepInPastCoord: 0,// go through pastCoord
  addBodySegment: function() {
    var seg = document.createElement( "div" );
          seg.className = "snake-body";
          fieldObj.field.appendChild( seg );

          seg.style.top = this.p.x + "px";// receive current position
          seg.style.left = this.p.y + "px";

  },
  update: function() {
    var snakeTarget = document.getElementById("snake-target");

    if ( this.keys.down ) {
       this.p.x += this.v.x;
    } else if ( this.keys.up ) {
       this.p.x -= this.v.x;
    } else if ( this.keys.r ) {
       this.p.y += this.v.y;
    }else if ( this.keys.l ) {
       this.p.y -= this.v.y;
    }
    this.snakeHead.style.top = this.p.x + "px";
    this.snakeHead.style.left = this.p.y + "px";

    gameObj.pastCoord.push([this.p.x, this.p.y]);// create and push coord of snake head

    //every step index in snakeBody receive coords from pastCoord
    this.snakeBody[this.stepInSnakeBody].style.top = gameObj.pastCoord[this.stepInPastCoord][0] + "px";
    this.snakeBody[this.stepInSnakeBody].style.left = gameObj.pastCoord[this.stepInPastCoord][1] + "px";

    this.stepInSnakeBody++; // increment index every step
    this.stepInPastCoord++;
    if ( this.stepInSnakeBody === this.snakeBody.length ) {
      this.stepInSnakeBody = 0; // when stepInSnakeBody equal length of snake go to zero
                                //and apply coords
    }
    // detect collision with target
    if ( this.snakeHead.style.top === snakeTarget.style.top &&
         this.snakeHead.style.left === snakeTarget.style.left ) {
        fieldObj.field.removeChild( snakeTarget );
        gameObj.createSnakeTarget();
        snakeObj.addBodySegment();
    }
    if ( parseInt(this.snakeHead.style.top) == fieldObj.h ||
         parseInt(this.snakeHead.style.left) == fieldObj.w ) {
        gameObj.stopGame();
        clearTimeout(globalTimer);
    }
  }
};

// Crome works only with keydown and keyup
window.addEventListener('keydown', function() {
// before changing direction you have to put previous direction to false
  if ( event.keyCode == 38 ) {
      snakeObj.keys.up = true;
      snakeObj.keys.down = false;
  } else if ( event.keyCode == 40 ) {
      snakeObj.keys.down = true;
      snakeObj.keys.up = false;
  } else if ( event.keyCode == 39 ) {
      snakeObj.keys.r = true;
      snakeObj.keys.up = false;
      snakeObj.keys.down = false;
  } else if ( event.keyCode == 37 ) {
      snakeObj.keys.l = true;
      snakeObj.keys.r = false;
      snakeObj.keys.up = false;
      snakeObj.keys.down = false;
  }
}, false);
//TODO: add event hendler to click to some button

window.addEventListener( "load", function gameLoop() {
  globalTimer = setTimeout( function() {
    snakeObj.update();
    requestAnimationFrame( gameLoop );
  }, 100 );
 });

这是 codepen(仅在 CHROME 中工作)http://codepen.io/Kuzyo/pen/pamzC
感谢您的帮助。

4

1 回答 1

1

你需要打电话cancelAnimationFrame

但是,您需要确保您requestAnimationFrame 之前 update致电。当前您正在调用stopGame,但是在stopGame/update完成之后,会requestAnimationFrame安排另一个循环,因此即使您stopGame调用cancelAnimationFrame它也不会停止动画。

另一种方法是使用您在gameLoop函数中签入的布尔标志。

于 2013-08-05T13:15:28.947 回答