1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Phaser3で作ったゲームを地動説でレスポンシブ対応

Posted at

はじめに

これはJavaScript用のゲームライブラリPhaser3を使って、ちょっとしたゲームをWebで公開する人向けの記事です。

実装の目的

「こんなゲーム思いついたんだけど、もし良かったら遊んでみて!」なんてときに、Webページとしてゲーム作品が公開できるのは気軽でとても良いのですが、ゲーム画面が横長だとiPhoneなどのスマホ画面では上下の余白が大き過ぎてしまうのが気になりました。

Chromeの開発者ツールで、iPhoneでの表示を試すとこんな感じ。

スクリーンショット 2024-11-23 18.06.51.png

プレイヤーにスマホ画面の自動回転の設定を変えてもらったりしても良いのですが、ひと手間かかってしまいます。

そこで、余計な手間無しで気軽にゲームをプレイしてもらうために、ディスプレイが縦に長いときはゲーム画面を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)    

ゲーム画面を回転させる関数です。
isRotatetrueなら横幅(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の開発者ツールで動作確認してみます。
レスポンシブ表示の確認表示で縦長のとき、うまく画面に収まりました:v:

スクリーンショット 2024-11-23 17.50.51.png

もともとスクリーンが横長で、回転がいらない場合はそのまま表示されます。

スクリーンショット 2024-11-23 17.50.45.png

実機でも動作確認

実機でも確認できるようにDEMOページを公開しました。

FIT!
IMG_0096.jpeg

最後に

この方法は、文字の入力などが不要で画面のタッチ/クリックが多めのゲームに向いていると考えてます。

逆に、ゲーム表示を回転させているだけなのでDOM要素やソフトウェアキーボードを使いたい場合は向きません。
また物理エンジンを使っている場合も向かないので、ゲーム中は回転させずタイトル画面だけで画面方向を判定するなどにしか使えなそうです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?