また面白い 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 がサクサク動くようになったら、もっと色々と遊んでみたいのだけど、さてどうだろう?