Тормозит requestAnimationFrame
Пишу что-то вроде движка для игры.
При использовании (30 и более секунд), анимация начинает тормозить. Это можно увидеть если перемещать стрелками один из объектов. Сам код: --------Движок----------- var D = document; var full; var cnv = D.createElement('canvas'); var ctx = cnv.getContext("2d"); cnv.style.padding = 0; cnv.style.margin = 0; cnv.style.position = "fixed"; D.getElementsByTagName('html')[0].style.width = '100%'; D.getElementsByTagName('html')[0].style.height = '100%'; D.getElementsByTagName('html')[0].style.overflow = 'hidden'; D.body.style.width = "100%"; D.body.style.height = "100%"; function Game (){ 'use strict' this.setMap = function(posx,posy,width,height,color,texture){ this.HEIGHT = height; this.WIDTH = width; cnv.style.top = posy+"px"; cnv.style.left = posx+"px"; this.keys = {}; if(width == full){cnv.setAttribute('width',innerWidth)}else{cnv.setAttribute('width',this.WIDTH)}; if(height == full){cnv.setAttribute('height',innerHeight)}else{cnv.setAttribute('height',this.HEIGHT)} if(texture && !color){cnv.style.backgroundImage = "url('"+texture+"')"} else if(!texture && color){cnv.style.backgroundColor = color}; cnv.style.background = color; D.body.appendChild(cnv); }; var _Game = this; this.clear = true; var engine = function(){ if(_Game.clear == true){if(_Game.WIDTH == full && _Game.HEIGHT != full){ctx.clearRect(0,0,innerWidth,_Game.HEIGHT)} else if(_Game.WIDTH != full && _Game.HEIGHT == full){ctx.clearRect(0,0,_Game.WIDTH,innerHeight)} else{ctx.clearRect(0,0,innerWidth,innerHeight)}}; _Game.update(); requestAnimationFrame(engine); }; this.start = function(){ engine(); }; this.Rect = function(param){ this.width = param.width; this.height = param.height; this.x = param.x; this.y = param.y; this.color = param.color; }; this.Rect.prototype = { draw:function(){ ctx.beginPath(); ctx.fillStyle = this.color; ctx.fillRect(this.x,this.y,this.width,this.height); } }; this.delKey = function(name){ delete _Game.keys[name]; }; this.newKey = function(param,param2){ this.code = param; this.name = param2; _Game.keys[this.name] = this.code; _Game.keys[this.name + "_isPressed"] = false; }; this.isDown = function(name){ addEventListener('keydown',function(e){if(_Game.keys[name] == e.keyCode){_Game.keys[name+"_isPressed"] = true}},false); addEventListener('keyup',function(e){if(_Game.keys[name] == e.keyCode){_Game.keys[name+"_isPressed"] = false}},false); if(_Game.keys[name+"_isPressed"]==true){return true}; }; }; ---------тестовое поле------------ window.onload = function(){ var game = new Game(); game.setMap(0,0,full,full,"#2F2B2B"); var cube = new game.Rect({ x:20,y:20, width:100, height:100, color:"black", }); var cube2 = new game.Rect({ x:100,y:200, width:40, height:40, color:"lightblue", }); var player = new game.Rect({ x:500,y:500, width:30, height:30, color:"red", }); var player2= new game.Rect({ x:500,y:500, width:30, height:30, color:"green", }); game.newKey(87,"W"); game.newKey(65,"A"); game.newKey(83,"S"); game.newKey(68,"D"); game.newKey(37,"left"); game.newKey(39,"right"); game.newKey(40,"down"); game.newKey(38,"up"); game.update = function(){ if(game.isDown("up")){player2.y -=2}; if(game.isDown("down")){player2.y +=2}; if(game.isDown("right")){player2.x +=2}; if(game.isDown("left")){player2.x -=2}; if(game.isDown("W")){player.y -=2}; if(game.isDown("A")){player.x -=2}; if(game.isDown("S")){player.y +=2}; if(game.isDown("D")){player.x +=2}; cube.draw(); cube2.draw(); player.draw(); player2.draw(); }; game.start(); console.log(game.keys["W_isPressed"]); console.log(game.keys["A_isPressed"]) } index.html - минимальный, вот: <!DOCTYPE html> <html> <head> <title>Test</title> </head> <body> <script type="text/javascript"src = "core.js"></script> <script type="text/javascript"src = "test.js"></script> </body> </html> управление: объект1 - W,S,A,D; объект2 - стрелки; подскажите пожалуйста, в чем может быть проблема. |
Утечка памяти. У тебя addEventListener() в бесконечном цикле находится. При том, что addEventListener() не заменяет предыдущий обработчик, а прибавляет следующий:
for (var i = 0; i < 3; i++) addEventListener('click', function(e) { alert(e.type) }); document.body.click(); requestAnimationFrame() вызывается около 60 раз в секунду, вот и считай, 60 раз вызывается game.update(), 8 раз вызывается game.isDown(), 2 раза вызывается addEventListener(), за 30 секунд это 30 * 60 * 8 * 2 = 28800 обработчиков событий добавлено. |
Спасибо, очень помогли!
|
AndrewMaximum,
Есть еще косяки. 1. строки 6-14 бессмысленны, достаточно только body margin 0. 2. full это строка наверное, значит так 'full'. 3. строки 34-35 cnv.setAttribute('width',...) можно просто так cnv.width = .... 4. строки 37-39 color и texture можно объединить в слово background и назначить его в cnv.style.background. 5. строки 50-52 надо всего лишь написать if (_Game.clear) ctx.clearRect(0,0,cnv.width,cnv.height). 6. строки 90-106 наверно не нужны кроме 104-105 которые перенести куда-нибудь, попутно можно сократить: - addEventListener('keydown',function(e){_Game.keys[e.code] = true}); - addEventListener('keyup',function(e){_Game.keys[e.code] = false}); потом проверяется так if(game.keys.KeyW){...}, if(game.keys.ArrowLeft){...}. |
Rise,
Здаров, а что делать если допустим есть одна анимация на requestAnimationFrame, но при клике на кнопку я её пытаюсь вырубить с помощью cancel Animationframe и ниже вызываю функцию с новым requestAnimationFrame и эта функция начинает тормозить и страница зависает. Что делать? |
Andrea24000,
где код? |
рони,
let canv = document.getElementById("canv") ctx = canv.getContext("2d") doc = document.documentElement // ширина и высота canvas wth = canv.width = 500 height = canv.height = 500 // ширина прямоугольника x = 250 y = 440 dx = 5 dy = 5 score = 0 timeOneFps = 1/60 fpsSec = 0 xPlayer = 250 clientX = 0 colorRed = 195 colorGreen = 195 colorBlue = 189 const songPlayerRect = new Audio("song/songPlayerRect.mp3") const songBlockCrash = new Audio("song/songBlockCrash.mp3") let coordinateArrX = [] coordinateArrY = [] arrWth = 50 arrHeight = 15 arrClearRect = [] timeArr = [] clicker = false btnObj = { btn1: { x: 190, y: 280, w: 160, h: 50 }, btn2: { x: 170, y: 220, w: 200, h: 75 } } const arrColor = ['red', 'green', 'blue', 'yellow', 'pink', 'mangeta', 'brown', 'cian', 'orange', 'white'] function random() { const random = Math.round((Math.random() * 10)) return random } let x1 = 100 y1 = 200 dx1 = 2 dy1 = 2 requestId = null checkRequest = 0 window.addEventListener('load', () => animationStart()) function animationStart(params) { requestAnimationFrame(start) function start() { console.log(111); ctx.clearRect(0, 0, wth, height) ctx.beginPath() ctx.fillStyle = "black" ctx.fillRect(0, 0, 500, 500) ctx.fillStyle = arrColor[random()] ctx.font = "bold 50px sans-serif" ctx.fillText("АРКАНОИД", x1, y1) ctx.fillStyle = "yellow" ctx.font = "bold 40px sans-serif" createButtonReset(btnObj.btn2.x, btnObj.btn2.y, btnObj.btn2.w, btnObj.btn2.h) ctx.fillStyle = "yellow" ctx.fillText(`Играть`, 205, 270) checkBtnColl(btnObj.btn2.x, btnObj.btn2.y, btnObj.btn2.w, btnObj.btn2.h, requestId) x1 += dx1 y1 += dy1 if (x1 > 225 || x1 < -5) { dx1 = -dx1 } if (y1 > 500 || y1 < 40) { dy1 = -dy1 } if (!checkRequest) { requestId = requestAnimationFrame(start) } } start() } function animationPlay() { requestAnimationFrame(play) let requestId1 = null function play() { console.log(2); createCoordinate() init() ctx.clearRect(0, 0, wth, height) playingField.color = "black" playingField.draw() checkCollisionBlocks() scoreSum() timeGame() playerRectangle.color = "rgb(139,69,19)" playerRectangle.draw() function Arc(x, y, radius, zeroDeg, endDeg, rew) { x, y, radius, zeroDeg, endDeg, rew ctx.beginPath() ctx.strokeStyle = "yellow" ctx.arc(x, y, radius, zeroDeg, endDeg, rew) ctx.fillStyle = "red" ctx.fill() ctx.lineWidth = 2 ctx.stroke() } createArc = new Arc(x, y, 5, 0, Math.PI * 2, false) if (y + dy < 7) { dy = -dy } if (x + dx > 497) { dx = -dx } if (x + dx > 500 || x + dx < 7) { dx = -dx } y += dy x += dx function checkCollisionPlayerBlock() { if(x + dx >= playerRectangle.x && x + dx <= playerRectangle.x + 60 && y + dy >= playerRectangle.y - 3 && y + dy <= playerRectangle.y + 15) { dy = -dy songPlayerRect.play() } if(x > playerRectangle.x - 0.2 && x < playerRectangle.x + playerRectangle.width + 0.2 && y > playerRectangle.y && y < playerRectangle.y + playerRectangle.height) { dx = -dx dy = +dy } if(x + dx == playerRectangle.x && x + dx == playerRectangle.x + 60 && y + dy == playerRectangle.y - 3 && y + dy == playerRectangle.y + 15) { dy = -dy dx = -dx songPlayerRect.play() } if(x < playerRectangle.x + 60 && y > playerRectangle.y && y < playerRectangle.y + 5) { dx = +dx dy = +dy } } checkCollisionPlayerBlock() canv.addEventListener("mousemove", function(event) { xPlayer = event.clientX - ((doc.clientWidth - 500) / 2) - 30 if (xPlayer < 0) { xPlayer = 0 } if (xPlayer >= 440) { xPlayer = 440 } }) if (y > 500) { gameOver() } if (score == 400) { gameOver() } /* document.addEventListener("click", () => { if(clicker == true) { clicker = false }else { clicker = false } console.log(clicker); }) if (clicker == true) { paused() cancelAnimationFrame(requestId) }else { requestAnimationFrame(draw) } */ requestId1 = requestAnimationFrame(play) } play() } function createCoordinate(x, y, wth, height) { for (let i = 0; i < 5; i += 1) { for (let b = 0; b < 8; b++) { coordinateArrX.push(10 + 60 * b) } } for (let i = 0; i < 5; i++) { for (let b = 0; b < 8; b++) { coordinateArrY.push(25 + 20 * i) } } } function init() { // фон игры playingField = new Rectangle(0, 0, wth, height) // первая строка блоков createRectangle1 = new Rectangle(coordinateArrX[0], coordinateArrY[0], arrWth, arrHeight) createRectangle2 = new Rectangle(coordinateArrX[1], coordinateArrY[1], arrWth, arrHeight) createRectangle3 = new Rectangle(coordinateArrX[2], coordinateArrY[2], arrWth, arrHeight) createRectangle4 = new Rectangle(coordinateArrX[3], coordinateArrY[3], arrWth, arrHeight) createRectangle5 = new Rectangle(coordinateArrX[4], coordinateArrY[4], arrWth, arrHeight) createRectangle6 = new Rectangle(coordinateArrX[5], coordinateArrY[5], arrWth, arrHeight) createRectangle7 = new Rectangle(coordinateArrX[6], coordinateArrY[6], arrWth, arrHeight) createRectangle8 = new Rectangle(coordinateArrX[7], coordinateArrY[7], arrWth, arrHeight) playerRectangle = new Rectangle(xPlayer, 450, 60, 15) } function Rectangle(x, y, width, height) { this.color = `rgb(${colorRed}, ${colorGreen}, ${colorBlue})` this.x = x this.y = y this.width = width this.height = height this.draw = function() { ctx.beginPath() ctx.fillStyle = this.color ctx.fillRect(this.x, this.y, this.width, this.height) ctx.stroke() } } function scoreSum() { ctx.beginPath() ctx.fillStyle = "yellow" ctx.textBaseline = "middle" ctx.font = "bold 25px sans-serif" ctx.fillText(`Счёт: ${score}`, 10, 15) } function timeGame() { ctx.beginPath() ctx.fillStyle = "yellow" ctx.textBaseline = "middle" ctx.font = "bold 25px sans-serif" ctx.fillText(`Время: ${Math.round(fpsSec += timeOneFps)}`, 150, 15) } function gameOver() { timeArr.push(fpsSec) ctx.beginPath() ctx.fillStyle = "black" ctx.fillRect(0, 0, 500, 500) ctx.fillStyle = "yellow" ctx.font = "bold 25px sans-serif" ctx.fillText("Game Over!!!", 190, 200) ctx.fillText(`Счёт: ${score}`, 215, 230) ctx.fillText(`Время: ${Math.round(timeArr[0])}`, 215, 260) createButtonReset(btnObj.btn1.x, btnObj.btn1.y, btnObj.btn1.w, btnObj.btn1.h) ctx.fillStyle = "yellow" ctx.fillText(`Обновить`, 209, 305) checkBtnColl(btnObj.btn1.x, btnObj.btn1.y, btnObj.btn1.w, btnObj.btn1.h) } function createButtonReset(x, y, w, h) { x y w h let btn = new Rectangle(x, y, w, h) btn.color = "red" btn.draw() } function checkBtnColl(x, y, w, h, requestId) { x y w h requestId canv.addEventListener("click", (event) => { if (event.clientX >= x && x + w <= event.clientX && event.clientY >= y && y + h <= event.clientY) { delete x animationPlay() ctx.clearRect(0, 0, 500, 500) checkRequest = 1 } }) } function checkCollisionBlocks() { for (let i = 0; i < coordinateArrX.length; i++) { for (let b = 0; b < coordinateArrY.length; b++) { if (x + dx >= coordinateArrX[i] && x + dx <= coordinateArrX[i] + arrWth && y + dy >= coordinateArrY[i] - 3 && y + dy <= coordinateArrY[i] + arrHeight) { dy = -dy delete coordinateArrX[i] delete coordinateArrX[i] score += 10 songBlockCrash.play() colorRed = Math.round((Math.floor(Math.random() * 100) * 2.5)) colorGreen = Math.round((Math.floor(Math.random() * 100) * 2.5)) colorBlue = Math.round((Math.floor(Math.random() * 100) * 2.5)) } } } } |
Andrea24000,
функция play 119 бесконечно ставит обработчики 202, что-то не так у вас с логикой. плюс двойной запуск одного и того же, 117 и 238 , ещё 73 и 109. |
рони,
202 строка, там обработчик события мыши, получает координаты мыши и заставляет платформу в арканойде двигаться за этими координатами. Не знаете что можно сделать вместо этого? |
Andrea24000,
искать canvas mousemove animation tutorial |
Часовой пояс GMT +3, время: 17:55. |