像素/沙盒模拟器优化

4

我已经在这个项目上工作了几天了,它是一个像素模拟器,现在我只有沙子这一个元素。我正在调整沙子的物理特性,以便为其他元素做好基础。但我注意到,放置沙子一段时间后,程序开始明显变慢。我正在寻找任何可以改进或改变代码的事情,使其运行更加流畅。感谢您的帮助!

主文件的代码:

let alter = true;

particles = []

function setup() {
  let canvas = createCanvas(windowWidth, windowHeight);
  frameRate(120);
}

function sandColor() {
  r = Math.floor(Math.random() * (255 - 230 + 1) + 230)
  g = Math.floor(Math.random() * (230 - 200 + 1) + 230)
  b = Math.floor(Math.random() * (150 - 130 + 1) + 130)
  return color(r, g, b)
}

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) {
  found = false;
  let p;
  for (i in particles) {
    if (particles[i].x == x && particles[i].y == y) {
      found = true;
      p = particles[i].p;
    }
  }
  if (found) {
    return [found, p]
  } else {
    return [found];
  }
}

function draw() {

  drect(color(37, 150, 190), 0, 0, windowWidth, windowHeight)

  tw = 4;
  th = 4;

  for (var i in particles) {
    particles[i].draw()
  }

  alter = !(alter)
  if (!alter) {

    for (i in particles) {
      if (particles[i].p == 's') {
        let down = false
        if (!check(particles[i].x, particles[i].y + 4)[0]) {
          particles[i].y += 4;
          down = true;
        }
        if (!down) {
          let r = Math.floor(Math.random() * 2) + 1;
          if (r == 1) {
            if (!check(particles[i].x - 4, particles[i].y + 4)) {
              particles[i].y += 4;
              particles[i].x -= 4;
            } else {
              if (!check(particles[i].x + 4, particles[i].y + 4)) {
                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 (var m in particles) {
            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());
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>

此处提供托管示例和完整源代码:https://replit.com/@LoganStottle202/pixsim?v=1


“check”分配一个数组只是为了计算返回值-非常昂贵。我会首先将其重构为原始类型。你确定要让沙子无限地掉落吗?如果是这样,请销毁屏幕外的沙子。“for(i in particles){”创建全局变量,应该是“for..of”或传统循环。“check”不应该遍历所有粒子来查找“x”/“y”-使用键对象或2d数组来表示屏幕或粒子。 - ggorlen
@ggorlen,我已经改用for循环了,但我不完全理解你在第一句话中的意思。你能给一个代码示例吗?你可以把它放在一个新帖子里。感谢你的帮助。 - bread
[] 是一个昂贵的对象分配,会占用内存。但是它立即被丢弃了,并且在循环中有 O(n) 个这样的分配,随着粒子数量的增加而增加。这是个坏消息。调整逻辑,使您只需要从调用中返回一个原始值。check 函数内部的循环可能是最痛苦的部分,因此这里可能存在许多潜在问题。 - ggorlen
如果您编辑代码,请记住这可能会使现有答案无效,并请保留可运行的片段。能够在不必处理其他网站的情况下运行它会更容易。谢谢。 - ggorlen
1
似乎已经重新发布到优化p5.js项目/沙盒/像素模拟器 - ggorlen
我在发布另一个时还在学校。我没有访问这个电子邮件地址的权限。 - bread
1个回答

0
一个普通的for()循环比一个for(in)循环快6到11倍。
这是您当前的代码:
function check(x, y) {
  found = false;
  let p;
  for (i in particles) {
    if (particles[i].x == x && particles[i].y == y) {
      found = true;
      p = particles[i].p;
    }
  }
  if (found) {
    return [found, p] 
  } else {
    return [found];
  }
}

而且我还会删除一些不必要的变量(它们可以被替换为返回值)

还有一件事我会改变,在JavaScript中,如果你从一个for()循环或if()语句中删除括号,它只会执行下一条语句。这是你可以在这里做的事情

我会这样做:

function check(x, y) {
  for (let i = 0; i < particles.length; i++)
    if (particles[i].x == x && particles[i].y == y)
      return [true, particles[i].p];
  return [false];
}

好处:

  • 更快
  • 易于阅读
  • 少量文本,文件更小

我注意到这个被接受了 - 它实际上显著提高了速度吗?在 check 中仍然有一个嵌套的粒子循环,这可能是大部分缓慢的原因,并且其他问题也没有得到解决,所以如果这带来了显著的收益,我会感到惊讶。 - ggorlen
@ggorlen 我是stackoverflow的新手,它确实提高了速度,但肯定不是唯一可以帮助的东西。我还有点改变了整个项目的代码并重新做了一些事情。更新的代码+托管示例在这里:https://replit.com/@LoganStottle202/pixsim?v=1如果您有更多建议,那就太好了,如果您想在discord上给我发消息,那就更好了,这样您就可以向我展示您看到的所有错误。我的discord账号是bread#7194,感谢您的帮助。 - bread
如果我有时间,我会稍后查看的,目前我只有时间提供建议。编写一个认真的、完整的答案并验证所有主张需要一些时间。这是个好问题,所以我相信这个帖子最终会出现更多的想法。 - ggorlen
我知道你个人面包... - ITDW
另外,我只是根据您认为的问题来执行了您的检查函数以保持答案。但是,是的,ggorlen是正确的,还有许多其他可以改进的地方。 - ITDW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接