Как я могу замедлить мою анимацию, используя requestAnimationFrame () в JavaScript - PullRequest
0 голосов
/ 21 февраля 2019

Сейчас я пишу код жизни Конвея на JavaScript, проблема, с которой я столкнулся, связана с моей анимацией, использующей 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>

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Вот как вы можете использовать requestAnimationFrame: функция, которую вы передаете ей, принимает один аргумент, который является отметкой времени.Вы можете использовать его для расчета пройденного времени.В этом примере шаг установлен в 2 с (2000 мс).Обратите внимание, что вам нужно начать с 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 раза, пока он перерисовывается..

0 голосов
/ 21 февраля 2019

также см.

этот ответ

Я думаю, вы должны использовать время, прошедшее между рендерами, в сочетании с коэффициентом скорости.

Например, выможно определить, что вы хотите, чтобы ваш главный персонаж двигался на 200 пикселей в секунду.Затем - используя истекшее время между рендерами, вы можете рассчитать, как далеко вы хотите переместить его (код макета):

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

Так что если ваше время, прошедшее с последнего рендера, составляет 500 мс, то в этом рендере вы будете двигатьсяего 100px.

...