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
ソースコード
// パーティクルクラス 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
コメント