【enchant.js】Hello Physical World vol.7【box2d】

アレですよ。そろそろBox2Dの記事でも書きましょうよ。
――と、誰に言われたというわけではないんですが、お久しぶりの【Hello Physical World】でございます。
vol.5でSpriteに加える力は3種類あると説明しました。今回は3つのうちの最後、applyTorque について説明します。

Torque(トルク)とは何か。例によってWikipediaをのぞいてみ――たら不必要に頭が混乱しそうなのでポチッと戻るボタンを押しました。ようは物体を回転させる力のことですね*1

リファレンスには以下のようにあります。

applyTorque(torque)
継続的な回転力を与える

Parameters:
{Number} torque
    加える回転力 

もうちょっと解説がほしいところですね。この関数、加えるトグルを正の値にすると右回転、負の値にすると左回転となります。
そこを踏まえてサンプルを組んでみました。

はい。最後にボール同士がぶつかって跳ねますね?
次回はそこのところ、衝突判定のcontactを扱いましょう。

*1:正しくは物体を回転させる「力のモーメント」だそうですが、「モーメントって何」という体たらくなので勘弁して下さい。

【enchant.js】正弦波の書き方【やっぱり関係ない】

前回は円を扱いましたので、今回は正弦波を描画してみましょう。
正弦波ってどんな図形かというと、『あずまんが大王』のOPの1:10あたりでやってる動きですw

冗談はさておき、正弦波の描く図形は「波」です。
これがなぜ円と関係してくるのでしょうか。
円を描く時のy軸に注目して下さい。
y軸の動きは、まず下方向へと動き、下限に達すると上方向の動きとなります。そしてまた上限に達すると下方向の動きへと転じ、最後に元いた座標に戻ります。
さて、ここでx軸の動きをプラス方向へと限定してみましょう。x軸の本当の動きは、y軸と同じで上限・下限の行ったり来たりですが、これを一方向へと限定することで波の図形を描くことが出来るようになるのです。
そんなこんなで、今回のコードぉおおお!

重要な部分をピックアップしてみましょう。

        var width = 320;
        var swing = 50; // 振り幅
        var cycle = width / 3; // 周期
        var velocity = (Math.PI * 2) / cycle; // 角速度

width は正弦波を描く横の長さです。こいつを160としたら、画面の中ほどまでしか波が描画されません。
swing はy軸の上限下限の振り幅ですね。これを160としたら、画面の上下いっぱいの波を描きます。
cycle は周期です。上のコードでは、width の中に3つの周期を描くとしています。
velocity は角速度です。時間(x軸の位置)によって描画角度がどう変わるかを表したものです。角速度のお蔭で線がギザギザにならず、きれいな曲線を描いてくれるんですね。

        ctx.translate(0,160);
        for (var i = 0; i < width; i++) {
            var x0 = i;
            var y0 = swing * Math.sin(velocity*x0) * -1; // -1で符号反転
            var x1 = i + 1;
            var y1 = swing * Math.sin(velocity*x1) * -1; // -1で符号反転
            ctx.beginPath();
            ctx.moveTo(x0,y0);
            ctx.lineTo(x1,y1);
            ctx.stroke();
        }

まず translate で描画の原点を変更します。
あとはx軸がiの座標とi+1の座標を求めつないでいくだけです。

さて、やっぱりこうきたらアニメーションもさせてみましょう。

今回も同様、width いっぱいに図形を描画しても処理を止めてませんので延々と波を描き続けます。
Spriteの幅をもっと大きく取って、正弦波が半ばまで描かれたらSpriteを左にスライドさせていくって処理も面白いと思います。
では!

【enchant.js】arcを使わない円の書き方【あんまり関係ない】

ここ最近、すっかりプログラミング熱が冷めております。
じゃあプログラミングに向けられていた熱がどこ行ったのかというと、今はお絵かきの方に向けられています。
最近はA・ルーミスという方が書かれた教本をチラチラと見ているのですが、これがまた面白い!
単純な図形――主に円――をいくつか組み合わせ人の顔を描き出す工程は実に見事で、そしてそれを真似るとあら不思議! 自分でも描けるんですね。これは本当に楽しい!
絵を描く練習をしたいという方にはすごくオススメです。

