Добрый вечер, уважаемые хабравчане!
Взялся за изучение js: решил реализовать игру «Жизнь» с использованием canvas. За основу игры взят самый простой алгоритм с циклами и двумя двумерными массивами.
Столкнулся с такой проблемой, что после определенного времени работы приложения (примерно после 250 шага игры) оно начинает тормозить. От загруженности поля это не зависит: в начале игры могут стабильно без задержек отрисовываться 100+ объектов, а после определенного момента даже при 3 живых клетках будут задержки.
Подскажите, пожалуйста: в чем может быть дело?
Заранее благодарю.
ИграИсходный код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);
}
П.С. Буду безмерно рад комментариям по коду о том, как не надо писать на js.