使用P5.js实现分形树时遭遇递归异常问题求助
P5.js分形树异常问题修复
问题现象
用P5.js编写分形树程序时出现以下异常:
- 仅第一个递归调用执行,draw循环会在非预期位置重启
- 分支层数设置为3或更少时,绘制效果异常
原代码
function setup() { createCanvas(1920, 1080); } function draw() { background(10); x = 1920/2 y = 1080/2 fractalDraw(x, y, 5, 0) } function fractalDraw(nodeX, nodeY, numNodes, sideFlag){ offset = 10 * numNodes leftNodeX = nodeX - offset rightNodeX = nodeX + offset topNodeY = nodeY - offset botNodeY = nodeY + offset if(sideFlag === -1){ //Leftside draw line(nodeX, nodeY, leftNodeX, topNodeY) stroke(255,255,255) line(nodeX, nodeY, leftNodeX, botNodeY) stroke(255,255,255); } else if(sideFlag === 1){ //Rightside draw line(nodeX, nodeY, rightNodeX, topNodeY) stroke(255,255,255); line(nodeX, nodeY, rightNodeX, botNodeY) stroke(255,255,255); } else{ //Starting draw line(nodeX, nodeY, leftNodeX, topNodeY) stroke(255,255,255) line(nodeX, nodeY, leftNodeX, botNodeY) stroke(255,255,255); line(nodeX, nodeY, rightNodeX, topNodeY) stroke(255,255,255); line(nodeX, nodeY, rightNodeX, botNodeY) stroke(255,255,255); } if(numNodes === 1){ //Recursion Base Case return 1 } else{ //Recursive calls fractalDraw(leftNodeX, topNodeY, numNodes-1, -1) fractalDraw(leftNodeX, botNodeY, numNodes-1, -1) fractalDraw(rightNodeX, topNodeY, numNodes-1, 1) fractalDraw(rightNodeX, botNodeY, numNodes-1, 1) } }
错误根源
- 全局变量污染:所有变量(
x、y、offset、leftNodeX等)未用let/const声明,默认成为全局变量。递归过程中后续调用会覆盖这些变量值,导致递归逻辑混乱,出现仅第一个递归执行、绘制位置偏移的问题。 - stroke调用位置错误:
stroke()放在line()之后,第一条线会使用默认黑色(未设置白色笔触),且重复调用冗余。 - 不必要的返回值:递归终止条件返回
1无意义,直接return即可。 - offset计算不合理:
10 * numNodes会让层数越少的分支长度越短,导致层数≤3时分支过于细碎,视觉上异常。
修复后的代码
function setup() { createCanvas(1920, 1080); stroke(255, 255, 255); // 统一设置白色笔触,避免重复调用 } function draw() { background(10); const x = 1920 / 2; const y = 1080; // 把起始点移到画布底部,更符合树的形态(可选调整) fractalDraw(x, y, 5, 0); } function fractalDraw(nodeX, nodeY, numNodes, sideFlag) { const offset = 30 * numNodes; // 调整偏移量系数,让分支长度更合理 const leftNodeX = nodeX - offset; const rightNodeX = nodeX + offset; const topNodeY = nodeY - offset; const botNodeY = nodeY + offset; if (sideFlag === -1) { // 左侧分支绘制 line(nodeX, nodeY, leftNodeX, topNodeY); line(nodeX, nodeY, leftNodeX, botNodeY); } else if (sideFlag === 1) { // 右侧分支绘制 line(nodeX, nodeY, rightNodeX, topNodeY); line(nodeX, nodeY, rightNodeX, botNodeY); } else { // 初始节点绘制 line(nodeX, nodeY, leftNodeX, topNodeY); line(nodeX, nodeY, leftNodeX, botNodeY); line(nodeX, nodeY, rightNodeX, topNodeY); line(nodeX, nodeY, rightNodeX, botNodeY); } if (numNodes === 1) { // 递归终止条件 return; } // 递归调用所有子节点 fractalDraw(leftNodeX, topNodeY, numNodes - 1, -1); fractalDraw(leftNodeX, botNodeY, numNodes - 1, -1); fractalDraw(rightNodeX, topNodeY, numNodes - 1, 1); fractalDraw(rightNodeX, botNodeY, numNodes - 1, 1); }
修复说明
- 给所有局部变量添加
const/let声明,隔离递归过程中的变量作用域,避免全局污染。 - 将
stroke()移到setup()中统一设置,减少冗余代码,确保所有线条都是白色。 - 调整初始Y坐标到画布底部,让分形更像树的形态(可根据需求改回原位置)。
- 增大offset的系数,让低层数的分支长度更合理,解决层数≤3时的异常问题。
- 移除递归终止条件中不必要的返回值,逻辑更简洁。
内容的提问来源于stack exchange,提问作者Yonahel
相关产品推荐
相关产品推荐

