将 setTimeout 应用于 p5.js 中的递归树

applying setTimeout to recursive tree in p5.js

我正在使用 p5.js 在 html5 convas 中创建正在生长的树。
我想顺利地生成下面的树,而不是一次生成。

function setup(){ 
  createCanvas(600,600); 
  noLoop(); 
} 

function draw(){ 
  background(255);    
  strokeWeight(10); 
  translate(width/2,height-20); 
  branch(0); 
} 

function branch(depth){ 
  if (depth < 10) { 
    line(0,0,0,-height/10); // draw a line going up
    { 
      translate(0,-height/10); // move the space upwards
      rotate(random(-0.05,0.05));  // random wiggle

      if (random(1.0) < 0.6){ // branching   
        rotate(0.3); // rotate to the right
        scale(0.8); // scale down
        
        push(); // now save the transform state
        branch(depth + 1); // start a new branch!
        pop(); // go back to saved state
        
        rotate(-0.6); // rotate back to the left 
        
        push(); // save state
        branch(depth + 1);   // start a second new branch 
        pop(); // back to saved state        
     } 
      else { // no branch - continue at the same depth  
        branch(depth);
      } 
    } 
  }
} 


function mouseReleased(){ 
  redraw();  
}
html, body {
  margin: 0;
  padding: 0;
}
<script src="https://cdn.jsdelivr.net/npm/p5@0.10.2/lib/p5.js"></script>
<!DOCTYPE html><html><head>
  </head>
  <body>
    <script src="sketch.js"></script>
  

</body></html>

我正在使用 setTimeout 函数来延迟每个递归分支以使树顺利生长。
但是得到了意想不到的形状

function setup(){ 
  createCanvas(600,600); 
  noLoop(); 
} 

function draw(){ 
  background(255);    
  strokeWeight(10); 
  translate(width/2,height-20); 
  branch(0); 
} 

function branch(depth){ 
setTimeout(function() {
  if (depth < 10) { 
    line(0,0,0,-height/10); // draw a line going up
    { 
      translate(0,-height/10); // move the space upwards
      rotate(random(-0.05,0.05));  // random wiggle

      if (random(1.0) < 0.6){ // branching   
        rotate(0.3); // rotate to the right
        scale(0.8); // scale down
        
        push(); // now save the transform state
        branch(depth + 1); // start a new branch!
        pop(); // go back to saved state
        
        rotate(-0.6); // rotate back to the left 
        
        push(); // save state
        branch(depth + 1);   // start a second new branch 
        pop(); // back to saved state        
     } 
      else { // no branch - continue at the same depth  
        branch(depth);
      } 
    } 
  }
}, 500);
} 


function mouseReleased(){ 
  redraw();  
}
html, body {
  margin: 0;
  padding: 0;
}
<script src="https://cdn.jsdelivr.net/npm/p5@0.10.2/lib/p5.js"></script>
<!DOCTYPE html><html><head>
  </head>
  <body>
    <script src="sketch.js"></script>
  

</body></html>

请给出让树顺利生长的任何解决方案(而不是一次)。

您可以为此使用 asyncawait

  1. 定义效用函数 returns 在给定延迟后解决的承诺:

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
    
  2. 使您的 branch 函数 async(只需在其前面加上该关键字)。

  3. 在您进行的三个递归调用中的每一个之前添加 await。例如:

    await branch(depth+1);
    
  4. 新增一行引入延迟:

    if (depth < 10) {
        await delay(10); // "sleep" for 10 milliseconds.
        // ...
    

结果:

function setup(){ 
  createCanvas(600,600); 
  noLoop(); 
} 

function draw(){ 
  background(255);    
  strokeWeight(10); 
  translate(width/2,height-20); 
  branch(0); 
} 

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function branch(depth){ 
  if (depth < 10) { 
    await delay(10);
    line(0,0,0,-height/10); // draw a line going up
    { 
      translate(0,-height/10); // move the space upwards
      rotate(random(-0.05,0.05));  // random wiggle

      if (random(1.0) < 0.6){ // branching   
        rotate(0.3); // rotate to the right
        scale(0.8); // scale down
        
        push(); // now save the transform state
        await branch(depth + 1); // start a new branch!
        pop(); // go back to saved state
        
        rotate(-0.6); // rotate back to the left 
        
        push(); // save state
        await branch(depth + 1);   // start a second new branch 
        pop(); // back to saved state        
     } 
      else { // no branch - continue at the same depth  
        await branch(depth);
      } 
    } 
  }
} 


function mouseReleased(){ 
  redraw();  
}
<script src="https://cdn.jsdelivr.net/npm/p5@0.10.2/lib/p5.js"></script>

请注意,当异步绘图链仍在进行时,可能会调用 mouseReleased 函数。这将导致绘图发生意想不到的混合。

你可以通过暂时 "disabling" 带有守卫的功能来避免这种情况,如下所示:

  1. 定义一个全局变量busy = false;

  2. 通过将函数 draw 更改为:

    来管理绘图 start/end 处的变量
    function draw(){ 
      if (busy) return; // guard against concurrent drawing activity
      busy = true; // set guard
      background(255);    
      strokeWeight(10); 
      translate(width/2,height-20); 
      branch(0).then(() => busy = false); // clear guard asynchronously
    } 
    

function setup(){ 
  createCanvas(600,600); 
  noLoop(); 
} 

let busy = false;
function draw(){ 
  if (busy) return; // guard against concurrent drawing activity
  busy = true; // set guard
  background(255);    
  strokeWeight(10); 
  translate(width/2,height-20); 
  branch(0).then(() => busy = false); // clear guard asynchronously
} 

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function branch(depth){ 
  if (depth < 10) { 
    await delay(10);
    line(0,0,0,-height/10); // draw a line going up
    { 
      translate(0,-height/10); // move the space upwards
      rotate(random(-0.05,0.05));  // random wiggle

      if (random(1.0) < 0.6){ // branching   
        rotate(0.3); // rotate to the right
        scale(0.8); // scale down
        
        push(); // now save the transform state
        await branch(depth + 1); // start a new branch!
        pop(); // go back to saved state
        
        rotate(-0.6); // rotate back to the left 
        
        push(); // save state
        await branch(depth + 1);   // start a second new branch 
        pop(); // back to saved state        
     } 
      else { // no branch - continue at the same depth  
        await branch(depth);
      } 
    } 
  }
} 


function mouseReleased(){ 
  redraw();  
}
<script src="https://cdn.jsdelivr.net/npm/p5@0.10.2/lib/p5.js"></script>