javascript - 提高画布中粒子的性能
问题描述
我一直在尝试用画布和 Javascript 重新创建这个项目。我无法破译原始代码,所以我从头开始。不同之处在于我的项目开始滞后于大约 2500 个粒子,而上面的项目使用 30 000 个粒子。
我将在下面粘贴我的整个代码,但这些是相关部分:
var particleContainer = []
var distance = 10
for(let i = 0; i< square.height/distance; i++){
for(let j = 0; j< square.height/distance; j++){
particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}
}
if( c < 90 ){
i.xVelocity = a/c * -20
i.yVelocity = b/c * -20
}else if(90 < c && c < 95){
i.xVelocity = a/c * -1
i.yVelocity = b/c * -1
}else if(c2 !== 0){
i.xVelocity =( a2/c2 )
i.yVelocity = (b2/c2 )
}
- (c -> 鼠标和粒子之间的距离)
我正在为正方形的每个“距离”像素创建一个新粒子,并将它们全部推入一个数组中。当我的鼠标靠近其中一个时,粒子将开始远离鼠标移动,直到距离鼠标 90-95 像素。
从这条线来看,30 000 像素似乎以类似的方式工作
for ( i = 0; i < NUM_PARTICLES; i++ ) {
p = Object.create( particle );
p.x = p.ox = MARGIN + SPACING * ( i % COLS );
p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );
list[i] = p;
}
但该项目并没有遇到与我相同的性能问题。
我的完整代码供参考,(html只是一个画布):
var canvas = document.querySelector("canvas")
var c = canvas.getContext('2d')
function getMousePos(canvas, evt) {
// var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX,
y: evt.clientY
};
}
document.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
mouse.x= mousePos.x;
mouse.y= mousePos.y;
}, false);
var mouse = {
x:0,
y:0
}
function Particle(x,y){
this.x = x;
this.y = y;
this.xFixed = x;
this.yFixed = y;
this.radius = 1
this.xVelocity = 0
this.yVelocity = 0
this.color = 'white'
}
Particle.prototype.draw = function(){
c.save()
c.beginPath()
c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
c.fillStyle = this.color
c.fill()
}
Particle.prototype.update = function(){
this.draw()
this.x += this.xVelocity
this.y += this.yVelocity
}
var square = {
x: 500,
y: 150,
height: 500,
width: 500,
color: 'white'
}
var particleContainer = []
var distance = 10
for(let i = 0; i< square.height/distance; i++){
for(let j = 0; j< square.height/distance; j++){
particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}
}
function animate(){
requestAnimationFrame(animate);
c.clearRect(0,0,window.innerWidth,window.innerHeight)
canvas.width = window.innerWidth
canvas.height = window.innerHeight
for(i of particleContainer){
let a = mouse.x - i.x
let b = mouse.y - i.y
let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))
let a2 = i.xFixed - i.x
let b2 = i.yFixed - i.y
let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))
if( c < 90 ){
i.xVelocity = a/c * -20
i.yVelocity = b/c * -20
}else if(90 < c && c < 95){
i.xVelocity = a/c * -1
i.yVelocity = b/c * -1
}else if(c2 !== 0){
i.xVelocity =( a2/c2 )
i.yVelocity = (b2/c2 )
}
}
for(i of particleContainer){
i.update()
}
}
animate()
解决方案
学习使用开发工具中的性能选项卡,您可以查看哪些功能花费的时间最多。在这种情况下,我想你会看到它是ctx.fill
. 您发布的示例是将像素写入ImageData
缓冲区,这将比绘制和填充弧快得多。示例中还有许多其他小的优化,但这将是最重要的优化,绘图通常比更新慢得多。
推荐阅读
- angular - EsriLoader 和 Angular:没有边界和街道的底图
- python - 如何导入顶级文件夹中的文件?
- fingerprint - 如何让 fprint 为 su 工作,它为 sudo 工作
- php - 在 PDO 中动态 WHERE 子句查询后计算特定行数
- javascript - 在 ios14 中查看本地保存的 HTML5 和 javascript
- c# - 仅实现单个枚举的最佳方式 Moq IEnumerable
- sql - 用另一个字符串 SQL 替换其中带有单引号的字符串
- javascript - 使用 JavaScript 解密 RSA
- asp.net-core - MailKit.Security.SslHandshakeException:主机名与服务器 SSL 证书中给出的名称不匹配。asp.net 核心 5,nginx
- reactjs - 如何编写一个依赖于反应道具的计时器间隔?