さて。
円といえば前々回の記事で描きましたよね。
この時、円形そのものはarc関数を用いて描きましたが、ちょっと趣向を変えてlineToを使って描いてみましょう。

はい。0度から360度まで線をつなげて描画です。
ポイントは、i が0の時だけ moveTo を呼ぶってところでしょうか。パッと確認したところ、すべて lineTo でもきちんと円を描画できましたが、座標(0,0)から描画が始まるって可能性もあり得ると思いますので、きちんと処理しておきましょう。
ではこれの応用。
今度は円を描画するアニメーションを作ってみましょう。

for 文の中身を onenterframe に移した格好ですね。
1回1回、onenterframe の中で描写が完結してますので begintPath → moveTo → lineTo → stroke という流れを忘れずに。あと、前回描画したところの座標も記憶しておく必要がありますね(その都度計算で求めてもいいけど)。
そうそう。このコードは円の描画が終わっても onenterframe を止めていないので、延々と円を描き続けます。

――お後がよろしいようで。

【enchant.js】MOON Challenge!【9leap】

久々に9DaysChallengeが開催されましたね。
その名もMOON Challenge
7月に発売されたUEIのタブレット『enchantMOON』にちなんだ9Daysです。
それも2回!
もちろん、私も参加しました!

MOON Challenge #1
9leap : マルっと! by v416 - どこでも遊べる、投稿型ゲームサイト
9leap : 水着だよ! by v416 - どこでも遊べる、投稿型ゲームサイト

MOON Challenge #2
9leap : グルっと! by v416 - どこでも遊べる、投稿型ゲームサイト
9leap : 斬! by v416 - どこでも遊べる、投稿型ゲームサイト

よかったら遊んでみてくださいね!

【enchant.js】円を区切る方法【canvas】

みなさま、お久しぶりでございます。
もはや月に1回の更新があるかどうかというへなちょこブログの更新であります。
8月はコミケに9daysが2回と、ついでに言うと仕事の方でもリリースがあったりとイベント盛りだくさんの月でした。
「だから更新できなくてもしかたがないよねー」というのはただの怠慢でしかなく、かと言ってbox2dのことについてあれこれ書く気力もなく――といったところに面白いネタが飛び込んできました。
こちらの記事です。
materialize.jp » ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【ホロスコープ(Horoscope)篇】 黄道十二宮(Zodiac)を描く

黄道十二宮を描く! 中々に面白い記事ですよね。
惜しむらくは、この方法だと応用が効きにくいということです。
宮の数が倍の24個になったら? 48個になったら?
これらをすべて事前に計算し定数を用意しておくのは、コードが長くなりすぎて良いとはいえないと思います。
そんなわけで、for文で回して描画してみましょう。

ひとつめ。
描画座標を計算する方法です。

for (var i = 0; i < 12; i++) {
    // 外円座標を計算
    var s = 150 * Math.cos(rad*i) + 160;
    var c = 150 * Math.sin(rad*i) + 160;
    ctx.moveTo(s, c);
    // 内円座標を計算
    s = 120 * Math.cos(rad*i) + 160;
    c = 120 * Math.sin(rad*i) + 160;
    ctx.lineTo(s, c);
}

まぁスタンダードですね。

もひとつ。
こちらは描画するキャンバス自身を回転させる方法です。

ctx.save();
for (var i = 0; i < 12; i++) {
    //画像の軸を中心に変更
    ctx.translate(160,160);
    //回転
    ctx.rotate(rad);
    //軸を元に戻す
    ctx.translate(-160,-160);
    //パスの描画
    ctx.moveTo(160,40);
    ctx.lineTo(160,10);
}
ctx.restore();

ソースの全体はこちらです。


人様のふんどしだけでお茶を濁すのもアレですし、最後にひとつ。
こんな風に時計も作れたりします。

【enchant.js】Hello Physical World vol.6【box2d】

もう7月終りだよ! ということで久々のブログ更新であります。
ここのところ、仕事とコミケの同時進行でニッチもサッチも行かなくなっていましたが、ようやっと落ち着いて来ました。……たぶん。

