Javascript Starfield canvas程序占用太多CPU

Javascript Starfield canvas程序占用太多CPU,javascript,html,canvas,cpu-usage,Javascript,Html,Canvas,Cpu Usage,我使用canvas创建了一个starfield,它可以正常工作: <!DOCTYPE HTML5> <html> <head> <title>StarField</title> <style> * { margin: 0; padding: 0; }

我使用
canvas
创建了一个starfield,它可以正常工作:

<!DOCTYPE HTML5>

<html>
    <head>
        <title>StarField</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            body {
                width: 100%;
                height: 100%;
            }
        </style>
    </head>

    <body onLoad="startGame()"></body>

    <script type="text/javascript">
        var NO_OF_STARS = 512;
        var stars = [];

        function startGame() {          
            gameArea.start(); /* Makes the canvas */

            gameRun = requestAnimationFrame(gameArea.update); /* Starts the game and coordinates all the animations */

            window.addEventListener("keydown", function(e) {
                if(e.keyCode == 27) { /* ESC stops everything */
                    stopEverything();
                }
            });
        }

        var gameArea = {
            canvas : document.createElement("canvas"),
            start : function() {
                document.body.appendChild(this.canvas);

                this.canvas.width = document.body.clientWidth;
                this.canvas.height = document.body.clientHeight;
            },
            update : function() {               
                gameArea.clear(); /* Fills the canvas with #000000 */
                gameArea.drawStars(); /* Draws the stars */

                gameRun = requestAnimationFrame(gameArea.update); /* Repeat the whole thing */
            },
            drawStars : function() {
                var ctx = gameArea.canvas.getContext("2d");

                if(stars.length == 0) {
                    for(var i = 0; i < NO_OF_STARS; i++) {
                        var opacity = ((Math.floor(Math.random() * 10) / 10) + .1);

                        stars.push([getRandomInt(0, gameArea.canvas.width - 1), getRandomInt(0, gameArea.canvas.height - 1),opacity]);

                        ctx.beginPath();
                        ctx.strokeStyle = "rgba(255, 255, 255, " + opacity + ")";
                        ctx.moveTo(stars[i][0], stars[i][1]);
                        ctx.lineTo(stars[i][0] + 1, stars[i][1] + 1);
                        ctx.stroke();
                    }
                } else {
                    for(var i = 0; i < NO_OF_STARS; i++) {
                        ctx.strokeStyle = "rgba(255, 255, 255, " + stars[i][2] + ")";

                        stars[i][0] -= ((stars[i][2] == 1.0) ? 5 :
                                        (stars[i][2] >= 0.8) ? 4 :
                                        (stars[i][2] >= 0.5) ? 3 :
                                        (stars[i][2] >= 0.3) ? 2 :
                                                               1);

                        if(stars[i][0] < 0) {
                            var opacity = ((Math.floor(Math.random() * 10) / 10) + .1);
                            stars.splice(i, 1, [gameArea.canvas.width, getRandomInt(0, gameArea.canvas.height - 1), opacity]);
                        }

                        ctx.beginPath();
                        ctx.moveTo(stars[i][0], stars[i][1]);
                        ctx.lineTo(stars[i][0] + 1, stars[i][1] + 1);
                        ctx.stroke();
                    }
                }
            },
            clear : function() {
                var ctx = this.canvas.getContext("2d");
                ctx.fillStyle = "#000000";
                ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
            }
        };

        /**
         * Returns a random integer between min (inclusive) and max (inclusive)
         */
        function getRandomInt(min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }

        function stopEverything() {
            cancelAnimationFrame(gameRun);
        }

    </script>

</html>

斯塔菲尔德
* {
保证金:0;
填充:0;
}
身体{
宽度:100%;
身高:100%;
}
var NO_OF_星=512;
var星=[];
函数startName(){
gameArea.start();/*生成画布*/
gameRun=requestAnimationFrame(gameArea.update);/*启动游戏并协调所有动画*/
window.addEventListener(“向下键”,函数(e){
如果(e.keyCode==27){/*ESC停止所有操作*/
停止一切();
}
});
}
var游戏区={
画布:document.createElement(“画布”),
开始:函数(){
document.body.appendChild(this.canvas);
this.canvas.width=document.body.clientWidth;
this.canvas.height=document.body.clientHeight;
},
更新:函数(){
gameArea.clear();/*用#000000填充画布*/
gameArea.drawStars();/*绘制星星*/
gameRun=requestAnimationFrame(gameArea.update);/*重复整个过程*/
},
drawStars:function(){
var ctx=gameArea.canvas.getContext(“2d”);
如果(stars.length==0){
对于(VarI=0;i=0.8)?4:
(星[i][2]>=0.5)?3:
(星[i][2]>=0.3)?2:
1);
if(星[i][0]<0){
var不透明度=((数学地板(数学随机()*10)/10)+.1);
拼接(i,1,[gameArea.canvas.width,getRandomInt(0,gameArea.canvas.height-1),不透明度);
}
ctx.beginPath();
ctx.moveTo(stars[i][0],stars[i][1]);
ctx.lineTo(星[i][0]+1,星[i][1]+1);
ctx.stroke();
}
}
},
清除:函数(){
var ctx=this.canvas.getContext(“2d”);
ctx.fillStyle=“#000000”;
ctx.fillRect(0,0,this.canvas.width,this.canvas.height);
}
};
/**
*返回最小值(含)和最大值(含)之间的随机整数
*/
函数getRandomInt(最小值、最大值){
返回Math.floor(Math.random()*(max-min+1))+min;
}
函数stopEverything(){
取消动画帧(游戏运行);
}
这里的问题是,它占用大量CPU(在装有AMD A8四核处理器的笔记本电脑上占60%到65%)。我希望这个canvas程序也能在其他有低端处理器的计算机上运行

我已经尝试减少
无星星数
,但这并没有改变CPU使用率。然而,当增加它时,动画速度会大大减慢,CPU使用率也会降低(我不认为我会增加它,所以这并不重要)

我还注意到画布的大小在CPU使用率中起着重要作用。(我上面提到的笔记本电脑的分辨率为1366x768),但我希望画布能够显示整个视口


那么,如何降低CPU使用率呢?

为每个星形定义路径、笔划样式并将其光栅化是相当昂贵的。尝试收集一些操作以减少负载-这都是为了做出妥协:

  • 选择3-5个预定义的不透明度级别
  • 绘制按预定义不透明度级别数划分的星星数
  • 在循环之前使用单个beginPath()
  • 使用rect()而不是moveTo+LineTo
  • fill()循环完成后,继续执行下一个不透明度级别
  • 获取3D上下文一次,而不是每次调用
  • 对星形位置使用整数值(强制执行整数步长,在这种情况下可能不理想,但值得一试)
  • 回收/重用星形条目,而不是拼接和创建新条目
  • 尽可能减少计算和条件的数量
  • 将帧速率降低到30 FPS(每隔一次切换RAF以绘制)。60 FPS很好,但我们也可以像电影一样以30 FPS的速度拍摄(尽管它们从运动模糊中受益;我们可以通过使用嵌入“运动模糊”的精灵而不是绘制矩形来作弊)
  • 可选:将每个字段层存储为单独的画布,绘制为图像(速度更快,但需要更多内存)。可以通过旋转和/或翻转画布来进行变化
我个人会硬编码不透明度水平,但我留下了调整后的代码随机生成(点击运行按钮数次)

通常,CPU/GPU仍然会受到一些影响