見出し画像

Processing Community Hangout Japan vol.2:スケッチ鑑賞会に応募

2020/07/05(日) 開催のクリエイティブ・コーディング関連のオンラインイベント「Processing Community Hangout Japan vol.2」、その中の企画で七夕をお題にした作品を募集する「スケッチ鑑賞会」に応募してみました。

画像2

意気込み!

今回の作品作りでは2つのことに挑戦しました。

複数シーンのリアルタイムアニメーション
リアルタイムに画面表示される複数のシーンからなるアニメーションに挑戦しました。
普段は Processing でのグローバル変数を嫌ってリアルタイムのアニメーションはあまり作ってませんでした。複数シーンのものもあまり作ったことがなく、ワンシーンのループアニメーションばかり作っていました。

ループアニメーション例

詩的表現
自分なりに詩的な(詩的って何かしら?🤔)表現を考えて、それを実装することに挑戦しました。
いつもはロジック先行で、「こんなロジックを基にコードを書いたらこんな結果になった」という作り方ばかりしていましたが、今回はまず結果の絵とその動きを先に考えて、それをコードでいかに実装するかという作り方(多分これが一般的な作り方?)で進めました。

画像3

完成したアニメーション

出来上がったものがこちらです。「歌」とありますが、音はありません。

いかがでしたか?🙂
詩的な表現を感じていただけたでしょうか?

画像4

工夫した点

コードは Processing で書きました。

4月に行われた「Creative Coding Online Meetup 1」での Naoto Hieda さんの発表を拝見して、PGraphics を利用して複数作品を組み合わせる方法を知り、今回それを使ってレイヤー的にシーンを重ねる処理を行いました。

<コード例>
  PGraphics bg; // Background starry sky
  PGraphics tz; // Tanzaku

  ~

  image(bg, 0.0, 0.0);
  image(tz, 0.0, 0.0);


短冊の上に願い事を書くシーン(のつもり)はポリモーフィズム(のつもり)を使って各短冊毎に異なる動きを付けているつもりです。

<コード例>
fds[0] = new RandomWalker(ngs[0], 3);
fds[1] = new RandomFlower(ngs[1]);
~
for (int i = 0; i < toIndex; i++) {
  fds[i].move();
  image(ngs[i], width * i / ngNum, 0.0);
}


短冊を細かく散らすシーンでは、短冊の描画結果を切り出して使用しています。
p5.js なら コピー先.copy(コピー元) でいけるんですが、Processing だとコピー先がメインのキャンバス固定になるようで copy() は使えませんでした。代わりにコピー元がメインのキャンバスとなる get() を使って コピー先.image(get()) として切り出しました。

<コード例>
    kfs[i][j].beginDraw();
    kfs[i][j].image(
                    get(
                        kfW * i, kfH * j,
                        kfW, kfH
                        ),
                    0.0, 0.0);
    kfs[i][j].endDraw();


天の川の渦は漸化式とベクターフィールドを使って描きました

<コード例>
    for (int j = 0; j < 200; j++) {
      float plotRatio = map(j, 0, 200, 0.0, 1.0);
      ex += 0.2 * cos(TWO_PI * (sin(TWO_PI * paramA * py) - cos(TWO_PI * paramB * px)));
      ey += 0.2 * sin(TWO_PI * (sin(TWO_PI * paramC * px) - cos(TWO_PI * paramD * py)));
      es = sin(PI * plotRatio) * 1.0;
      _p.ellipse(ex, ey, es, es);
      px = ex;
      py = ey;
    }

元ネタはご存知 尾形光琳 紅白梅図屏風 です。

画像1

直前に日本美術についての本を読んでて影響受けまくりです。🤣

画像5

反省点

構図がピンと来ない。
良い構図にするルールも知らず、感性でもピンと来るものなくて、天の川と星座、和歌の文章の配置をどうしたものかと迷いました。
ちゃんとデザインの勉強しないといけませんね。

なんとなくコーディング。
クラスを使ってデータと描画をまとめている場合と、関数にキャンバス渡して描画している場合が混在していて、その使い分けの意図が「なんとなく」になっちゃってます。
今はいいけど、あとからコード見直したときに意味わかんなくて困るパターン。

