ProcessingAdventCalendar
今年もProcessingAdventCalendar2016が開催されております。(ちなみに今年は管理の関係上Qiitaに移行しました)
今年は常連様の参加が少なかったので、AdventCalendar存亡の危機にさらされていたのですが、そんな中@n_ryotaさんが2日間素敵なツリー作品を投稿してくださいました。ありがとうございました。
Processingアドカレ 明日こそ誰か…ヘルプ… https://t.co/ridu32qRzD https://t.co/jXC2r2a5na
— n_ryota (@n_ryota) 2016年12月2日
私も何か投稿せねばと思い、急遽3日目を担当することにしました。
今回の成果物
2日間ツリーでしたので、何かツリー縛りで考えたのですが、何も思いつかなかったので、困ったときのGenerative頼みで、雪の結晶を作成することにしました。Generative最高ヽ(・-・)ノ
こんなものができます。
概要
点を描画するパーティクルクラスを作成し、進行方向や速度などを管理することにします。そのパーティクルをArrayListに格納し、ひたすら点を打ち込んでいくだけの簡単なお仕事です。
雪の結晶は6方向に進んでいくので、1パーティクルに対し、60度ずつ回転させながら6回描画すると結晶っぽくなります。
途中で確率で枝分かれを行い、ArrayListに子パーティクルを追加していけば、あとはGenerativeでいい味を出してくれます。永遠とさまざまな形の雪の結晶を作成しますので、ずっと眺めていることができますね。
動くものは下記OpenProcessingで公開しております。
https://www.openprocessing.org/sketch/392536
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
// パーティクルクラス class P { float ang; // 進行角度 PVector pos; // 位置 float v; // 速度 int depth; // 深さ float size; // 大きさ P() { pos = new PVector(); } // 初期化 void init(float _ang, float x, float y, float _v, int _depth, float _size) { ang = _ang; pos.set(x, y); v = _v; depth = _depth; size = _size; } // 子として生まれる void born(P p, float _ang) { ang = p.ang + _ang; pos.set(p.pos.x, p.pos.y); depth = p.depth - 1; v = p.v * (0.4 * depth) * (random(0.2) + 0.8); size = p.size; } // 描画動作 void act() { // パラメータ変更 pos.add(cos(ang) * v, sin(ang) * v); v -= 0.02; // 描画 translate(width / 2, height / 2); for (int i = 0; i < 6; i++) { ellipse(pos.x, pos.y, size, size); rotate(radians(60)); } translate(- width / 2, -height / 2); } } ArrayList<P> perticles = new ArrayList<P>(); float generateRatio; // 子供性確率変数 float waitCount; // 描画終了後の待機時間 //------------------------------------------------- // setup //-------------------------------------------------- void setup() { background(0); size(700, 700); init(); } //-------------------------------------------------- // 初期化処理 //-------------------------------------------------- void init() { fill(255, 255); noStroke(); perticles.clear(); P p = new P(); p.init(random(60), 0, 0, random(2) + 2, 3, random(3) + 1); perticles.add(p); generateRatio = random(0.03) + 0.02; } //-------------------------------------------------- // draw //-------------------------------------------------- void draw() { if (perticles.size() == 0) { waiting(); } else { drawing(); } } //-------------------------------------------------- // 描画完了後の余韻 //-------------------------------------------------- void waiting() { fill(0, 8); rect(0, 0, width, height); waitCount++; if (waitCount >= 50) { waitCount = 0; init(); } } //-------------------------------------------------- // 描画メイン処理 //-------------------------------------------------- void drawing() { ArrayList<P> childs = new ArrayList<P>(); // 今回生まれた子 ArrayList<P> deads = new ArrayList<P>(); // 今回死ぬパーティクル for (P p : perticles) { p.act(); if (p.v <= 0) { deads.add(p); } if (random(1) < (generateRatio * p.depth)) { float r = random(30) + 20; P child1 = new P(); child1.born(p, radians(r)); childs.add(child1); P child2 = new P(); child2.born(p, radians(-r)); childs.add(child2); } } // リストから生まれた子を追加 for (P child : childs) { perticles.add(child); } // リストから死んだ子を削除 for (P dead : deads) { perticles.remove(dead); } } void mouseClicked() { init(); } |
発展
パラメータを調整すれば、自然界に存在しない10角形の結晶や30角形の結晶も作り出すことができます。
雪の結晶というよりもコースターに近いかな。
感想
Generative画像はいつまでも観ていられるので本当に楽しいものです。
来年も素敵なProcessingライフをお送りください。
あと、ProcessingAdventCalendar2016にはまだまだ開き枠がありますので、皆様ぜひぜひご参加ください。
http://qiita.com/advent-calendar/2016/processing
コメント