You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升p5js迷宫生成器的运行速度?

优化方案:大尺寸p5.js迷宫生成器性能提升

一、砍掉重复渲染(最见效的优化)

原代码每次draw()都重绘整个背景和所有单元格,这是性能卡爆的核心原因——99%的单元格生成后就不会再变,完全没必要反复画。

1. 用离屏缓存存静态内容,只更改变动部分

搞个离屏画布把已经稳定的单元格一次性画好,之后每次draw()只画当前活跃的路径:

// 新增缓存变量
var buffer;

function setup() {
  createCanvas(canvX, canvY);
  buffer = createGraphics(canvX, canvY); // 创建离屏缓存画布
  stroke(0);
  strokeWeight(0.5);
  rect(0, 0, canvX, canvY);
  cols = floor(width/w);
  rows = floor(height/w);
  frameRate(60);
  
  // 初始化网格(原有代码不变)
  for(var j = 0; j < rows; j++){
    for (var i = 0; i < cols; i++){
      var cell = new Cell(i,j);
      grid.push(cell);
    }
  }
  
  current = grid[0];
  // 初始化缓存背景
  buffer.background(51);
}

function draw() {
  // 先把缓存的静态内容画到主画布
  image(buffer, 0, 0);
  
  // 只画当前活跃的单元格
  current.highlight();
  
  // 原有迷宫生成逻辑
  current.visited = true;
  var next = current.checkNeighbors();
  if(next) {
    next.visited = true;
    stack.push(current);
    removeWalls(current,next);
    // 把新稳定的单元格画到缓存里,以后不用再画
    drawCellToBuffer(current);
    drawCellToBuffer(next);
    current = next;
  } else if (stack.length > 0) {
    current = stack.pop();
  }
  
  // 迷宫生成完就停掉循环,别瞎跑
  if (current === grid[0] && stack.length === 0) {
    noStroke();
    fill(0, 255, 0);
    rect(canvX-w+2, canvY-w+2, w-4, w-4);
    noLoop();
  }
}

// 新增:把单元格画到缓存的函数
function drawCellToBuffer(cell) {
  var x = cell.i*w;
  var y = cell.j*w;
  buffer.noStroke();
  buffer.fill(255);
  buffer.rect(x, y, w, w);
  
  buffer.stroke(0);
  if(cell.walls[0]){
    buffer.line(x    ,y    ,x + w,y    );
  } 
  if(cell.walls[1]){
    buffer.line(x + w,y    ,x + w,y + w);
  }
  if(cell.walls[2]){
    buffer.line(x + w,y + w,x    ,y + w);
  }
  if(cell.walls[3]){
    buffer.line(x    ,y + w,x    ,y    );
  }
}

2. 生成完就停循环

当current回到起点且栈为空时,调用noLoop()终止draw(),避免无意义的重复执行。

二、优化墙体绘制,减少重复劳动

原代码每个单元格都画4条墙,其实很多墙是相邻单元格共享的(比如A的右墙就是B的左墙),重复画纯纯浪费性能。

修改缓存绘制函数,只画必要的墙:

function drawCellToBuffer(cell) {
  var x = cell.i*w;
  var y = cell.j*w;
  buffer.noStroke();
  buffer.fill(255);
  buffer.rect(x, y, w, w);
  
  buffer.stroke(0);
  // 顶部墙:只有第一行,或上方单元格没拆底部墙时才画
  if (cell.j === 0 || grid[index(cell.i, cell.j-1)].walls[2]) {
    buffer.line(x, y, x + w, y);
  }
  // 左侧墙:只有第一列,或左侧单元格没拆右墙时才画
  if (cell.i === 0 || grid[index(cell.i-1, cell.j)].walls[1]) {
    buffer.line(x, y, x, y + w);
  }
  // 右墙和底墙只画自己的,相邻单元格负责自己的对应墙
  if (cell.walls[1]) {
    buffer.line(x + w, y, x + w, y + w);
  }
  if (cell.walls[2]) {
    buffer.line(x, y + w, x + w, y + w);
  }
}