キャンバスサイズ可変にしたかった。
描画の位置やサイズをキャンバスサイズとの比率で指定することでキャンバスサイズを変えてもうまいこと表示されるようにしたかったのですが、線の太さとかまで比率で指定するのが大変になってきて、途中で諦めてしまいました。

画像6

コード

全体のコードはこちらです。書くのにのべ 18時間以上はかかってます。

「一日一万回 感謝の 30minコーディング」を毎日続ければ、やがて 30分でこれぐらいのコードを書けるようになるのだろうか…?🤔

/**
* Tanab@ta
* for Processing Community Hangout Japan #02
* 
* Processing 3.5.3
* @author @deconbatch
* @version 0.1
* created 0.1 2020.07.04
*/

int ngNum    = 5;  // Negaigoto = Tanzaku number
int kfwNum   = 10; // Kami Fubuki column number
int kfhNum   = 16; // Kami Fubuki row number
int frmRate  = 30; // frameRate
int[] timing = {   // switching timing
 frmRate * 3,
 frmRate * 8,
 frmRate * 26,
 frmRate * 40,
 frmRate * 60
};

// layer
PGraphics bg; // Background starry sky
PGraphics tz; // Tanzaku
PGraphics sz; // Seiza
PGraphics ngs[]   = new PGraphics[ngNum];          // Negaigoto

// drawing objects
PGraphics kfs[][] = new PGraphics[kfwNum][kfhNum]; // Kami Fubuki
PVector   kfl[][] = new PVector[kfwNum][kfhNum];   // Kami Fubuki Location
Fude      fds[]   = new Fude[ngNum];               // Negaigoto no Fude
Constellation syokujyo, kengyuu; // Seiza
Utayomi       uta;               // Waka

/**
* Fude
* drawing methods of Negaigoto.
*/
public abstract class Fude {
 PGraphics p;
 Fude(PGraphics _p) {
   p = _p;
 }
 public abstract void move();
}

public class Ripples extends Fude {
 int rNum = 20;
 ArrayList<PVector> ripples = new ArrayList<PVector>();
 Ripples(PGraphics _p) {
   super(_p);
   addRipple();
 }

 private void addRipple() {
   ripples.add(new PVector(random(0.25, 0.75) * p.width, random(0.2, 0.8) * p.height, 0.0));
 }

 public void move() {
   if (ripples.size() < rNum && random(1.0) < 0.2) {
     addRipple();
   }
   p.beginDraw();
   p.background(0.0, 0.0, 0.0, 0.0);
   p.noFill();
   p.strokeWeight(1.0);
   for (int i = 0; i < ripples.size(); i++) {
     PVector r = ripples.get(i);
     r.z += 1.5;
     if (r.z > 100.0) {
       ripples.remove(i);
     } else {
       p.stroke(0.0, 0.0, 20.0, 100.0 - r.z);
       for (float eR = r.z; eR > 2; eR -= 15) {
         p.ellipse(r.x, r.y, eR, eR);
       }
     }
   }
   p.endDraw();
 }
}

public class RandomFlower extends Fude {
 int fNum = 15;
 ArrayList<PVector> flows = new ArrayList<PVector>();
 RandomFlower(PGraphics _p) {
   super(_p);
   addFlow();
 }

 private void addFlow() {
   flows.add(new PVector(random(0.2, 0.8) * p.width, random(p.height), random(40.0, 70.0)));
 }

 public void move() {
   if (flows.size() < fNum && random(1.0) < 0.2) {
     addFlow();
   }
   p.beginDraw();
   p.background(0.0, 0.0, 0.0, 0.0);
   p.rectMode(CENTER);
   p.noFill();
   p.strokeWeight(1.0);
   for (int i = 0; i < flows.size(); i++) {
     PVector r = flows.get(i);
     r.x += sin(i * TWO_PI / flows.size());
     r.y += 0.5;
     r.z -= 1.0;
     if (r.z <= 0.0) {
       flows.remove(i);
     } else {
       for (float eR = r.z; eR > r.z - 15.0; eR -= 5.0) {
         p.stroke(0.0, 0.0, 0.0, map(eR, 70.0, 0.0, 60.0, 0.0));
         p.pushMatrix();
         p.translate(r.x, r.y);// - eR * eR * 0.025);
         p.rotate(eR * 0.2);
         p.ellipse(0.0, 0.0, eR, eR * 0.25);
         p.ellipse(0.0, 0.0, eR * 0.25, eR);
         p.popMatrix();
       }
     }
   }
   p.endDraw();
 }
}

