PIXI.jsでモバイル対応とFPSの変更

Log

リサイズ、FPS調整、座標取得についての備忘録。
バージョンはv6.0.4

PCブラウザとスマホブラウザに同時に対応するゲームを作るためのやつ。
FPS周りは人によっては必要ないかも。

全然詳しいわけじゃないので、参考程度に。

リサイズ


PCブラウザ上ではブラウザサイズに合わせて画面をリサイズします。
スマホでも同じようなものですが、こちらは回転への対応が必要です。

公式ページでscaleToWindowというものが紹介されているのでそれを使います。
英語です。

GitHub - kittykatattack/scaleToWindow: A function to scale an HTML canvas element to the maximum browser window
A function to scale an HTML canvas element to the maximum browser window - kittykatattack/scaleToWindow

説明通りに書いていけばとりあえず対応できます。
スマホの回転についてはイベントリスナーで”orientationchange”を加えればいけます。

windowwindow.addEventListener("orientationchange", function(event){ 
  scaleToWindow(anyelementElement);
});

FPS


自分の場合、全体のfpsを15、AnimatedSpriteのfpsを7~8くらいにする必要がありました。
以下のツイートが完成図です。

すべてのアニメーションの始動を同期させる必要があります。
なので、基本的にAnimationSpriteの持つ“onFrameChange”“onLoop”を使ってアニメーションを切り替えていきます。

以下、この前提で進めていきます。

AnimatedSpriteのAnimationSpeed


まずこれが厄介です。

PIXI.jsのアニメーションスプライトは、各々が持つ_currentTimeを割った余りによってcurrentFrame(表示するフレーム)を決定しています。
_currentTimeの方はAnimationSpeedとラグによって決定します。
ラグで途中のアニメが抜けても困るので、deltaTimeが関わるものは事前に消しておきます。(pixi.min.js 42867行辺り)
15fpsの中で7~8fpsで動いてほしいので、AnimationSpeedは0.5で設定しておきます。

これで上手くいけばいいのですが、そうはいきません。
currentFrameが最終的にMath.floor()で小数点を切り捨てているからです。

AnimationSpeedは0.5ですが、なんやかんやあって(詳しくない)ぴったり0.5を足してくれるわけじゃないからです。
大体3フレーム辺りで微妙に下回り、1フレームの誤差が生じてしまいます。

なのでMath.floor()の前にMath.round()を追加していい感じに四捨五入します。(PIXI.min.js 43038行辺り)

また、めちゃめちゃな力業ですが、当時頭のおかしかった私のように、AnimationSpeedを設定することでも回避できます。

sprite.animationSpeed = 0.50000000000001;

ちなみに、フレームにズレが発生するまで3,857万日です。
適当にパパッと回答だけ見てる人、上のコードは参考にせず、ちょっと上に戻ってください。

TickerのmaxFPS


maxFPSはTickerの設定です。
maxFPSは雑に言うと、maxFPSの値を超えたら追加されたupdateを実行するというものです。

maxFPSはAnimationSpriteに(基本的には)影響しないので
「maxFPSを変更してもAnimationSpeedを変更しなくていい!」
という恩恵があるのですが、アニメーションの同期に敏感な場合、その恩恵は不要です。
ということで、ここでもアニメーションのズレが生じます。

onLoopなどのタイミングがズレます。
内部的には_currentFrameは変更されているものの、updateが実行されないのでonLoopが観測されません。
その結果、本来のタイミングから少し遅れてonLoopやonFrameChangeが実行されてしまいます。
この場合、始動だけは合いますが、その後がめちゃくちゃです。

解法としてはupdate()内でAnimatedSpriteを更新するというものです。

AnimatedSprite内部の_currentTimeなどは“Pixi.Ticker.shared”
自分で作ったupdate()関数などはチュートリアル通りにやっていれば“PIXI.Application.ticker”
というふうに、Tickerという名前ですが管轄が違います。

maxFPSはApplication.tickerの方の設定です。
ということで、手順は以下

Ticker.sharedのautoStartを切る。
Application.tickerのmaxFPSを設定。
update()内にTicker.shared.update()を記入。

app.ticker.maxFPS = 15;
PIXI.Ticker.shared.autoStart = false;
PIXI.Ticker.shared.update();

適切な場所に書いてください。
多分これでFPSの設定は大丈夫なはずです。

逆再生について


逆再生から始動したい場合、gotoAndPlay(sprite.totalFrames – 1)なんかにするとズレます。
Math.floor()を使っているので1フレーム後には次のコマになってしまうからです。

必要に応じて+0.5などする必要があります。

座標取得


主にスマホ側に合わせて作っていきます。
また、scaleToWindowも関わってきます。

必要なのは
リサイズの倍率、ポインターの座標、ピクセル比、マージン

ピクセル比という奴さえわかれば楽勝です。

リサイズの倍率


scakeToWindowのものをそのまま取ってきます。

let canvas = app.renderer.view;
let scaleX = document.documentElement.clientWidth / canvas.offsetWidth;
let scaleY = document.documentElement.clientHeight / canvas.offsetHeight;
let scale = Math.min(scaleX, scaleY);

ポインターの座標


イベントリスナーでclientX, clientYを取ります。
ポインターは「マウスでもタップでもペンタブでもいいよ!」という便利なやつです。

app.renderer.view.addEventListener("pointermove", pointerMove);

function pointerMove(event) {
    let pointerX = event.clientX;
    let pointerY = event.clientY;
}

ピクセル比


まずピクセル比ってなんだよって話ですが、ブラウザをそのままスマホに持ってきたときに文字が小さすぎるのを避けるためのものっぽいです。
だいたい2くらいに設定されており、普通にブラウザのサイズを取ろうとすると想定される数値の半分くらいで出てきます。

以下のように取得します。

let pixelRatio = window.devicePixelRatio;

マージン


scaleToWindowのものをそのまま取ってきます。

let marginLeft = parseInt(canvas.style.marginLeft);
let marginTop = parseInt(canvas.style.marginTop);

最終


全部合体させます。


app.renderer.view.addEventListener("pointermove", pointerMove);

function pointerMove(event) {
    let canvas = app.renderer.view;
    let scaleX = document.documentElement.clientWidth / canvas.offsetWidth;
    let scaleY = document.documentElement.clientHeight / canvas.offsetHeight;
    let scale = Math.min(scaleX, scaleY);

    let pointerX = event.clientX;
    let pointerY = event.clientY;

    let pixelRatio = window.devicePixelRatio;

    let marginLeft = parseInt(canvas.style.marginLeft);
    let marginTop = parseInt(canvas.style.marginTop);

    Point = new PIXI.Point(
        (pointerX - marginLeft) * pixelRatio / scale,
        (pointerY - marginTop) * pixelRatio / scale);
}

終わり


恐らくこれでいけるはずです。
FPS周りは調べながら行ったり来たりしていたので、もっと楽な方法があるかもしれません。

コメント

  1. […] PIXI.jsでモバイル対応とFPSの変更 […]

タイトルとURLをコピーしました