如何使用javascript中的requestAnimationFrame()减慢我的动画速度

问题描述 投票:0回答:2

现在我正在使用JavaScript编写Conway的生活游戏,我遇到的问题是使用requestAnimationFrame()进行动画制作。当我在浏览器中加载游戏时,动画在闪烁时运行得太快。我想知道是否有人可以提供任何建议,关于我如何减慢动画速度以便看到它正常运行可见?

Javascript代码如下:

$(function(event) {

    var GRIDWIDTH = 400;
    var GRIDHEIGHT = 400;
    var gameGrid = createGrid(GRIDWIDTH); //Grid used to display the grid
    var newGameGrid = createGrid(GRIDWIDTH); //Grid used to update game state

    //creates the grid for the game, using an array of empty arrays
    function createGrid(rows) {
      var gridArray = []; //is the game grid
      //for loop that creates the grid array, each element is an empty array to create the multi-dimensional array
      for (var i = 0; i < rows; i++) {
        gridArray[i] = [];
      }
    return gridArray;
    }

    //will populate the grid randomly with alive and dead cells
    function populateGrid() {
      for (var rows = 0; rows < GRIDHEIGHT; rows++) { //goes across the rows within the grid
        for (var cols = 0; cols < GRIDWIDTH; cols++) { //goes across the columns within the grid
            var cell = Math.floor(Math.random() * 2 ); //the cells of the grid is either a 1 or 0 (alive or dead), chosen at random
            if (cell === 1) { //if the cell variable is the same as the integer value 1 and same type int then the element at gameGrid[rows][cols] is set to a 1 else a 0, this is done randomly.
            gameGrid[rows][cols] = 1;
          }
            else {
            gameGrid[rows][cols] = 0;
          }
        }
      }
    }

    //Will draw the game grid on the screen including cells
    function drawGrid() {
      // var gameCanvas = $("#gameCanvas"); //gets the gameCanvas element
      var ctx = $("#gameCanvas")[0].getContext("2d");
      ctx.clearRect(0, 0, 400, 400);
      //both loops go through the rows and columns respectively and draws the pixel in the grid in the specified colour
      for (var rows = 1; rows < GRIDHEIGHT; rows++) {
        for (var cols = 1; cols < GRIDWIDTH; cols++) {
          if (gameGrid[rows][cols] === 1) { //if the element is a 1 the pixel is coloured (red) to represent it is alive
            ctx.fillStyle = "#FF0000";
            ctx.fillRect(rows, cols, 1, 1);
          }
        }
      }
    }

    //this function will update the grid to show the new position of the pixels
    function updateGrid() {
      for (var rows = 1; rows < GRIDHEIGHT - 1; rows++) {
        for (var cols = 1; cols < GRIDWIDTH - 1; cols++) {
          var totalNeighbours = 0; //holds the total neighbours a cell has
          //calculations to add the neighbours
          totalNeighbours += gameGrid[rows-1][cols-1]; //top left
          totalNeighbours += gameGrid[rows-1][cols]; //top center
          totalNeighbours += gameGrid[rows-1][cols+1] //top right

          totalNeighbours += gameGrid[rows][cols-1] //middle left
          totalNeighbours += gameGrid[rows][cols+1] //middle right

          totalNeighbours += gameGrid[rows+1][cols-1] //bottom left
          totalNeighbours += gameGrid[rows+1][cols] //bottom center
          totalNeighbours += gameGrid[rows+1][cols+1] //bottom right

          //Game of life rules:

          //alive cell rules
          if (gameGrid[rows][cols] === 1) {
            switch(totalNeighbours) {
              //rule 1 any live cell with fewer than two live neighbours dies, as if by underpopulation
              case totalNeighbours < 2:
                newGameGrid[rows][cols] = 0;
                break;
              //rule 2 any live cell with two or three live neighbours lives on to the next generation
              case totalNeighbours == 2:
              case totalNeighbours == 3:
                newGameGrid[rows][cols] = 1;
                break;
              //rule 3 any live cell with more than three live neighbours dies, as if by overpopulation
              case totalNeighbours > 3:
                newGameGrid[rows][cols] = 0;
                break;
            }
          }
          //dead cell rule 4 any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
          else if (gameGrid[rows][cols] === 0) {
            if (totalNeighbours == 3) {
              newGameGrid[rows][cols] = 1;
              }
            }
          }
        }
        //iterate through the rows and columns and gameGrid is set to the newGameGrid with the updated cells in the grid
        for (var rows = 0; rows < GRIDWIDTH; rows++) {
          for (var cols = 0; cols < GRIDHEIGHT; cols++) {
            gameGrid[rows][cols] = newGameGrid[rows][cols];
          }
        }
      }

      populateGrid();
      start();
      function start() {
        drawGrid();
        updateGrid();
        requestAnimationFrame(start);
      }

    })
