我一直试图用P5.js创建一个简单的分形树程序,用于在网站上显示,但我似乎得到了意想不到的行为.代码和图片附上.

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)
  }
}

Fractals not fractaling

我正在使用递归调用,似乎只有我的第一个递归调用正在运行,一旦第一个(也只是第一个)递归调用结束,整个绘制循环就会在不同的开始位置重新启动.当我使用少量的分支层(3个或更少)时,我也有一些奇怪的行为.

推荐答案

主要问题是,您没有使用varletconst来定义变量,因此所有变量都被隐式声明为全局变量,这是造成混乱的原因.leftNodeX和类似变量的值被递归调用修改,因此当这些递归调用返回时,这些变量不再具有它们的预期值,并且下一次递归调用将获得不再有意义的参数.

还有其他几个问题:

  • 偏移量不应随常量而减小.如果你从numNodes开始等于5,那么在不同的递归深度,你会得到offset,50,然后是40,30,20,...这并不理想.该序列应该是geometric序列,即offset应该减go factor,而不是常量.要实现这一点,只需将偏移量作为参数传递,而不是将 node 数作为参数传递会更容易.

  • 因为没有设置笔划,所以没有画出第一条线.请注意,这条线是在调用line()时绘制的,您只需要调用stroke一次:它是对line(和其他绘制函数)的任何后续调用的配置.这样你就可以在你的设置中移动stroke()呼叫.

  • 要支持其他屏幕大小,请不要硬编码画布大小,而是使用有关屏幕大小(或窗口大小)的浏览器信息(与CSS一起).

  • P5将永远继续呼叫draw.因为您没有动画,所以没有必要这样做:一个调用就足够了.您可以通过添加对P5的S noLoop的呼叫来指示这一点

  • Should I use semicolons in JavaScript?

更正:

function setup() {
  // Use browser information to set size (see also CSS settings for body)
  createCanvas(screen.width, screen.height);
  // Call stroke before drawing
  stroke(255,255,255);
}

function draw() {
  background(10);
  // Define variables with const 
  const x = width >> 1; // Use integer division
  const y = height >> 1;
  // Pass the initial offset instead of the number of nodes
  fractalDraw(x, y, width >> 2, 0);
  noLoop(); // Avoid repeating calls to draw()
}

function fractalDraw(nodeX, nodeY, offset, sideFlag){
  // Define variables with const (here was the most dramatic bug) 
  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(offset <= 1){
    return 1;
  }
  else{
    // The offset should decrease by a factor, not by a constant
    offset >>= 1; // For example: integer divide by 2
    fractalDraw(leftNodeX, topNodeY, offset, -1);
    fractalDraw(leftNodeX, botNodeY, offset, -1);
    fractalDraw(rightNodeX, topNodeY, offset, 1);
    fractalDraw(rightNodeX, botNodeY, offset, 1);
  }
}
html, body { margin: 0; height: 100%; overflow: hidden; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>

代码绘制的"树"形状也有一个问题.我假设所有的线路都应该是连接的,但是如果标志是-1或1(所以除了初始调用之外的所有情况),四个递归调用中的两个将传递先前的line调用可能没有使用的坐标,因此您有时会断开连接的线路.

我只能猜测你想要什么形状,但这里有一个你可能想要考虑的替代方案:

function setup() {
  createCanvas(screen.width, screen.height);
  stroke(255,255,255);
}

function draw() {
  background(10);
  const x = width >> 1
  const y = height >> 1;
  fractalDraw(x, y, x, y, width >> 2);
  noLoop();
}

function fractalDraw(fromX, fromY, nodeX, nodeY, offset){
  line(fromX, fromY, nodeX, nodeY);
  if (offset < 1) {
    return;
  }
  const leftNodeX = nodeX - offset;
  const rightNodeX = nodeX + offset;
  const topNodeY = nodeY - offset;
  const botNodeY = nodeY + offset;

  offset >>= 1;
  fractalDraw(nodeX, nodeY, leftNodeX, topNodeY, offset);
  fractalDraw(nodeX, nodeY, leftNodeX, botNodeY, offset);
  fractalDraw(nodeX, nodeY, rightNodeX, topNodeY, offset);
  fractalDraw(nodeX, nodeY, rightNodeX, botNodeY, offset);
}
html, body { margin: 0; height: 100%; overflow: hidden; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>

Javascript相关问答推荐

materialized - activeIndex返回-1

有条件的悲剧

过滤对象数组并动态将属性放入新数组

IMDB使用 puppeteer 加载更多按钮(nodejs)

类型脚本中只有字符串或数字键而不是符号键的对象

使用JavaScript重新排序行

Rehype将hashtag呈现为URL

配置WebAssembly/Emscripten本地生成问题

如何在Vue 3中创建自定义 Select 组件,并将选项作为HTML而不是props 传递?

在HTML语言中调用外部JavaScript文件中的函数

当用户点击保存按钮时,如何实现任务的更改?

搜索功能不是在分页的每一页上进行搜索

无法重定向到Next.js中的动态URL

P5.js中的分形树

react -原生向量-图标笔划宽度

如何在AG-Grid文本字段中创建占位符

postman 预请求中的hmac/sha256内标识-从js示例转换

ReactJS Sweep Line:优化SciChartJS性能,重用wasmContext进行多图表渲染

CSS网格使页面自动滚动

JavaScript structuredClone在Chrome/Edge中获得了非法调用,但在NodeJS中没有