如何提升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
相关产品推荐
相关产品推荐

