enchant.js ゲーム制作 Tips – キーボードでプレイヤーを移動させてみよう!! 斜め移動にも対応してるよん♪

phiary に引っ越しました. 毎日プログラミングやWebに関する情報を発信しています! RSS 登録してたまに覗いたり, tweet やハテブして拡散してもらえると幸いです.

Pocket

以前書いた『enchant.js ゲーム制作 Tips – マウスクリックやタッチでプレイヤーを移動させてみよう!!』に引き続き enchant.js についてのエントリーです.

キーボードでプレイヤーを移動させるサンプルを作成しました. 斜め移動も考慮した実装になっているので enchant.js に限らずゲームを作る際の参考にしてみてください.

Sample And Data

今回制作したサンプルです.

キーボードの十字キーを押すとプレイヤーが移動します.

Sample 00 では上下左右移動と時と斜め移動した時とで, 移動速度が違ってしまっています. Sample 01 は斜めでも一定速度で移動するように, そして Sample 02 では処理を高速化した例になっています.

Download はこちらからできます.

Code

今回のテストプログラム, Sample 02 全体のコードです. ビット演算やルックアップテーブルなどを活用してます.

<!DOCTYPE html>

<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
        <title>Sample 02 - ビット演算子とルックアップテーブルを使って高速化しよう!!</title>
        <style>
            * {
                margin: 0px;
                padding: 0px;
            }
        </style>
        <script charset="UTF-8" src="enchant.js"></script>
        <script charset="UTF-8" src="dummysprite.enchant.js"></script>
        <script charset="UTF-8">
            // 使いやすくするおまじない
            enchant();
            
            // 十字キーを角度に変換するルックアップテーブル
            var ARROW_TO_ANGLE_TABLE = {
                // 上下左右
                0x0001: 270,    // 下
                0x0002:   0,    // 右
                0x0004:  90,    // 上
                0x0008: 180,    // 左
                // 斜め
                0x0006:  45,    // 右上
                0x0003: 315,    // 右下
                0x000c: 135,    // 左上
                0x0009: 225,    // 左下
                // 三方向同時押し対応
                // 想定外の操作だが対応しといたほうが無難
                0x000e:  90,    // 右上左
                0x000d: 180,    // 上左下
                0x000b: 270,    // 左下右
                0x0007:   0,    // 下右上
            };
            
            // 移動速度
            var SPEED = 4;
            
            // 初期化時処理
            window.onload = function() {
                // Game インスタンスを生成
                var game = new Game(320, 320);
                // 初期化
                game.onload = function() {
                    // 背景色を設定
                    this.rootScene.backgroundColor = "black";
                    // ダミースプライトを生成
                    var dummySprite = new DummySprite(20, 20, "red");
                    dummySprite.moveTo(160-10, 160-10);
                    this.rootScene.addChild(dummySprite);
                    // 更新イベントを登録
                    this.rootScene.addEventListener("enterframe", function(e){
                        var input = game.input;
                        
                        // 角度で移動させる
                        var arrowBit = (input.left << 3) | (input.up << 2) | (input.right << 1) | (input.down << 0);
                        var angle = ARROW_TO_ANGLE_TABLE&#91; arrowBit &#93;;
                        if (angle !== undefined) {
                            var vx = Math.cos(angle*Math.PI/180) * SPEED;
                            var vy =-Math.sin(angle*Math.PI/180) * SPEED;
                            dummySprite.moveBy(vx, vy);
                        }
                    });
                };
                // 開始
                game.start();
            };
        </script>
    </head>
    <body>
        <h1>Sample 02 - ビット演算子とルックアップテーブルを使って高速化しよう!!</h1>
    </body>
</html>

Tips

Sample 00 - Arrow キーの押した方向に単純に移動!!

enchant.js では Game インスタンスが持っている input の left, right, up, down で 十字キーを押しているかどうかをチェックすることができます.

var input = game.input;
if (input.left  === true) dummySprite.x -= 4;
if (input.right === true) dummySprite.x += 4;
if (input.up    === true) dummySprite.y -= 4;
if (input.down  === true) dummySprite.y += 4;

Sample 00 では上下左右に移動した際と斜めに移動した際とで下の画像のように移動距離に差がでてしまいます.

今回の例では上下左右では 4 しか動きませんが斜め移動の場合 4√2 動いてしまいます. この対策は Sample 01 で行なっています.

Sample 01 - 斜め移動を考慮した移動に修正しよう!!

十字キーの押している方向を角度に置き換えて, sin, cos を使って移動させています.

// 移動速度
var SPEED = 4;
var input = game.input;

// 角度で移動させる
var angle = null;
if      (input.right && input.up)   { angle = 45; }
else if (input.left  && input.up)   { angle =135; }
else if (input.left  && input.down) { angle =225; }
else if (input.right && input.down) { angle =315; }
else if (input.right)   { angle =  0; }
else if (input.up)      { angle = 90; }
else if (input.left)    { angle =180; }
else if (input.down)    { angle =270; }

if (angle !== null) {
    var vx = Math.cos(angle*Math.PI/180) * SPEED;
    var vy =-Math.sin(angle*Math.PI/180) * SPEED;   // y軸は下が正なので符号を反転させる
    dummySprite.moveBy(vx, vy);
}

この方法であればどの方向でも一定距離を移動させることができます.

Sample 02 - ビット演算子とルックアップテーブルを使って高速化しよう!!

まず, left, up, right, down それぞれに 4, 3, 2, 1 ビットを割り当てて一つの数値に変換します. そしてその数値をキーとして対応したルックアップテーブルを使い角度に変換しています.

// 十字キーを角度に変換するルックアップテーブル
var ARROW_TO_ANGLE_TABLE = {
    // 上下左右
    0x0001: 270,    // 下
    0x0002:   0,    // 右
    0x0004:  90,    // 上
    0x0008: 180,    // 左
    // 斜め
    0x0006:  45,    // 右上
    0x0003: 315,    // 右下
    0x000c: 135,    // 左上
    0x0009: 225,    // 左下
    // 三方向同時押し対応
    // 想定外の操作だが対応しといたほうが無難
    0x000e:  90,    // 右上左
    0x000d: 180,    // 上左下
    0x000b: 270,    // 左下右
    0x0007:   0,    // 下右上
};

// 移動速度
var SPEED = 4;
var input = game.input;

// 角度で移動させる
var arrowBit = (input.left << 3) | (input.up << 2) | (input.right << 1) | (input.down << 0);
var angle = ARROW_TO_ANGLE_TABLE[ arrowBit ];
if (angle !== undefined) {
    var vx = Math.cos(angle*Math.PI/180) * SPEED;
    var vy =-Math.sin(angle*Math.PI/180) * SPEED;
    dummySprite.moveBy(vx, vy);
}
[/code]

今回のように毎フレーム1回しか通らない処理の場合あまり効果を発揮しませんが, 衝突判定やシンプルな分岐処理ではビット演算を使って判定を少なくしたり switch をルックアップテーブルに置き換えることで かなり高速化できることがあります.

私は, コードをわかりにくくまでして高速化する必要はない(実仕事ではそうはいきませんが...)と考えていますが, 今回のサンプルではコードの見た目もスッキリするので採用してみました.

次回は, 衝突判定について書こうかな. Chrome が Sound 関係安定してくれれば今すぐにでもそっちを書きたいんだけどなぁ.

TRACK BACK URL

POST COMMENT

メールアドレスが公開されることはありません。

COMMENT