The html is simple as follows:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Conway's Game Of Life</title>
    <script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
    <script type="text/javascript" src="../js/index.js"></script>
    <link rel="stylesheet" href="../css/index.css">
    <link href="https://fonts.googleapis.com/css?family=Anton" rel="stylesheet">
  </head>
  <body>
    <div class="gameScreen">
      <div class="title">John Conway's Game Of Life</div>
      <canvas id="gameCanvas" width="400" height="400" style="border:1px solid #000000;"></canvas>
    </div>
  </body>
</html>
javascript html animation requestanimationframe
2个回答
0
投票

也看到了

this answer

我认为你应该使用渲染之间经过的时间和速度因子。

例如,您可以定义您希望主角在一秒钟内移动200px。然后 - 使用渲染之间经过的时间,您可以计算您想要移动他的距离(模型代码):

var distance_to_move = 200px * time_since_last_render / 1000;
setNewPosition();
render();

因此,如果你自上次渲染后经过的时间正好是500毫秒,那么在这个渲染中你将移动他100px。


0
投票

这就是你如何使用requestAnimationFrame:你传递给它的函数接受一个参数,即时间戳。您可以使用它来计算通过的时间。在此示例中,步骤设置为2s(2000ms)。请注意,您需要从requestAnimationFrame(start);而不是start();开始:

