P5.js 中的分形树

问题描述 投票:0回答:1

我一直在尝试使用 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 或更少)时,我也有一些奇怪的行为。

javascript recursion graphics p5.js fractals
1个回答
0
投票

主要问题是您没有使用

var
let
const
定义变量,因此所有变量都隐式声明为全局变量,这是造成严重破坏的原因。
leftNodeX
和类似变量的值会被递归调用修改,因此当这些递归调用返回时,这些变量不再具有其预期值,并且下一个递归调用将获得不再有意义的参数。

还有其他一些问题:

  • 偏移量不应以常数减小。如果您从

    numNodes
    等于 5 开始,那么在不同的递归深度,您的
    offset
    将为 50,然后是 40、30、20……这并不理想。该序列应该是一个geometric序列,即
    offset
    应该减少一个factor,而不是一个常数。为了实现这一点,将偏移量作为参数而不是节点数传递会更容易。

  • 第一条线未绘制,因为未设置笔画。请注意,当调用

    line()
    时,就会绘制线条,并且您只需要调用
    stroke
    一次:它是对
    line
    (以及其他绘图函数)的任何后续调用的配置。因此,您可以在设置中移动该
    stroke()
    调用。

  • 要支持其他屏幕尺寸,请勿对画布尺寸进行硬编码,而是使用浏览器的信息(与 CSS 一起),例如

    clientWidth
    clientHeight

  • p5将永远继续呼叫

    draw
    。正如您所定义的
    fractalDraw
    ,没有必要这样做:一次调用就足够了。您可以通过添加对 p5 的
    noLoop

    的调用来表明这一点
  • 使用 我应该在 JavaScript 中使用分号吗?

更正:

function setup() {
  // Use browser information to set size (see also CSS settings for body)
  createCanvas(document.documentElement.clientWidth, 
               document.documentElement.clientHeight);
  // 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){
  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>

© www.soinside.com 2019 - 2024. All rights reserved.