public class RandomWalker extends Fude {
 int corners;
 int   walkerMax;
 int   tailMax;
 float sideLen;
 ArrayList walkers = new ArrayList();

 RandomWalker(PGraphics _p, int _corners) {
   super(_p);
   corners = _corners;
   walkerMax = 8; //21 - corners * 2;
   tailMax   = 30; //corners * 3; // walker's tail
   sideLen   = 8.0 - corners * 1.0;

   for (int i = 0; i < walkerMax; i++) {
     float wC = (50.0 * i) % 360.0;
     float wD = TWO_PI / corners;
     int   wR = 0; //floor(random(corners));
     float wX = 0.0; //sideLen * corners * sin(wD) * i;
     float wY = sideLen * corners * sin(wD) * 2.0 * (i - walkerMax * 0.5); //sideLen * corners * i - (sideLen * corners * walkerMax) * 0.5;
     ArrayList<Walker> tails = new ArrayList<Walker>();
     for (int j = 0; j < tailMax; j++) {
       tails.add(new Walker(wX, wY, wC, wD, wR));
     }
     walkers.add(tails);
   }
  
 }

 public void move() {
   p.beginDraw();
   p.background(0.0, 0.0, 0.0, 0.0);
   p.translate(p.width * 0.5, p.height * 0.5);
   p.strokeWeight(4 - corners % 4);
   p.strokeJoin(ROUND);
   p.strokeCap(SQUARE);
   p.noFill();

   for (int i = 0; i < walkers.size(); i++) {
     float wX = 0.0;
     float wY = 0.0;
     float wC = 0.0;
     float wD = 0.0;
     int   wR = 0;
     float wA = 0.0;
       
     ArrayList<Walker> tails = (ArrayList)walkers.get(i);
     for (Walker walker : tails) {
       wX = walker.x;
       wY = walker.y;
       wC = walker.colour;
       wD = walker.radianDiv;
       wR = walker.rotateCnt;
       wA += 2.0;

       p.stroke(0.0, 0.0, 100.0, wA);
       p.beginShape();
       p.vertex(wX, wY);
       for (int j = 0; j < corners; j++) {
         // it makes a straight line between corners
         wX += sideLen * cos(wR * wD);
         wY += sideLen * sin(wR * wD);
         p.vertex(wX, wY);
       }
       p.endShape();
     }
       
     if (abs(wX) < p.width * 0.35 && abs(wY) < p.height * 0.35) {
       if (random(1.0) < 0.5) {
         --wR; // not turn
       } else {
         if (random(1.0) < 0.1) {
           wD *= -1.0; // turn
         }
       }
     }
       
     ++wR;
     wR %= corners;
     // tail shift
     tails.add(new Walker(wX, wY, wC, wD, wR));
     tails.remove(0);
   }
   p.endDraw();
 }

 private class Walker {
   public float x, y;
   public float colour;
   public float radianDiv;
   public int   rotateCnt;

   Walker(float _x, float _y, float _c, float _d, int _r) {
     x = _x;
     y = _y;
     colour = _c;
     radianDiv = _d;
     rotateCnt = _r;
   }
 }
}

/**
* Constellation
* drawing constellation of the Lyra and the Aquila.
*/
public abstract class Constellation {
 PGraphics p;
 ArrayList<PVector> stars = new ArrayList<PVector>();
 ArrayList<Integer> lines = new ArrayList<Integer>();
 float hueVal;
 float initX, initY;
 float sizeMult;
 int beat;

 Constellation(PGraphics _p, float _c, float _x, float _y, float _s, int _b) {
   p = _p;
   hueVal = _c;
   initX = _x;
   initY = _y;
   sizeMult = _s;
   beat = _b;
   setStars();
   setLines();
 }

