R
R
Riodevista2013-08-19 20:10:59
JavaScript
Riodevista, 2013-08-19 20:10:59

Application performance drops?

Good evening, dear habravchane!
I took up the study of js: I decided to implement the game "Life" using canvas. The game is based on the simplest algorithm with cycles and two two-dimensional arrays.
Faced such a problem that after a certain time of the application (after about 250 steps of the game), it starts to slow down. This does not depend on the workload of the field: at the beginning of the game, 100+ objects can be drawn stably without delays, and after a certain point, even with 3 live cells, there will be delays.
Prompt, please: in what there can be a business?
Thank you in advance.
Game
source code

var gridColor = "#c9c9c9";
var pieceColor = "green";
var backgroundColor = "#ffffff"; //c0cd02

var gDrawingContext, gCanvasElement, gStopwatchElement;
var gameSpeed = 100;
var dGameSpeed = 50;
var kBoardWidth = 80; 
var kBoardHeight= 40;
var kMinBoardSize=4;
var kPieceWidth = 10;
var kPieceHeight= 10;
var kPixelWidth = 1 + (kBoardWidth * kPieceWidth);
var kPixelHeight= 1 + (kBoardHeight * kPieceHeight);
var gridOn = true;
var gameInProgress = false;
var k = 0; // how many pieces exist now - population
var step = 0;
var piece = [];
var h = 0, s = 0, min = 0;
var gameTimer;
var timer; //stopwatch
var firstStart = 1;

function Cell(column, row){
  this.y = row;
  this.x = column;
}
function matrix(a,b) {
  var arr = [];
  for(var i=0;i<=a+1;i++) {arr[i] = [];}
  for(var i=0;i<=a+1;i++){
    for(var k=0;k<=b+1;k++) {arr[i][k] = 0;}
  }
  return arr;
}
function initGame(canvasElement, scoreCountElement, stopwatchElement) {
    if (!canvasElement) {
        canvasElement = document.createElement("canvas");
    canvasElement.id = "life_canvas";
    canvasElement.style.margin = "0 0 0 -"+kPixelWidth/2+"px";
    document.body.appendChild(canvasElement);
    }
    gCanvasElement = canvasElement;
  gCanvasElement.addEventListener("click", lifeOnClick, false);
    gCanvasElement.width = kPixelWidth;
    gCanvasElement.height = kPixelHeight;
    gScoreCountElem = scoreCountElement;
  gStopwatchElement = stopwatchElement;
    gDrawingContext = gCanvasElement.getContext("2d");
  newGame();
}

function newGame() {
  firstStart = 1;
  step = 1;
  arrayA = matrix(kBoardWidth,kBoardHeight);
  arrayB = matrix(kBoardWidth,kBoardHeight);
  arrayA[23][1] = 1;
  arrayA[24][14] = 1;
  arrayA[25][14] = 1;
  arrayB[23][14] = 1;
  arrayB[24][14] = 1;
  arrayB[25][14] = 1;
  k = 3;
  document.getElementById('step').innerHTML = step;
  document.getElementById('population').innerHTML = k;
  gameInProgress = true;
    drawBoard();
  gStopwatchElement.innerHTML = "00:00:00";
  clearInterval(timer);
  clearInterval(gameTimer);
  stopwatch();
  message(false,"");
  gameClock();
  if (firstStart == 1) {pauseGame(); message(true,'.</br> Backspace to pause or resume game.</br>');firstStart = 2;}
  }

function gameOver(way){
  clearInterval(gameTimer);
  clearInterval(timer);
  gameInProgress = false;
}
function gameClock(){
  gameTimer = setInterval(
    function(){
      if (!gameInProgress) {return;}
      evolution();
      drawBoard();
      step++;
      document.getElementById('step').innerHTML = step;
      document.getElementById('population').innerHTML = k;
    },gameSpeed);
}
function makePiece(cell){
  k++;
  arrayA[cell.x][cell.y] = 1;
  arrayB[cell.x][cell.y] = 1;
  gDrawingContext.fillRect((cell.x-1)*kPieceWidth+1, (cell.y-1)*kPieceHeight+1, kPieceWidth-1, kPieceHeight-1);
  document.getElementById('population').innerHTML = k;
}

