モノ創りで国造りを

ハード/ソフト問わず知見をまとめてます

Processingで再帰の勉強

f:id:yuji2yuji:20180824064403g:plain

人生で初めて、再帰ってものを使ってみました。上のやつがソレです。
今まで趣味でやってたゲーム開発では、再帰関数を使用する場面はなかったのですが
processingでジェネラティブアートを創作するには、知ってないとまずいヤツです。

端的に説明すると、関数の中に同じ関数を生成するというもので
一度その関数を呼び出すと延々と同じ関数が実行されるという、危険な代物です。
実使用の際は、関数の繰り返し回数を制限し、無限ループには陥らないよう注意が必要です。

今まで馴染みのない考えだったので、
参考書読みつつもなかなかうまくいかず、
夜更かしして睡眠不足に。

それでも不思議なことに、
一晩もソースコードとにらめっこしていると
だんだんと概念が体の芯に染み込んできて
ソースコードが頭でビジュアル化されていく感覚になり
上手く再帰を扱えるようになりました。

再帰は指数関数的に処理が増えていくので パラメーター変更すると、processingの表示がしばしば表示されなくなりました。
原因がソースコードなのかPCの非力さなのかがわからず、 時間を浪費しました。

ソースは以下。

final int startBranchNum = 3;
Branch[] branch = new Branch[startBranchNum];
void setup() {
  size(1600, 1200);
  background(255);
  smooth();
  noStroke();
  frameRate(10);
  for (int i=0; i<startBranchNum; i++) {
    branch[i] = new Branch(0, width/2, 300, 90, true);
  }
}

void draw() {
  for (int i=0; i<startBranchNum; i++) {
    branch[i].updateMe();
  }
}


class Branch {

  final float branchLength;
  final float maxAngleRange = 180;
  final float colBase = 100;
  final float colRandom = 155;
  final int maxCounter = 100;
  final float branchAlpha = 20;
  final float branchWidth = 10;

  final int childNum = 2;
  float startX;
  float startY;
  float stopX;
  float stopY;
  float branchAngle;
  color branchColor = color(random(colRandom)+colBase, random(colRandom)+colBase, random(colRandom)+colBase, branchAlpha);
  int myGeneration;


  int stopGeneration = 7;
  int maxCnt = 20;
  int cnt = 0;
  boolean goBranch;

  Branch[] children = new Branch[0];

  Branch(int myGen, float motherStopX, float motherStopY, float motherAngle, boolean go) {
    branchLength = 150/(myGen+1) + 70;
    goBranch = go;
    startX = motherStopX;
    startY = motherStopY;
    myGeneration = myGen;
    branchAngle = random(maxAngleRange);
    float angle = branchAngle%maxAngleRange - maxAngleRange/2 + motherAngle;//Go to Lower
    stopX = startX + cos(radians(angle))*branchLength;
    stopY = startY + sin(radians(angle))*branchLength;

    if (myGeneration < stopGeneration) {
      children = new Branch[childNum];
      for (int i = 0; i < childNum; i++) {
        children[i] = new Branch(myGeneration+1, stopX, stopY, angle, false);
      }
    }
  }

  void updateMe() {
    if (goBranch == true && cnt<maxCnt) {
      stroke(branchColor);
      strokeWeight(branchWidth);
      float posX;
      float posY;


      posX = (stopX - startX)*cnt/maxCnt + startX;
      posY = (stopY - startY)*cnt/maxCnt + startY;
      line(startX, startY, posX, posY);

      cnt++;
    }

    if (myGeneration < stopGeneration) {
      for (int i = 0; i < childNum; i++) {
        if (cnt == maxCnt) {
          children[i].goBranch = true;
        }
        children[i].updateMe();
        println("children's StopX is "+ children[i].stopX);
        println("children's StartX is "+ children[i].startX);
      }
    }
  }
}