 abstract public void setStars();
 abstract public void setLines();
 
 public void draw() {

   p.beginDraw();
   p.pushMatrix();

   p.blendMode(SCREEN);
   p.rectMode(CENTER);
   p.translate(initX, initY);

   p.noStroke();
   for (PVector s : stars) {
     for (int i = 0; i < 4; i++) {
       p.fill(0.0, 0.0, 50.0 - i * 10.0, 100.0);
       p.pushMatrix();
       p.translate(s.x * sizeMult, s.y * sizeMult);
       p.rotate(PI * 0.25);
       p.rect(0.0, 0.0, i * sizeMult * 0.75, i * sizeMult * 0.75);
       p.popMatrix();
     }
   }
   p.noFill();
   p.strokeWeight(1.0);
   p.strokeJoin(ROUND);
   p.strokeCap(SQUARE);
   p.stroke(0.0, 0.0, 50.0, 100.0);
   p.beginShape();
   for (int l : lines) {
     p.vertex(stars.get(l).x * sizeMult, stars.get(l).y * sizeMult);
   }
   p.endShape();

   p.popMatrix();
   p.endDraw();
   
 }
 
 public void grow() {
   float rate = (frameCount % beat) * 1.0 / beat;
   float bri = 20.0 + 80.0 * sin(PI * rate);
   float siz = sizeMult * (1.0 - sin(PI * rate)) * 5.0;
   
   p.beginDraw();
   p.blendMode(BLEND);
   p.translate(initX, initY);
   p.noStroke();
   p.fill(hueVal, 60.0, bri, 100.0);
   p.ellipse(
             stars.get(0).x * sizeMult,
             stars.get(0).y * sizeMult,
             siz,
             siz
             );
   p.endDraw();
 }
}

public class Syokujyo extends Constellation {
 Syokujyo(PGraphics _p, float _c, float _x, float _y, float _s, int _b) {
   super(_p, _c, _x, _y, _s, _b);
 }
 public void setStars() {
   stars.add(new PVector(0.0, 0.0));
		stars.add(new PVector(-10.0, 8.0));
		stars.add(new PVector(-20.0, 10.0));
		stars.add(new PVector(-25.0, 30.0));
		stars.add(new PVector(-15.0, 28.0));
 }
 public void setLines() {
   lines.add(0);
   lines.add(1);
   lines.add(2);
   lines.add(3);
   lines.add(4);
   lines.add(1);
 }
}

public class Kengyuu extends Constellation {
 Kengyuu(PGraphics _p, float _c, float _x, float _y, float _s, int _b) {
   super(_p, _c, _x, _y, _s, _b);
 }
 public void setStars() {
   stars.add(new PVector(0.0, 0.0));
		stars.add(new PVector(2, -3));
		stars.add(new PVector(-3, 4));
		stars.add(new PVector(-12, 16));
		stars.add(new PVector(-2, 12));
		stars.add(new PVector(8, 9));
		stars.add(new PVector(18, 24));
		stars.add(new PVector(16, -6));
 }
 public void setLines() {
   lines.add(0);
   lines.add(1);
   lines.add(0);
   lines.add(2);
   lines.add(3);
   lines.add(4);
   lines.add(5);
   lines.add(6);
   lines.add(5);
   lines.add(7);
   lines.add(0);
 }
}

