我就此问题发表了一篇文章,但意识到它说得不太好,所以我删除了它,并为这篇文章提供了更多信息。因此,我将这款游戏进行了一段时间,它是一种游戏,其中一种游戏作为一种颜色,并收集其他颜色的球并获得积分。您可以在下面使用我的工作代码片段进行播放。一段时间后(例如30或45秒),游戏落后很多,并且无法很好地进行游戏。我检查了所有地方,但似乎找不到任何地方重复每一帧,这会减慢速度。有什么办法可以找到性能问题所在的地方?
以下是代码段:
let ctx = document.getElementById("can").getContext("2d");
let can = document.getElementById("can");
let width = can.width;
let height = can.height;
let disp = document.getElementById("dis");
ctx.fillStyle = "black";
ctx.rect(0, 0, can.width, can.height);
ctx.fill();
ctx.font = "30px ComicSans";
let colors = ["red", "green", "blue"];
let Player = function(){
this.x = 250;
this.y = 400;
this.colornum = 0;
this.xspeed = 10;
this.yspeed = 10;
this.pressRight = false;
this.pressLeft = false;
this.pressUp = false;
this.pressDown = false;
this.radius = 30;
this.num = 0;
this.draw = function(){
ctx.save();
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2*Math.PI, false);
ctx.fillStyle = colors[this.colornum];
ctx.fill();
ctx.closePath();
//Number Style
ctx.beginPath();
ctx.fillStyle = "Black";
ctx.fillText(this.num, this.x - 15, this.y + 10);
ctx.fill();
ctx.restore();
}
this.updatePosition = function(){
if(this.pressRight){
if(this.x + this.radius < can.width){
this.x += this.xspeed;
}
}else if(this.pressLeft){
if(this.x - this.radius > 0){
this.x -= this.xspeed;
}
}else if(this.pressUp){
if(this.y - this.radius > 0){
this.y -= this.yspeed;
}
}else if(this.pressDown){
if(this.y + this.radius < can.height){
this.y += this.yspeed;
}
}
}
this.update = function(){
this.updatePosition();
this.draw();
}
}
let Entity = function(){
this.x = Math.floor(Math.random() * 500);
this.y = Math.floor(Math.random() * 500);
this.colornum = Math.floor(Math.random() * 3);
this.xspeed = Math.floor(Math.random() * 7);
this.yspeed = Math.floor(Math.random() * 7);
this.collide = function(){
if(this.x > can.width || this.x < 0){
this.xspeed = -this.xspeed;
}
if(this.y > can.height || this.y < 0){
this.yspeed = -this.yspeed;
}
}
this.updatePosition = function(){
this.collide();
this.x += this.xspeed;
this.y += this.yspeed;
}
this.draw = function(){
ctx.save();
ctx.beginPath();
ctx.arc(this.x, this.y, 20, 0, 2*Math.PI, false);
ctx.fillStyle = colors[this.colornum];
ctx.fill();
ctx.closePath();
}
this.update = function(){
this.updatePosition();
this.draw();
}
}
let player1 = new Player();
let enemylist = {};
for(let i = 0; i < 20; i++){
let id = Math.floor(Math.random() * 100);
enemylist[id] = new Entity();
}
function CollideDetect(x1, y1, x2, y2){
if(Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) < (player1.radius + 20)){
return true;
}else
return false;
}
function update(){
ctx.clearRect(0,0,width,height);
ctx.fillStyle = "White";
ctx.rect(0,0,800,600);
ctx.fill();
for(let key in enemylist){
let collided = CollideDetect(enemylist[key].x, enemylist[key].y, player1.x, player1.y);
if(collided && player1.colornum == enemylist[key].colornum){
player1.radius += 5;
player1.num += 1;
delete enemylist[key];
}else if(collided && player1.colornum != enemylist[key].colornum){
if(player1.num <= 0 || player1.radius <5){
delete enemylist[key];
}else{
player1.radius -= 5;
player1.num -= 1;
delete enemylist[key];
}
}
}
for(let key in enemylist){
enemylist[key].update();
}
player1.update();
if(Object.keys(enemylist).length == 0){
disp.innerHTML = "Game Over";
}else if(Object.keys(enemylist).length != 0){
disp.innerHTML = "Start";
}
}
let Restart = function(){
if(Object.keys(enemylist).length == 0){
player1.num = 0;
player1.radius =30;
for(let i = 0; i < 20; i++){
let id = Math.floor(Math.random() * 10);
enemylist[id] = new Entity();
}
}
}
document.onkeydown = function(event){
if(event.keyCode == 68){
player1.pressRight = true;
}else if(event.keyCode == 65){
player1.pressLeft = true;
}else if(event.keyCode == 83){
player1.pressDown = true;
}else if(event.keyCode == 87){
player1.pressUp = true;
}else if(event.keyCode == 71){
player1.colornum = 0;
}else if(event.keyCode == 72){
player1.colornum = 1;
}else if(event.keyCode == 74){
player1.colornum = 2;
}
}
document.onkeyup = function(event){
if(event.keyCode == 68){
player1.pressRight = false;
}else if(event.keyCode == 65){
player1.pressLeft = false;
}else if(event.keyCode == 83){
player1.pressDown = false;
}else if(event.keyCode == 87){
player1.pressUp = false;
}else if(event.keyCode == 87){
}
}
let gameloop = function(){
window.requestAnimationFrame(gameloop);
update();
}
gameloop();
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Collision Game</title>
</head>
<body>
<h1>Collision Game</h1>
<button onclick="Restart()">Restart </button>
<canvas id="can" height="600" width="800" style="border:1px solid black"></canvas>
<p id="dis">Start</p>
<script src="game.js"></script>
</body>
</html>
答案 0 :(得分:1)
在处理了一些代码之后,我发现了问题。
您对disp.innerHTML
的呼叫方式过多。垃圾收集器无法跟上更新dom的次数。
因此,如果我们采用这段代码并将其移出更新循环并移至其自己的setInterval(..., 500)
中,则游戏将继续进行,并且dom可以跟上。
做到这一点:
if (Object.keys(enemylist).length == 0) {
disp.innerHTML = "Game Over";
} else if (Object.keys(enemylist).length != 0) {
disp.innerHTML = "Start";
}
成为这个:
setInterval(() = > {
if (Object.keys(enemylist).length == 0) {
disp.innerHTML = "Game Over";
} else if (Object.keys(enemylist).length != 0) {
disp.innerHTML = "Start";
}
}, 500)
在chrome开发工具中进行性能测试时,我看到有800多个节点,但是在查看元素时,页面中只有几个元素。但是,p
元素进行了很多更新。因此,我们只是放慢了它的更新速度,并解决了这个问题,现在我们将节点保持在100个以下!
答案 1 :(得分:1)
删除ctx.save()
和ctx.restore()
。
在游戏中,它们基本上没有用,因为您需要清除画布并在每次更新时从头开始重新绘制所有内容。无论如何,我们不需要在下一帧中保存的任何信息。
保存到堆栈中的drawing state包括:
在逐帧重画的游戏中,这些都不是有用的,这使得调用ctx.save()
和ctx.restore()
毫无意义。这并不意味着您不能使用strokeStyle
,fillStyle
等。保存这些数据毫无意义。