function evolution(){
  var nearPieces = 0;
  for (var i=1;i<=kBoardWidth;i++){
    for (var j=1;j<=kBoardHeight;j++){
      nearPieces = arrayA[i+1][j] + arrayA[i-1][j] + arrayA[i+1][j+1] + arrayA[i-1][j-1] + arrayA[i+1][j-1] + arrayA[i-1][j+1] + arrayA[i][j+1] + arrayA[i][j-1];
      if (nearPieces == 3 && arrayA[i][j] == 0) {arrayB[i][j] = 1; k++;}
      if (arrayA[i][j] == 1){	
        if (nearPieces == 2 || nearPieces == 3){arrayB[i][j] = 1;}
        else {arrayB[i][j] = 0; k--;}
      }
    }
  }	
}

function drawBoard() {	
    gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight);
  gDrawingContext.fillStyle = backgroundColor;
  gDrawingContext.fillRect(0, 0, kPixelWidth, kPixelHeight);
  if (gridOn) {
      for (var x = 0; x <= kPixelWidth; x += kPieceWidth) {
    gDrawingContext.moveTo(0.5 + x, 0);
    gDrawingContext.lineTo(0.5 + x, kPixelHeight);
    }
    for (var y = 0; y <= kPixelHeight; y += kPieceHeight) {
      gDrawingContext.moveTo(0, 0.5 + y);
      gDrawingContext.lineTo(kPixelWidth, 0.5 +  y);
    }
  }
  else {
      gDrawingContext.moveTo(0.5, 0);
      gDrawingContext.lineTo(0.5, kPixelHeight);
      gDrawingContext.moveTo(0, 0.5);
      gDrawingContext.lineTo(kPixelWidth, 0.5);
      gDrawingContext.moveTo(kPixelWidth - 0.5, 0);
      gDrawingContext.lineTo(kPixelWidth - 0.5, kPixelHeight);
      gDrawingContext.moveTo(0, kPixelHeight - 0.5);
      gDrawingContext.lineTo(kPixelWidth, kPixelHeight - 0.5);
  }
    gDrawingContext.strokeStyle = gridColor;
    gDrawingContext.stroke();
  drawPieces();
}
function drawPieces() {
  gDrawingContext.fillStyle = pieceColor;
  for (var i=1;i<=kBoardWidth;i++){
    for (var j=1;j<=kBoardHeight;j++){
      if (arrayB[i][j] == 1){
        gDrawingContext.fillRect((i-1)*kPieceWidth+1, (j-1)*kPieceHeight+1, kPieceWidth-1, kPieceHeight-1);
        arrayA[i][j] = 1;
      } else {arrayA[i][j] = 0;}
    }
  }

}

function getCursorPosition(e) {
    var x;
    var y;
    if (e.pageX != undefined && e.pageY != undefined) {
    x = e.pageX;
    y = e.pageY;
    }
    else {
    x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
    y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    x -= gCanvasElement.offsetLeft;
    y -= gCanvasElement.offsetTop;
    x = Math.min(x, kBoardWidth * kPieceWidth);
    y = Math.min(y, kBoardHeight * kPieceHeight);
    var cell = new Cell(Math.floor(x/kPieceWidth)+1, Math.floor(y/kPieceHeight)+1);
    return cell;
}

function lifeOnClick(e) {
    var cell = getCursorPosition(e);
  makePiece(cell);
}
/****Main stopwatch****/
function stopwatch(){
  var sh="00", ss="00", smin="00";
  h = 0, s = 0, min = 0;
    timer = setInterval(
      function () {
        if (!gameInProgress) {return;}
        s++;
        if (s==60) {min++; s = 0; if (min<10) {smin="0"+min} else {smin = min}}
        if (min==60) {h++; min = 0; if (h<10) {sh="0"+h} else {sh = h}}
        if (s>=10) {ss = s} else {ss="0"+s};
        gStopwatchElement.innerHTML = sh+":"+smin+":"+ss;},
      1000);
}

P.S. I would be immensely happy for comments on the code about how not to write in js.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
sheknitrtch, 2013-08-19
@Riodevista

I seem to have found the reason.
First, by typing, it was determined that if you comment out line 97:

drawBoard();

Then there are no brakes in Opera.
Secondly, if we gridOnwrite to the global variable false, then the brakes also disappear.
And thirdly, it turned out that it was enough to add after the 127th line
gDrawingContext.beginPath();

And the brakes disappear in Opera forever.
It seems to me that if you do not call beginPath, then Opera remembers all created using lineTothe line every time you call drawBoard. And when it is called, stroke()a grid is drawn from all previous frames combined. This hypothesis still needs to be tested. But judging by the fact that the call beginPathfixes the performance problem, I think that's the point.

S
sdevalex, 2013-08-19
@sdevalex

Didn't see any delays. Have you tried running the profiler?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question