/**
* Utayomi
* drawing the Waka.
*/
public class Utayomi {
 int     kuNum    = 5;                  // Ku number (it may be bad name)
 String  ku[]     = new String[kuNum];  // Ku text
 PVector locate[] = new PVector[kuNum]; // drawing location
 int     yomi[]   = new int[kuNum];     // for drawing animation
 int     timing[] = new int[kuNum * 2]; // switching timing
 Utayomi(int _start, int _stop) {
   ku[0] = "ひさかたの";     //  5  5
   ku[1] = "天つしるしと";   //  7  6
   ku[2] = "水無し川";       //  5  4
   ku[3] = "隔てて置きし";   //  7  6
   ku[4] = "神代し恨めし";   //  7  6

   locate[0] = new PVector(width * 0.825, height * 0.6);
   locate[1] = new PVector(width * 0.77,  height * 0.55);
   locate[2] = new PVector(width * 0.715, height * 0.675);
   locate[3] = new PVector(width * 0.3,   height * 0.775);
   locate[4] = new PVector(width * 0.235, height * 0.825);

   // 11.5 : frmRate * 2(yomihajime) + frmRate * 4.5(interval) + frmRate * 5(yoin)
   // 7 : frmRate * 6.2(yomi)
   int frmLen = _stop - _start;
   if (frmLen - frmRate * 11.5 < frmRate * 7) { // enough time?
     for (int i = 0; i < kuNum; i++) {
       timing[i * 2] = 0;
       yomi[i] = ku[i].length();
     }
   } else {
     timing[0] = floor(_start + frmRate * 2);
     timing[1] = floor(timing[0] + frmRate * 1.0);
     
     timing[2] = floor(timing[1] + frmRate * 1.0);
     timing[3] = floor(timing[2] + frmRate * 1.4);
     
     timing[4] = floor(timing[3] + frmRate * 1.0);
     timing[5] = floor(timing[4] + frmRate * 1.2);
     
     timing[6] = floor(timing[5] + frmRate * 1.5);
     timing[7] = floor(timing[6] + frmRate * 1.2);
     
     timing[8] = floor(timing[7] + frmRate * 1.0);
     timing[9] = floor(timing[8] + frmRate * 1.4);
     for (int i = 0; i < kuNum; i++) {
       yomi[i] = 0;
     }
   }
 }
 
 public void utau() {
   fill(0.0, 0.0, 90.0, 100.0);
   textAlign(CENTER, TOP);
   for (int i = 0; i < kuNum; i++) {
     int t = i * 2;
     if (frameCount > timing[t] && frameCount < timing[t + 1]) {
       yomi[i] = ceil(map(frameCount, timing[t], timing[t + 1], 0, ku[i].length()));
     }
     text(ku[i].substring(0, yomi[i]), locate[i].x, locate[i].y, 62.0, height);
   }
 }
}

/**
* world famous Setup and Draw
* 
*/
public void setup() {
 size(1280, 720);
 colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
 rectMode(CENTER);
 smooth();
 frameRate(frmRate);

 /*** WARNING! environment-dependent ***/
 textFont(createFont("KouzanBrushFontSousyo", 58, true));

 // initialize layers
 bg = pgInit();
 tz = pgInit();
 sz = pgInit();
 for (int i = 0; i < ngNum; i++) {
   ngs[i] = ngInit();
 }

 // initialize drawing objects
 for (int i = 0; i < kfwNum; i++) {
   for (int j = 0; j < kfhNum; j++) {
     kfs[i][j] = kfInit();
   }
 }
 
 fds[0] = new RandomWalker(ngs[0], 3);
 fds[1] = new RandomFlower(ngs[1]);
 fds[2] = new RandomWalker(ngs[2], 4);
 fds[3] = new Ripples(ngs[3]);
 fds[4] = new RandomWalker(ngs[4], 6);

 syokujyo = new Syokujyo(sz, 350.0, width * 0.225, height * 0.165, 5.5, frmRate * 5);
 kengyuu  = new Kengyuu(sz, 220.0, width * 0.825, height * 0.775, 5.5, frmRate * 4);

 uta = new Utayomi(timing[3], timing[4]);

 // initial draw
 darkSky(bg);
 syokujyo.draw();
 kengyuu.draw();
 amanogawa(sz);
 
}

public void draw() {

 background(0.0, 0.0, 0.0, 100.0);
 
 if (frameCount < timing[0]) {
   image(bg, 0.0, 0.0);
 } else if (frameCount < timing[1]) {
   // Ki
   insertTanzaku(tz, map(frameCount, timing[0], timing[1] - frmRate, 0.0, 1.0));
   image(bg, 0.0, 0.0);
   image(tz, 0.0, 0.0);
 } else if (frameCount < timing[2]) {
   // Syou
   image(bg, 0.0, 0.0);
   image(tz, 0.0, 0.0);
   drawNegaigoto(timing[1], timing[2]);
   if (frameCount == timing[2] - 1) {
     cutTanzaku();
   }
 } else if (frameCount < timing[3]) {
   // Ten
   image(bg, 0.0, 0.0);
   syokujyo.grow();
   kengyuu.grow();
   image(sz, 0.0, 0.0);
   drawKamifubuki((frameCount - timing[2]) * 0.05);
 } else if (frameCount < timing[4]) {
   // Ketsu
   image(bg, 0.0, 0.0);
   syokujyo.grow();
   kengyuu.grow();
   image(sz, 0.0, 0.0);
   uta.utau();
 } else {
   exit();
 }
 
}

