また面白い JavaScript+HTML5 のコードを発見!
ALとかAIっぽい話は好きなので、早速ボイドを enchantMOON でも飛ばしてみた。
と言っても、JavaScript そのまま動かすのでは特にすることもないので、今回はペンで障害物を描いて、更に軌跡を描くとそれに沿ってリーダーが飛んで群れが障害物を避けながら飛ぶという形にしてみた。
ま、障害物を避けるところは全然ダメダメなんだけど…。
その代わり、障害物に当たるとパーティクルが弾けるようにしてみたよ!
正直、画面周りの HTML5(なの?)の div とか canvas とか良くわからないので、下記のページのコードを参考にして div と canvas を用意してみた。
// enchantMOON var backing = MOON.getPaperJSON(MOON.getCurrentPage().backing), tracks = backing.strokes.pop(), div = window.document.createElement("div"), canvas = window.document.createElement("canvas"); canvas.width = backing.width; canvas.height = backing.height; window.document.body.appendChild(div); var ctx = canvas.getContext('2d'); div.appendChild(canvas);
とりあえず動いているけど、こういうことで良いのかな?
後はボイドのコードをまんま持ってくれば、まずはボイドの enchantMOON への移植(!)は完了。
オリジナルは群れの中心に向かって動くようになっているけど、これをリーダーに向かって動くようにするだけ。
ルール1をガッツリ変更。
/** * ルール1: ボイドは近くに存在する群れの中心に向かおうとする */ var rule1 = function(index) { boids[index].vx += (leader.x-boids[index].x) / 100; // リーダーに向かう boids[index].vy += (leader.y-boids[index].y) / 100; // リーダーに向かう };
本当に単純にリーダーと自分の位置の差分を取って x,y それぞれの移動速度を決めています。
次にリーダーがストロークをなぞって移動するようにすれば、群れは自然とリーダーに追いかけてくれる。
リーダーは単純にストロークの x,y をそのまま使って移動するようにしています。
var moveLeader = function() { if (pos<data.length) { leader.x = data[pos++]; leader.y = data[pos++]; pos++; // リーダーのスピードが遅いので1つ飛ばしにする pos++; pos++; pos++; } else { pos = 0; leader.x = data[pos++]; leader.y = data[pos++]; pos++; } }
pos はリーダーが何番目のストロークにいるのか、data は軌跡のストロークが入っている配列。
pos++ が余分に3つあるのは、単純にリーダーの移動速度が遅かったから。
ストロークを1つ飛ばしでリーダーは移動しています。
障害物は、軌跡に使うストローク以外のストローク全部。
ストローク1つ1つが1つの障害物になります。
障害物は各ストロークを Rect にしているだけなので、丸とか三角とかにしても境界線は Rect です。
var makeObstacle = function(data) { var minX = SCREEN_WIDTH, minY = SCREEN_HEIGHT, maxX = 0, maxY = 0; for (var i=0;i<data.length;) { var x = data[i++]; var y = data[i++]; i++; if (x<minX) { minX = x; } if (x>maxX) { maxX = x; } if (y<minY) { minY = y; } if (y>maxY) { maxY = y; } } var obstacle = { x: minX, y: minY, width: maxX - minX, height: maxY - minY } return obstacle; } var getObstacles = function(strokes) { while (strokes.length>0) { var stroke = backing.strokes.pop(); var data = stroke.data; obstacles.push(makeObstacle(data)); } }
だらだらと長いけど、ストロークの data から、x,yの最大最小値を取り出して rect を作って障害物にしています。
正直、ちゃんと避けてそれっぽくリーダーに向かって行くようにはできていません。
var dodge = function(index, center) { var b = boids[index]; if (crash(b)) { var life = Math.sqrt(b.vx*b.vx + b.vy*b.vy) * 2; particles.push(b.x,b.y,b.vx*-0.05,b.vy*-0.05,life); } while (crash(b)) { b.x -= b.vx; b.y -= b.vy; var dx = center.x - b.x; var dy = center.y - b.y; if (Math.abs(dx)>Math.abs(dy)) { b.y -= b.vy + Math.random()*b.vy; } else { b.x -= b.vx + Math.random()*b.vx; } } }
x,y軸の、リーダーに近い軸だけ乱数で適当に動いているだけです。
進行方向の左右にずらして移動を試みるとか考えてみたのだけど、計算が…ということで乱数で適当にお茶を濁しました。
あ、後はぶつかった場合にはパーティクル出してます。
というわけで、以上の修正で enchantMOON で障害物を描いて、軌跡を描いてボイドを飛ばして遊べるようになりました。
画面に障害物を描いて、最後に軌跡を1本描いたら準備完了です。
シールをタップするとボイドが軌跡に沿って障害物を避けながら(ぶつかりながら)飛びます。
障害物は何個でも描くことができます。
今回は前に「enchantMOONで簡易版ぷよぷよを遊べるようにしてみた」でお世話になったサイトのコードをまた使わせてもらいました。
このサイトのコード、JavaScript が良くわからない自分にもわかるように書かれているので、enchantMOON であれこれやって遊べるから非常に助かってます!
おかげでなんとなく JavaScript と HTML5 がわかってきたような気が…。
v.2.6.0 で enchantMOON がサクサク動くようになったら、もっと色々と遊んでみたいのだけど、さてどうだろう?