さてさて。6回めを数える「Hello Physical World」では、applyForce について取り上げたいと思います。
前回が applyImpulse だったので、流れ的にも「applyForce だな~」と思っていたのですが、ここ最近「applyForce」での検索結果でアクセスしてくる人も多いようだったので、box2d.enchant.js だけじゃなく、本家 box2dweb の方もいぢってみました。

さて。恒例のリファレンス確認です。

applyForce(force)
継続的な力を加える

Parameters:
{b2Vec2} force
    加える力のベクトル 

継続的な力を加える――つまり、force で与えられたベクトルをオブジェクトに加え続けるということですね。サンプルプログラムを組んでみましょう。

applyImpulse との違いはこんな感じです。

同じ力を加えているのに、何故 applyForce と applyImpulse は初動が違うのでしょうか。先日入手した「Box2Dで始める物理シミュレーション入門 ~JavaScript編~*1にその答えが載っていました。

……物体が持っている移動速度や角速度は、「Step」関数でのシミュレーション内で、物体同士の衝突や重力などの影響を考慮した上での合力となり、物体の移動速度に影響を与えます。その一方で物体に対する衝撃は、物体同士の衝突や重力などの影響を考慮する前に、移動速度に作用します。

つまり、applyForce は重力や摩擦、対象となるオブジェクトの重量などを考慮した結果が反映されるのに対し、applyImpulse は純粋に与えられたベクトルだけが考慮されるということですね。

さて。
ここでひとつ舵を切って、box2dweb の方に視線を向けてみましょう。
box2d.enchant.js のラップ元である box2dweb にも、当然 applyForce と applyImpulse が存在します*2。しかしながら、applyForce の挙動が box2d.enchant.js のそれと違うのです! ちょっとサンプルを見てみましょう。

お分かりでしょうか。box2d.enchant.js の applyForce とは異なり、オブジェクトが加速してゆくようなことはありません。applyImpulse と同様、力が加えられるのは一瞬で、あとは重力など他の力に引きづられます。
なぜ挙動が違うのか。正直、まったくわかりません。box2d.enchant.js の中を読んでみると、単に applyForce を叩いているだけなんですけどねぇ……。

*1:値段(4500円!)と情報量(128ページ!)を考えると、はっきり言ってまったくオススメできない本ですw

*2:正しくは「ApplyForce」と「ApplyImpulse」です。

【enchant.js】Hello Physical World vol.5【box2d】

「Hello Physical World」第5回目。今回は Sprite に加える applyImpulse を取り上げます。
box2d.enchant.js には Sprite に力を加える関数が3つ用意されています。
継続的な力を加える applyForce、継続的な回転力を与える applyTorque、そして今回取り上げる applyImpulse は Sprite に瞬間的な力を加えます。
それではリファレンスを確認しましょう。

applyImpulse(impulse)
瞬間的な力を加える

Parameters:
{b2Vec2} impulse
    加える力のベクトル

加える力のベクトルが引数として必要ですね。
b2Vec2 は Box2D で扱うベクトルです。

var vecter = new b2Vec2(0, -1);

という感じで求めます。第一引数は x 軸に加える力、第二引数は y 軸に加える力です。
それでは実際にコードを書いてみましょう。

画面をタップすると、ボールが下から上に等速運動で飛んでゆくのがわかると思います。
b2Vec2 に与える第一引数に、1 を入れてみて下さい。

var vecter = new b2Vec2(1, -1);

今度は右上に等速運動で飛んでいきますね。-1 を入れたら右下に向かって飛んで行きます。

ところでこのコード、重力を設定していません。重力を設定したらどうなるでしょうか。

world = new PhysicsWorld(0.0, 9.8);

おっと! リンゴがどんどん落ちていきますね。ここは落ち着いてタップ! タップ!! タップ!!!
これだけでも十分なゲームになりますね。

では、せっかくなのでちょっとしたゲームを作ってみましょう。

リンゴをゲーム画面から出さずに、向かってくるドクロを避け続けるゲームです。
作りこめば、もっと面白いものができると思いますよ。