/**
* pgInit
* main canvas size layer initialization.
*/
public PGraphics pgInit() {
 PGraphics p = createGraphics(width, height);
 p.beginDraw();
 p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
 p.background(0.0, 0.0, 0.0, 0.0);
 p.endDraw();
 return p;
}

/**
* ngInit
* Negaigoto size layer initialization.
*/
public PGraphics ngInit() {
 PGraphics p = createGraphics(width / ngNum, height);
 p.beginDraw();
 p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
 p.background(0.0, 0.0, 0.0, 0.0);
 p.endDraw();
 return p;
}

/**
* kfInit
* Kami Fubuki size layer initialization.
*/
public PGraphics kfInit() {
 PGraphics p = createGraphics(width / kfwNum, height / kfhNum);
 p.beginDraw();
 p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
 p.background(0.0, 0.0, 0.0, 0.0);
 p.endDraw();
 return p;
}

/**
* darkSky
* draw dark starry sky.
*/
public void darkSky(PGraphics _p) {
 _p.beginDraw();
 _p.background(0.0, 0.0, 0.0, 100.0);
	_p.noStroke();
	for (int x = 0; x < width; x += 10) {
		for (int y = 0; y < height; y += 10) {
			_p.fill(
             map(noise(y * 0.005, x * 0.005), 0, 1, 220.0, 260.0),
             60.0,
             noise(x * 0.002, y * 0.002) * 60.0,
             100.0
             );
			_p.rect(x, y, 10.0, 10.0);
     if (random(1.0) < 0.1) {
       _p.fill(random(20.0, 60.0), random(80.0), random(60.0), 100.0);
       _p.ellipse(x, y, 2.0, 2.0);
     }
		}
	}
 _p.endDraw();
}

/**
* amanogawa
* draw milky way with points and flowing lines.
*/
public void amanogawa(PGraphics _p) {

 float paramA = random(0.5, 1.0) / height;
 float paramB = paramA * 0.2;
 float paramC = random(0.5, 1.0) / width;
 float paramD = paramC * 0.2;
 
 _p.beginDraw();
 _p.translate(_p.width * 0.3, 0.0);
 _p.blendMode(SCREEN);
	_p.noStroke();
	for (int y = 0; y < _p.height; y += 2) {
		float wave = -cos(TWO_PI * (0.2 + y * 0.8 / _p.height)) * _p.width * 0.2;
		float rW = _p.width * 0.55 * (0.1 + y * 0.9 / _p.height);
		for (int i = 0; i < floor(rW * 0.02); i++) {
     float ex = random(wave, wave + rW);
     float ey = y;
     float es = random(1.0, 3.0);
     _p.fill(60.0, random(60.0), random(30.0, 90.0), 100.0);
     _p.ellipse(ex, ey, es, es);

     float px = ex;
     float py = ey;
     _p.fill(60.0, random(40.0), random(5.0, 20.0), 100.0);
     for (int j = 0; j < 200; j++) {
       float plotRatio = map(j, 0, 200, 0.0, 1.0);
       ex += 0.2 * cos(TWO_PI * (sin(TWO_PI * paramA * py) - cos(TWO_PI * paramB * px)));
       ey += 0.2 * sin(TWO_PI * (sin(TWO_PI * paramC * px) - cos(TWO_PI * paramD * py)));
       es = sin(PI * plotRatio) * 1.0;
       _p.ellipse(ex, ey, es, es);
       px = ex;
       py = ey;
     }
		}
	}
 _p.endDraw();
}

