JavaScript canvas 一段时间后游戏 FPS 下降
JavaScript canvas game is dropping FPS after some time
最近我一直在尝试制作 JS canvas 项目,几天前我开始编写代码。我创建了在 canvas 上生成随机点并移动到它的敌人。我通过 运行 createEnemy() 函数创建敌人。它用敌人的数据创建一个对象并将其存储在“敌人”数组中。一切正常,除了我的 FPS :( 一段时间后,它们下降得非常厉害。发生了什么,为什么?这是我的代码:
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
context.save();
context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
context.save();
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
context.save();
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++
}
else if (en.targetY < en.currentY) {
en.currentY--
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--
}
}
}
en.draw()
})
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame()
startLoop();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>
首先我要说你进展顺利。使用传统的 ecma 可以很好地填充
good/comform 在 canvas 面向脚本中。
您在 context.save() 调用时出错。
在不调用 restore() 的情况下不断调用 save() 会给程序带来很大的痛苦
并导致内存泄漏。
canvas 2d context 必须用smart way.
- 切勿无目的使用上下文。
- 有些设置更昂贵,例如 .font 或 shadows。
保存恢复的用法
// we have some complex setup initial already
// but we need to change something
ctx.save()
ctx.fillStyle = "red";
ctx.fillText ('use it' , 1, 1, 111, 111)
ctx.restore()
// Now back me to the old setup
差点忘记一个更大的错误:
我删除了 startLoop() 我把它放在 drawFrame 函数中的最后一次调用中。
这样我们的工作就流畅了。
说明:
您调用 drawFrame() 并同时调用 startLoop func 如何再次调用 drawFrame....
My english is bad but i am glad if i help...
drawFrame()
startLoop();
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
// context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++;
}
else if (en.targetY < en.currentY) {
en.currentY--;
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++;
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--;
}
}
}
en.draw();
})
startLoop();
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>
最近我一直在尝试制作 JS canvas 项目,几天前我开始编写代码。我创建了在 canvas 上生成随机点并移动到它的敌人。我通过 运行 createEnemy() 函数创建敌人。它用敌人的数据创建一个对象并将其存储在“敌人”数组中。一切正常,除了我的 FPS :( 一段时间后,它们下降得非常厉害。发生了什么,为什么?这是我的代码:
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
context.save();
context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
context.save();
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
context.save();
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++
}
else if (en.targetY < en.currentY) {
en.currentY--
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--
}
}
}
en.draw()
})
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame()
startLoop();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>
首先我要说你进展顺利。使用传统的 ecma 可以很好地填充 good/comform 在 canvas 面向脚本中。
您在 context.save() 调用时出错。 在不调用 restore() 的情况下不断调用 save() 会给程序带来很大的痛苦 并导致内存泄漏。
canvas 2d context 必须用smart way.
- 切勿无目的使用上下文。
- 有些设置更昂贵,例如 .font 或 shadows。
保存恢复的用法
// we have some complex setup initial already
// but we need to change something
ctx.save()
ctx.fillStyle = "red";
ctx.fillText ('use it' , 1, 1, 111, 111)
ctx.restore()
// Now back me to the old setup
差点忘记一个更大的错误: 我删除了 startLoop() 我把它放在 drawFrame 函数中的最后一次调用中。 这样我们的工作就流畅了。
说明: 您调用 drawFrame() 并同时调用 startLoop func 如何再次调用 drawFrame....
My english is bad but i am glad if i help...
drawFrame()
startLoop();
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
// context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++;
}
else if (en.targetY < en.currentY) {
en.currentY--;
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++;
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--;
}
}
}
en.draw();
})
startLoop();
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>