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







コメント