/**
* insertTanzaku
* Tanzaku inseting animation.
*/
public void insertTanzaku(PGraphics _p, float _ratio) {
 // Tanzaku 5 colors. Blue, Red, Yellow, White, Black(Purple)
 float[][] c =
   {
     new float[]{220.0, 60.0, 90.0},
     new float[]{0.0, 40.0, 90.0},
     new float[]{60.0, 50.0, 90.0},
     new float[]{0.0, 0.0, 90.0},
     new float[]{260.0, 60.0, 70.0}
   };
 float w = width / ngNum;
 
 _p.beginDraw();
 _p.background(0.0, 0.0, 0.0, 0.0);
 _p.rectMode(CENTER);
 _p.translate(w * 0.5, 0.0);
 _p.noStroke();
 for (int i = 0; i < ngNum; i++) {
   float y = constrain(height * (1.0 - _ratio * map(i, 0, 4, 3.0, 1.0)), -10.0, height + 10.0);
   _p.fill(c[i][0], c[i][1], c[i][2], 100.0);
   _p.pushMatrix();
   _p.translate(i * w, height * 0.5);
   _p.rotate(PI * (i % 2));
   _p.rect(0.0, y, w, height + 20.0);
   _p.popMatrix();
 }
 _p.endDraw();
}

/**
* drawNegaigoto
* draw each Negaigoto.
*/
public void drawNegaigoto(int _start, int _stop) {
 float div = (_stop - _start) * 1.0 / (ngNum + 2);
 int toIndex = constrain(ceil((frameCount - _start) / div), 1, ngNum);
 for (int i = 0; i < toIndex; i++) {
   if (frameCount % 2 == 0) { // speed down
     fds[i].move();
   }
   image(ngs[i], width * i / ngNum, 0.0);
 }
}

/**
* cutTanzaku.
* cut the Tanzaku into Kami Fubuki.
*/
public void cutTanzaku() {
 for (int i = 0; i < kfwNum; i++) {
   for (int j = 0; j < kfhNum; j++) {
     int kfW = floor(kfs[i][j].width);
     int kfH = floor(kfs[i][j].height);
     kfs[i][j].beginDraw();
     kfs[i][j].image(
                     get(
                         kfW * i, kfH * j,
                         kfW, kfH
                         ),
                     0.0, 0.0);
     kfs[i][j].endDraw();
     kfl[i][j] = new PVector(kfW * i, kfH * j);
   }
 }
}

/**
* drawKamifubuki
* draw Kami Fubuki animation.
*/
public void drawKamifubuki(float _time) {
 for (int i = 0; i < kfwNum; i++) {
   for (int j = 0; j < kfhNum; j++) {
     float nFactor = i * 10.0 + j;
     float kfW = kfs[i][j].width;
     float kfH = kfs[i][j].height * cos(HALF_PI * noise(nFactor) * _time);

     kfl[i][j].x += (0.5 + map(noise(nFactor, _time * 0.5, 100.0), 0.0, 1.0, -2.0, 2.0)) * _time;
     kfl[i][j].y += (0.5 + map(noise(nFactor, _time * 0.5, 200.0), 0.0, 1.0, -2.0, 2.0)) * _time;
     pushMatrix();
     translate(kfl[i][j].x + kfW * 0.5, kfl[i][j].y + kfH * 0.5);
     rotate(noise(nFactor, _time, 300.0) * _time * 0.3);
     image(kfs[i][j], -kfW * 0.5, -kfH * 0.5, kfW, kfH);
     popMatrix();      
   }
 }
}

/*
Copyright (C) 2020- deconbatch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/


(30分のコーディングを1万回行うには 5,000 時間が必要で、一日につき 4,976 時間ずつオーバーしていくので、30分でこれぐらいのコードを書けるようになったとしても、修行が終わらない 🧘‍♀️)

画像7


📘 他にも note でいろんな記事書いています。


🎨 こちらのブログはソースコード付きの作品集になってます。


🐦 Twitter でもいろいろ面白いの上げてるのでぜひフォローしてくださいね。


この記事が面白かったらサポートしていただけませんか? ぜんざい好きな私に、ぜんざいをお腹いっぱい食べさせてほしい。あなたのことを想いながら食べるから、ぜんざいサポートお願いね 💕