применение setTimeout к рекурсивному дереву в p5. js - PullRequest
1 голос
/ 28 февраля 2020

Я использую 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>

Пожалуйста, дайте любое решение, чтобы вырастить дерево плавно (а не сразу).

1 Ответ

3 голосов
/ 28 февраля 2020

Для этого вы можете использовать async и await.

  1. Определите функцию полезности, которая возвращает обещание, которое разрешается после заданной задержки:

    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 может вызываться, пока продолжается асинхронная цепочка рисования. Это приведет к неожиданному смешению рисунка.

Этого можно избежать, временно «отключив» эту функцию с помощью защитного устройства, следующим образом:

  1. Определите глобальную переменную busy = false;

  2. Управляйте этой переменной в начале / конце чертежа, изменив функцию draw на:

    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>
...