園児ニアのメモ

ただのエンジニア。何でも屋みたいな扱い受けてます。

enchant.jsの表示位置を動的にするとズレるバグがあるので修正した

enchant.jsでサクッと作れるということだったが動的な動きなどには対応していなかったので対応しました。
いろいろ制限することで初心者でも使いやすいということなのでenchant.jsが悪いわけじゃないですが…

事象説明

まず、なぜ動的に対応していないと気付いたかというところから話すと
1.enchant-stageをHTMLに記入する方法で実装した。(enchant-stageに関してはこちらを参考にしました:enchant.jsで自動的に画面が拡大されるのを抑制するには?)
2.enchant-stageが常に画面中央に出るようにJsで実装
 中央寄せを行う関数を作成

//センタリングを実行する関数
function centeringStage() {
    //画面(ウィンドウ)の幅、高さを取得
    var w = window.innerWidth;
    var h = window.innerHeight;
    var scale_h = h/game_.height*0.9;//外側に10%余白をつけたかったので0.9かけた
    var scale_w = w/game_.width*0.9;
    if(scale_w < scale_h){ //画面比率が小さい方に合わせ、Gameのscaleを変える
        game_.scale = scale_w;
    }else{
        game_.scale = scale_h;
    }
    var leftMargin = (w-game_.width*game_.scale)/2;
    var topMargin = (h-game_.height*game_.scale)/2;
    $("#enchant-stage").css({"left":leftMargin + "px","top":topMargin + "px"}); //#enchant-stageを上下中央にする
}

上の関数を呼ぶように実装

    //Game生成後に画面を合わせる
    centeringStage();
    //ブラウザがリサイズされたら、センタリングをする関数[centeringStage()]を実行する
    $(window).resize(centeringStage);

3.中央寄せになったもののタップしても反応しない,またはタップ位置がズレてしまう…
enchant.js内部でGameを初期化した時にenchant-stageの位置を記憶しているらしい
Game生成後にenchant-stageの座標を動かすとその分ズレてしまうみたい?
 (同じ現象の記事:enchant-stage につまづいた)

やったこと

最初はenchant.jsの中身を書き換えようとしたが結構複雑?あとアップデートのたびにやるのはめんどうで諦めた....
解決案としてはタッチイベント部分は自作にした。(enchant.jsにこだわる理由もないのだがpixi.jsや他のがiOS8.0に非対応だったり時間もなかったので…)

以下の変数,定数を宣言

var mouse_x = -9999999; //x座標
var mouse_y = -9999999; //y座標
var TOUCH = {
    NONE  : 0,
    START : 1,
    MOVE  : 2,
    END   : 3,
};
var TOUCH_EVENT = TOUCH.NONE; //現在のタッチ状況

以下でマウス座標とタッチを取得(PCだとタッチ非対応なのでmousedownなどの実装必要あり)
また、キーボード入力も今回使わなかったので未対応

// イベントリスナーに対応している
if(document.addEventListener){
    //enchant-stage内でのマウスポインタの位置をこのように取得
    window.addEventListener("mousemove", function(e){
        if(e){
            mouse_x = (e.pageX-stage.getBoundingClientRect().left-window.pageXOffset)/game_.scale;
            mouse_y = (e.pageY-stage.getBoundingClientRect().top-window.pageYOffset)/game_.scale;
        }else{
            mouse_x = -9999999; //取得失敗は画面外にいることにする
            mouse_y = -9999999;
        }
    });
            
    //タッチに対応している
    if(window.TouchEvent){
        //タッチを開始すると実行されるイベント
        document.addEventListener("touchstart",function(e){
            TOUCH_EVENT = TOUCH.START;
        });
                
        //タッチしたまま平行移動すると実行されるイベント
        document.addEventListener("touchmove",function(e){
            TOUCH_EVENT = TOUCH.MOVE;
        });
                
        //タッチを終了すると実行されるイベント
        document.addEventListener("touchend",function(e){
            TOUCH_EVENT = TOUCH.END;
        });
    }
}

座標と押しているかどうかは取得できたのでenchant.jsのGame内で使う
実際使うときはscene.onenterframeではなくokButton.onenterframeなど各タップ範囲ごとに監視したほうが作りやすいです。

scene.onenterframe = function(){
    if(this.x < mouse_x && mouse_x < this.x+this.width && this.y < mouse_y && mouse_y < this.y+this.height){
        //タッチ範囲内
        document.body.style.cursor = "pointer";
        this.backgroundColor = 'rgba(255, 255, 255, 0.7)';
        if(TOUCH_EVENT == TOUCH.START){
            //タッチ開始
            
        } else if(TOUCH_EVENT == TOUCH.MOVE) {
            //タッチ中
            
        } else {
            //タッチ終了
            
        }
    }else{
        //タッチ範囲外
        document.body.style.cursor = "default";
        this.backgroundColor = 'rgba(255, 255, 255, 0.5)';
    }
}

まとめ

マウスの位置、タップ状況を保存して各EntityやSprite,Labelなどで監視。
マウスの位置はGameの座標と合わせているので比較することでホバー処理なども可能になった。