はじめに
これはJavaScript用のゲームライブラリPhaser3を使って、ちょっとしたゲームをWebで公開する人向けの記事です。
実装の目的
「こんなゲーム思いついたんだけど、もし良かったら遊んでみて!」なんてときに、Webページとしてゲーム作品が公開できるのは気軽でとても良いのですが、ゲーム画面が横長だとiPhoneなどのスマホ画面では上下の余白が大き過ぎてしまうのが気になりました。
Chromeの開発者ツールで、iPhoneでの表示を試すとこんな感じ。
プレイヤーにスマホ画面の自動回転の設定を変えてもらったりしても良いのですが、ひと手間かかってしまいます。
そこで、余計な手間無しで気軽にゲームをプレイしてもらうために、ディスプレイが縦に長いときはゲーム画面を90度回転させてしまうことで画面に収めるというレスポンシブ対応をします!
実装について
環境
以下の環境でコーディングと動作確認を行いました。
- 言語 JavaScript
- ライブラリ Phaser3.87.0
- ビルド
- yarn 1.22
- Vite 5.4
レスポンシブ対応をしてないときのコード例
まず、例として背景と2つのキャラクターをPhaserのScene内で表示するコードです。
これを後でレスポンシブ対応します。
// 背景画像
let board = this.add.image(0, 0, 'board')
board.setPosition(board.width / 2, board.height / 2)
let cardB = this.add.image(400, 200, 'card_b')
let cardA = this.add.image(400, 360, 'card_a')
これを、下のような変更で90度クルッと回します!
// ここで画面回転のためのContainerをつくる
// 背景画像
let board = this.add.image(0, 0, 'board')
board.setPosition(board.width / 2, board.height / 2)
// boardをContainerに追加
let cardB = this.add.image(400, 200, 'card_b')
// cardBをContainerに追加
let cardA = this.add.image(400, 360, 'card_a')
// cardAをContainerに追加
/*
以降で画面の向きに合わせてContainerを90度回転させる
回転させたら、ゲームのキャンバスの縦横比も合わせる(game.scale.resize(x,y))
*/
実際のコードについて
実際のコードの全体はGithubリポジトリのmain.jsを参照してください。
main.js : https://github.com/kysaeed/pxy/blob/main/main.js
個々の処理の説明
最初に回転用のContainerを作っています。
// 回転用の親コンテナ すべての表示要素をこのコンテナにいれる
this.anchor = this.add.container(0, 0)
// 背景画像
let board = this.add.image(0, 0, 'board')
board.setPosition(board.width / 2, board.height / 2)
this.anchor.add(board)
ゲーム画面を回転させる関数です。
isRotate
がtrue
なら横幅(width)と高さ(height)を逆転させる
(false
の場合は回転の必要がないので、縦横はそのまま)
const setRotateState = (isRotate) => {
if (isRotate) {
// [|] 縦長スクリーンに表示
game.scale.displaySize.setAspectRatio( Constants.Screen.Height/Constants.Screen.Width );
game.scale.resize(Constants.Screen.Height, Constants.Screen.Width)
this.anchor.angle = 90
this.anchor.x = Constants.Screen.Height
game.scale.refresh()
} else {
// [--] 横長スクリーンに表示
game.scale.displaySize.setAspectRatio( Constants.Screen.Width/Constants.Screen.Height );
game.scale.resize(Constants.Screen.Width, Constants.Screen.Height)
this.anchor.x = 0
this.anchor.angle = 0
game.scale.refresh()
}
}
縦画面か横画面かの判定をしています。
画面が横に長く使えさえすればOKなので、厳密なチェックはせずゲーム表示の親要素の縦横どっちが長いかで判定してしまいます。
const isVertical = () => {
const game = window.game
const w = game.scale.parentSize.width
const h = game.scale.parentSize.height
let isVertical = false
if (w && h) {
if (w < h) {
isVertical = true
}
}
return isVertical
}
あとは、100ms以上リサイズされなくなるまで待って回転処理をします。
const fit = () => {
/*
// PCの場合は、ディレプレイの持ち方を変えないので回転しない
if (game.device.os.desktop) {
return
}
*/
setRotateState(isVertical())
}
let h
const onResize = () => {
if (h) {
clearTimeout(h)
}
h = setTimeout(() => {
fit()
}, 100)
}
動作確認してみる
Chromeの開発者ツールで動作確認してみます。
レスポンシブ表示の確認表示で縦長のとき、うまく画面に収まりました
もともとスクリーンが横長で、回転がいらない場合はそのまま表示されます。
実機でも動作確認
実機でも確認できるようにDEMOページを公開しました。
最後に
この方法は、文字の入力などが不要で画面のタッチ/クリックが多めのゲームに向いていると考えてます。
逆に、ゲーム表示を回転させているだけなのでDOM要素やソフトウェアキーボードを使いたい場合は向きません。
また物理エンジンを使っている場合も向かないので、ゲーム中は回転させずタイトル画面だけで画面方向を判定するなどにしか使えなそうです。