$(function(event) {

    var GRIDWIDTH = 400;
    var GRIDHEIGHT = 400;
    var gameGrid = createGrid(GRIDWIDTH); //Grid used to display the grid
    var newGameGrid = createGrid(GRIDWIDTH); //Grid used to update game state

    //creates the grid for the game, using an array of empty arrays
    function createGrid(rows) {
      var gridArray = []; //is the game grid
      //for loop that creates the grid array, each element is an empty array to create the multi-dimensional array
      for (var i = 0; i < rows; i++) {
        gridArray[i] = [];
      }
      return gridArray;
    }

    //will populate the grid randomly with alive and dead cells
    function populateGrid() {
      for (var rows = 0; rows < GRIDHEIGHT; rows++) { //goes across the rows within the grid
        for (var cols = 0; cols < GRIDWIDTH; cols++) { //goes across the columns within the grid
            var cell = Math.floor(Math.random() * 2 ); //the cells of the grid is either a 1 or 0 (alive or dead), chosen at random
            if (cell === 1) { //if the cell variable is the same as the integer value 1 and same type int then the element at gameGrid[rows][cols] is set to a 1 else a 0, this is done randomly.
            gameGrid[rows][cols] = 1;
          }
            else {
            gameGrid[rows][cols] = 0;
          }
        }
      }
    }

    //Will draw the game grid on the screen including cells
    function drawGrid() {
      // var gameCanvas = $("#gameCanvas"); //gets the gameCanvas element
      var ctx = $("#gameCanvas")[0].getContext("2d");
      ctx.clearRect(0, 0, 400, 400);
      //both loops go through the rows and columns respectively and draws the pixel in the grid in the specified colour
      for (var rows = 1; rows < GRIDHEIGHT; rows++) {
        for (var cols = 1; cols < GRIDWIDTH; cols++) {
          if (gameGrid[rows][cols] === 1) { //if the element is a 1 the pixel is coloured (red) to represent it is alive
            ctx.fillStyle = "#FF0000";
            ctx.fillRect(rows, cols, 1, 1);
          }
        }
      }
    }

    //this function will update the grid to show the new position of the pixels
    function updateGrid() {
      for (var rows = 1; rows < GRIDHEIGHT - 1; rows++) {
        for (var cols = 1; cols < GRIDWIDTH - 1; cols++) {
          var totalNeighbours = 0; //holds the total neighbours a cell has
          //calculations to add the neighbours
          totalNeighbours += gameGrid[rows-1][cols-1]; //top left
          totalNeighbours += gameGrid[rows-1][cols]; //top center
          totalNeighbours += gameGrid[rows-1][cols+1] //top right

          totalNeighbours += gameGrid[rows][cols-1] //middle left
          totalNeighbours += gameGrid[rows][cols+1] //middle right

          totalNeighbours += gameGrid[rows+1][cols-1] //bottom left
          totalNeighbours += gameGrid[rows+1][cols] //bottom center
          totalNeighbours += gameGrid[rows+1][cols+1] //bottom right

          //Game of life rules:

          //alive cell rules
          if (gameGrid[rows][cols] === 1) {
            switch(totalNeighbours) {
              //rule 1 any live cell with fewer than two live neighbours dies, as if by underpopulation
              case totalNeighbours < 2:
                newGameGrid[rows][cols] = 0;
                break;
              //rule 2 any live cell with two or three live neighbours lives on to the next generation
              case totalNeighbours == 2:
              case totalNeighbours == 3:
                newGameGrid[rows][cols] = 1;
                break;
              //rule 3 any live cell with more than three live neighbours dies, as if by overpopulation
              case totalNeighbours > 3:
                newGameGrid[rows][cols] = 0;
                break;
            }
          }
          //dead cell rule 4 any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
          else if (gameGrid[rows][cols] === 0) {
            if (totalNeighbours == 3) {
              newGameGrid[rows][cols] = 1;
              }
            }
          }
        }
        //iterate through the rows and columns and gameGrid is set to the newGameGrid with the updated cells in the grid
        for (var rows = 0; rows < GRIDWIDTH; rows++) {
          for (var cols = 0; cols < GRIDHEIGHT; cols++) {
            gameGrid[rows][cols] = newGameGrid[rows][cols];
          }
        }
      }

      populateGrid();
      requestAnimationFrame(start);

      var startTime = null, stepInMs = 2000, drawCount = 0;
      function start(timestamp) {
          var progress;
          if (startTime === null){
              startTime = timestamp;
          }
          progress = timestamp - startTime;
          if (progress > stepInMs) {
              drawCount++;
              document.getElementById('drawCount').innerHTML = drawCount;
              startTime = timestamp;
              drawGrid();
              updateGrid();
          }
          requestAnimationFrame(start);
      }

    })
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Conway's Game Of Life</title>
    <script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
    <script type="text/javascript" src="../js/index.js"></script>
    <link rel="stylesheet" href="../css/index.css">
    <link href="https://fonts.googleapis.com/css?family=Anton" rel="stylesheet">
  </head>
  <body>
    <div class="gameScreen">
      <div class="title">John Conway's Game Of Life - count: <span id="drawCount">0</span></div>
      <canvas id="gameCanvas" width="400" height="400" style="border:1px solid #000000;"></canvas>
    </div>
  </body>
</html>

编辑:添加了一个跨度来显示带有计数的重绘以证明,您的代码中可能存在错误,因为它只会在重新绘制时更改2次。

© www.soinside.com 2019 - 2024. All rights reserved.