5 javascript optimization game-physics p5.js
我已经开始了一个像素模拟项目,但它运行得并不好。我可以做什么来优化它?我相当有信心问题出在涉及粒子阵列的所有检查中。我正在寻找任何解决方案,做任何不同的事情,或者一般的任何优化,不仅仅是关于粒子数组,而是整个代码。我这个项目的目标是创建一个像素模拟 Web 应用程序,如果它在生成沙子几秒钟后无法正常运行,那么它就违背了 Web 应用程序的目的。任何帮助表示赞赏。
主要文件:
let alter = true;
let particles = []
function setup() {
let canvas = createCanvas(windowWidth, windowHeight);
frameRate(120);
}
var a = ['rgb(244,220,148)', 'rgb(236,211,140)', 'rgb(252,228,156)', 'rgb(252,220,149)', 'rgb(244,212,148)', 'rgb(228,204,132)', 'rgb(240,220,156)']
function sandColor() {
return color(a[Math.floor(Math.random() * a.length)]);
}
function drect(c, x, y, l, w) {
noStroke();
fill(c);
rect(x, y, l, w);
}
class Particle {
constructor(p, c, x, y, s) {
this.p = p;
this.c = c;
this.x = x;
this.y = y;
this.s = s;
}
draw() {
drect(this.c, this.x, this.y, this.s, this.s);
}
}
function check(x, y) {
return color(get(x, y));
}
function draw() {
drect(color(37, 150, 190), 0, 0, windowWidth, windowHeight)
tw = 4;
th = 4;
for (let i = 0; i < particles.length; i++) {
particles[i].draw()
}
alter = !(alter)
if (!alter) {
for (let i = 0; i < particles.length; i++) {
if (particles[i].p == 's') {
let down = false
if (JSON.stringify(check(particles[i].x, particles[i].y + 4).levels) == '[37,150,190,255]') {
particles[i].y += 4;
down = true;
}
if (!down) {
let r = Math.floor(Math.random() * 2);
if (r == 0) {
if (JSON.stringify(check(particles[i].x - 4, particles[i].y + 4).levels) == '[37,150,190,255]') {
particles[i].y += 4;
particles[i].x -= 4;
} else {
if (JSON.stringify(check(particles[i].x + 4, particles[i].y + 4).levels) == '[37,150,190,255]') {
particles[i].y += 4;
particles[i].x += 4;
}
}
}
}
}
}
if (mouseIsPressed) {
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
let p = 's'
let c = sandColor()
let x = (Math.floor(mouseX / tw)) * tw + (i * 4) - 9;
let y = (Math.floor(mouseY / th)) * th + (j * 4) - 9;
let s = 4;
let sand = new Particle(p, c, x, y, s)
let d = true;
for (let m = 0; m < particles.length; m++) {
if (particles[m].x == x && particles[m].y == y && particles[m].p == "s") {
d = false;
}
}
if (d) {
drect(c, x, y, s, s)
particles.push(sand)
}
}
}
}
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
document.addEventListener('contextmenu', event => event.preventDefault());Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>Run Code Online (Sandbox Code Playgroud)
托管示例: https: //pixsim.loganstottle202.repl.co/如果这不起作用,代码位于: https: //replit.com/@LoganStottle202/pixsim ?v=1
不幸的是,我没有时间提供一个详细的可运行示例,例如您有趣的草图。
希望我能给你一些指导:
get()参考文献中提到的:“使用 get(x, y) 获取单个像素的颜色很容易,但不如直接从 获取数据那么快pixels[]。”。loadPixels()您可以在帧开始时调用一次,然后使用pixels[4 * (x * d + i) + ((y * d + j) * width * d + )]where d = pixelDensity()。JSON.stringify()对于许多粒子来说,比较字符串可能会导致计算量很大。考虑将粒子的状态(碰撞、移动、静止/不活动等)标记为可以直接比较的整数值(例如,再次const使用描述性名称的整数状态)。(如果您愿意,您可以重复使用此状态以不同的颜色渲染粒子)。如果你真的想使用颜色,你可以通过使用不同状态的 alpha 值(例如 255、254、253 等)来简化,在感知上很难注意到,你可以只与避免.levels[3]和JSON.stringify()字符串比较进行比较。我确实建议使用具有描述性名称的全局或静态粒子状态变量和粒子实例的const基本属性。statecreateGraphics():一层用于渲染“活动/活动”活动粒子(它甚至可以是全局 p5 图形缓冲区)。另一层可用于渲染已沉降的静态粒子。然后,您可以使用 重新使用/重新绘制该图层image(yourStaticSandLayer, 0, 0);,从而消除rect()对静态粒子的调用(因为它们已经被绘制/缓存到图层中)。(此外,您可以简化sandColor()为简单return random(a);,因为 p5random()还可以为您选择数组中的随机项。这不会加快任何速度,只是简化代码:使其更易于阅读/维护)
更新这里是基本演示,大致基于您的Particle课程并使用p5.Graphics:
let particles = [];
let activeParticlesLayer;
let inactiveParticlesLayer;
function setup() {
createCanvas(300, 150);
activeParticlesLayer = createGraphics(width, height);
inactiveParticlesLayer = createGraphics(width, height);
for(let i = 0; i < 10; i++){
particles.push(new Particle(color(0, 192, 0), random(width), random(90), 10, 10));
}
}
function draw() {
// clear only active layer: don't clear inactive layer
activeParticlesLayer.background(255);
// for debugging only: count active particles
let numActiveParticles = 0;
for(let i = 0; i < 10; i++){
let p = particles[i];
// only update particles if they're active
if(p.isActive){
// if the current particle collided (with stage bottom for now)
// then make it inactive (change colour as a visual cue) and cache to inactive layer
// replace this with pixels[] collision logic
if(p.y > height - p.s){
p.isActive = false;
p.c = color(0, 128, 0);
// particle is inactive: cache into inactive layer (which isn't cleared)
p.draw(inactiveParticlesLayer);
}
// otherwise our particle is active: update position and render to active layer
else{
p.y += 1;
p.draw(activeParticlesLayer);
numActiveParticles++;
}
}
}
// display layers
image(activeParticlesLayer, 0, 0);
image(inactiveParticlesLayer, 0, 0);
text("active particles: " + numActiveParticles, 10, 15);
}
class Particle {
constructor(c, x, y, s) {
this.isActive = true;
this.c = c;
this.x = x;
this.y = y;
this.s = s;
}
update(){
if(this.y > height - this.s){
this.isActive = false;
this.c = color(0, 128, 0);
}else{
this.y += 1;
}
}
draw(buffer) {
buffer.fill(this.c);
buffer.rect(this.x, this.y, this.s, this.s);
}
}Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>Run Code Online (Sandbox Code Playgroud)
注意:上面删除了原始演示中的一些功能,例如使用颜色来检查碰撞。为了简单起见,只有极少量的粒子仅与画布底部碰撞(并且不堆叠)。希望这足以说明isActive状态更改并rect()仅在状态从活动更改为非活动时缓存调用一次。
此外,我建议查看开发人员工具并研究对代码进行分析,以准确找出较慢的代码段,并重点关注这些代码段(而不是优化几乎没有影响但有可能使代码更慢的代码段)可读/将来更难维护)