三、算法逻辑优化,减少渲染频率

1. 批量生成,一次多走几步

原代码每次draw()只走一步迷宫生成,对老设备来说60帧的压力太大。改成每次draw()执行100步,大幅减少渲染次数:

function draw() {
  image(buffer, 0, 0);
  current.highlight();
  
  // 每次循环执行100步生成逻辑
  for (let step = 0; step < 100; step++) {
    current.visited = true;
    var next = current.checkNeighbors();
    if(next) {
      next.visited = true;
      stack.push(current);
      removeWalls(current,next);
      drawCellToBuffer(current);
      drawCellToBuffer(next);
      current = next;
    } else if (stack.length > 0) {
      current = stack.pop();
    } else {
      // 生成完成,画终点并停循环
      noStroke();
      fill(0, 255, 0);
      rect(canvX-w+2, canvY-w+2, w-4, w-4);
      noLoop();
      break;
    }
  }
}

2. 预先生成再渲染(适合不需要看过程的场景)

如果不需要实时看生成动画,直接在setup()里一次性生成完整个迷宫再画出来,完全省掉draw()循环的开销:

function setup() {
  createCanvas(canvX, canvY);
  stroke(0);
  strokeWeight(0.5);
  cols = floor(width/w);
  rows = floor(height/w);
  
  // 初始化网格(原有代码不变)
  for(var j = 0; j < rows; j++){
    for (var i = 0; i < cols; i++){
      var cell = new Cell(i,j);
      grid.push(cell);
    }
  }
  
  current = grid[0];
  // 一次性生成整个迷宫
  generateMaze();
  
  // 画完整迷宫
  background(51);
  for(var i = 0; i < grid.length; i++){
    grid[i].show();
  }
  // 画终点
  noStroke();
  fill(0, 255, 0);
  rect(canvX-w+2, canvY-w+2, w-4, w-4);
}

// 新增:迷宫生成函数
function generateMaze() {
  while (true) {
    current.visited = true;
    var next = current.checkNeighbors();
    if(next) {
      next.visited = true;
      stack.push(current);
      removeWalls(current,next);
      current = next;
    } else if (stack.length > 0) {
      current = stack.pop();
    } else {
      break;
    }
  }
}

// 不需要draw()函数了

四、适配老设备的额外技巧

1. 降分辨率再放大

你的画布是2560x1440,对2012款iMac来说太吃力。先以小尺寸生成迷宫,再放大渲染:

// 修改变量
var w = 5;
var baseSize = {cols:256, rows:144};
var scale = 10; // 放大倍数
var canvX = baseSize.cols * w * scale;
var canvY = baseSize.rows * w * scale;
var buffer;

function setup() {
  createCanvas(canvX, canvY);
  // 创建小尺寸缓存画布生成迷宫
  buffer = createGraphics(baseSize.cols * w, baseSize.rows * w);
  buffer.stroke(0);
  buffer.strokeWeight(0.5);
  
  cols = baseSize.cols;
  rows = baseSize.rows;
  
  // 初始化网格、生成迷宫(用buffer绘制)
  
  // 生成完放大显示到主画布
  image(buffer, 0, 0, canvX, canvY);
  // 按缩放比例调整终点坐标
  noStroke();
  fill(0, 255, 0);
  rect((baseSize.cols*w -w +2)*scale, (baseSize.rows*w -w +2)*scale, (w-4)*scale, (w-4)*scale);
}

2. 切换WEBGL渲染模式

p5.js的WEBGL模式用GPU加速渲染,对老设备可能有帮助,只需要改一行:

createCanvas(canvX, canvY, WEBGL);

注意:WEBGL坐标系统有变化,需要调整绘制逻辑(比如用translate()把原点移到左上角)。

3. 调低帧速率

如果必须实时生成,把frameRate()降到30,减少CPU/GPU负载:

frameRate(30);

内容的提问来源于stack exchange,提问作者Leander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:43:07