I've been trying to create a simple fractal tree program using P5.js, for displaying on a website, but I seem to be getting unexpected behavior. Code and picture attached.
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)
}
}
I'm using recursive calls, and it seems only my first recursive call is running, then the entire draw loop restarts in a different starting position than intended once the first (and only the first) recursive call finishes. Also I had some weird behavior when using small number of branch layers (3 or less).
The main issue is that you don't define your variables with
var,letorconst, and so all your variables are implicitly declared as global variables, which is the cause of havoc. The values ofleftNodeXand similar variables are modified by the recursive calls, and so when these recursive calls return, these variables no longer have their intended values, and the next recursive call will get arguments that no longer make sense.There are also a few other issues:
The offset should not diminish with a constant. If you start with
numNodesequal to 5, then at different recursion depths, you'll have anoffsetof 50, then 40, 30, 20, ... This is not ideal. This sequences should be a geometric sequence, i.e. theoffsetshould reduce by a factor, not by a constant. To achieve that, it will be easier to just pass the offset as argument instead of the number of nodes.The very first line is not drawn, because the stroke was not set. Be aware that the line is drawn when the call
line()is made, and you only need to callstrokeonce: it is a configuration for any of the next calls toline(and other drawing functions). So you could move thatstroke()call in your setup.To support other screen sizes, don't hard-code the canvas size, but use the browser's information (together with CSS) about the screen size (or alternatively, the window's size).
p5 will continue to call
drawforever. As you have no animation, there is no need for that: one call is enough. You can indicate this by adding a call to p5'snoLoopShould I use semicolons in JavaScript?
Correction:
There is also an issue with the "tree" shape your code draws. I assume that lines should all be connected, but in case the flag is -1 or 1 (so all cases except the initial call), two out of four of the recursive calls will pass coordinates that might not have been used by a previous
linecall, and so you sometimes get disconnected lines.I can only guess which shape you were going for, but here is an alternative you may want to consider: