【レスポンシブ】WordPressにUnityをWebGlで公開する手順

Unity

先日、WordPressで動作する当サイトにポートフォリオの意味を込めて昔作ったUnityゲームを公開しました。その際、思いのほか手ごたえのある作業になりまして、満足のいくポートフォリオになりましたのでその手順を共有したいと思います。

ゲーム自体PC専用のくせしてレスポンシブ対応するという謎のこだわりがあり、アスペクト比をくずさずにウィンドウのリサイズが可能です。

ただ、あくまで私の環境での手順を公開するだけなので、全員の環境に適合するかどうかは保証できないものとします。ご了承ください。

以下がそのポートフォリオページです。BGMが再生されるのでご注意ください。

動作環境

Unity2018.4.3f1
WordPress5.6
Nginx1.17.7

当サイトは、VPSにDockerを走らせて運営しております。また、WebサーバにNginxを用いています。

公開手順

1. UnityプロジェクトをWebGL形式でビルド

今回は、WebGL形式でビルドする詳しい手順などは割愛します。一応、公式のマニュアルを載せておきます。

WebGL プロジェクトのビルドと実行 - Unity マニュアル
WebGL プロジェクトを ビルド すると、以下のファイルを含むフォルダーが Unity 内に作成されます。

ここで第一の壁、WebGL形式だけビルドが失敗する。しかも、ビルド終了後のコンソールにはSucceededの文字が出力されているからなお厄介です。teratailで同じ課題を持った人がいて助かりました。

unityで作ったゲームをWEBGLにビルドできない。
unityでゲームを作りました。これをWEBGLにビルドしたくて、ネットでいろいろと調べてビルドしてみたのですが、下のようなエラーメッセージがでます。でもコンソールにはBuild completed

どうやらUnityプロジェクトやビルドファイルの保存先のパス内に日本語が含まれているとNGみたい。Unityプロジェクトが~/Onedrive/デスクトップの中にありました、、、解決。

2. index.htmlをローカル環境で表示

ビルドに成功すると、/Build, /TemplateData, index.htmlが生成されます。とりあえず、index.htmlをローカルでサーバを経由せず表示。何も表示されず。デベロッパーツールからコンソールを確認すると、CORSエラーが。Windowsだとローカル表示でも動くって情報見たんだけどな。。仕方なく、npmのhttp-serverで簡易サーバたてて対処しました。

きました、表示されました。….ですが、何かがおかしい。一部のテキストが表示されていません。

表示されていないのは、どれも日本語のテキストばかりでした。

【Unity】WebGLで日本語テキストが表示されない問題について
UnityのWebGLで日本語テキストが表示されない問題の解決方法を記載します。 Unityエディタ上では日本語テキストが正常に表示されているのに、WebGLでビルドして確認すると表示されない。 私自身調べた内容を忘れそうなので備忘録に残したいと思います。

上記の記事によりますと、使用していたフォントが日本語対応していないArialだったため、こんなことが起きているようです。Unityエディタ上ではフォントフォールバック機能というものが働いているため、デバッグ時には気づけませんでした。

日本語テキストのフォントをArialからGoogleが提供している再配布可能なフォントの「Noto Sans JP」フォントに変更しました。

これでindex.htmlをローカル環境で表示することができたので、次は本番サーバに配置して本番環境で動作確認します。

3. index.htmlを本番環境で表示

ここでは、index.htmlの中身を変えずに本番環境で表示ができるかやってみます。Nginx設定ファイルをいじって、<FQDN>/static/で静的ファイルを配信できるよう設定します。以下にdefault.confの追記コードを示します。

location /static {
    alias /var/www/static;
}

これで本番サーバの/var/www/static配下のファイルを配信することが可能になりました。それでは、先ほどビルドした/Build, /TemplateData, index.htmlを/var/www/static配下に配置します。当サーバは、VPSを借りて運用しているのでSSHで通信するため、SCPを用います。

コマンドでももちろんいいですが、SSHクライアントのTeratermで秘密鍵等管理しているのでTeratermのSCP機能から素早く転送してしまいます。ディレクトリは転送できないのでzip形式に、また転送先のディレクトリの書き込みを許可しないと怒られるのでchmodしておきましょう(転送後は必ずもとに戻しましょう!)。

TeraTermでファイルの送受信(SCP)
TeraTermでファイルを送受信する方法 SSHクライアントであるTeraTermにはSCP使用してサーバとファイルの送受信を行う機能があります。 今回はその機能を使用してファイルを転送する方法を説明します。(とっても簡単です) この機能

転送後、zipを解凍して/var/www/static配下に/Build, /TemplateData, index.htmlを展開します。

<FQDN>/static/index.htmlにアクセスして、見事ローカル環境同様に表示がされれば成功です。(以下は当サイトproative.netのstatic/fox-run/index.htmlにアクセスした例ですが、URL構造が説明と違うのは気にしないでください)

4. iframeを使って記事に埋め込む

WebGLの公開はこれで完了したので、あとはポートフォリオページに綺麗に表示するだけとなります。

WordPressの投稿、または固定ページを新規作成します。そして任意のHTMLコードを挿入できる「カスタムHTML」ウィジェットを選択し、以下のコードを貼り付けます(【】の部分はそれぞれ変更してください)。

<iframe src="【先ほど配置したindex.htmlのURI】" width="【任意のwidthピクセル値】" height="【任意のheightピクセル値】" scrolling="no" frameborder="0"></iframe>

WordPressにおいてWebGLの公開方法は多数存在するみたいですが、今回はiframeを用いることとします。

HTML のインラインフレーム要素 (<iframe>) は、入れ子になった閲覧コンテキストを表現し、現在の HTML ページに他のページを埋め込むことができます。

iframeのwidth, heightプロパティはゲームのアスペクト比に合わせて調整してください。さて、これでWordPressにUnityのWebGLを公開することができるようになったわけですが、現状ではレスポンシブデザインに対応しておりません。確かにPCゲームでモバイルのアクセスは想定していないかもしれませんが、PCにてウィンドウをリサイズした時にゲームの表示が崩れてしまうと思います。それがどうしても気になってしまったのでレスポンシブ対応してやりました。

【番外編】5. レスポンシブ対応

紆余曲折

ここではレスポンシブ対応に至るまでの紆余曲折を書いていくので、早く正常に動作する結果が欲しい人は本章は飛ばしてください。

最初は、投稿のカスタムCSSにstyleを記述してiframe内にレンダリングされるゲームスクリーンのwidth・heightを動的に変更しようと試みました。

しかし、以下の記事にある通りCORS関係でiframe内の要素どもをstyle変更することは並みの方法じゃいかないようです。

そこで、iframe内にレンダリングされるゲームスクリーンにclassを付与するスクリプトを投稿のカスタムJavaScriptに記述する作戦に変更しました。iframe要素にはcontentWindowというプロパティによりiframe内に展開されるhtmlのwindowオブジェクトが提供されます。そこからゲームスクリーンにあたる要素に対しclassList.addしてclassを付与しstyleを適用する作戦です。

iframe要素.contentWindow

ただ、これも失敗に終わります。

これは、iframe内のゲームスクリーンのレンダリングが非同期で行われているため、起動直後に実行されるスクリプトではゲームスクリーンにあたる要素がルックアップできないためです。wordPress内で記述できるカスタムJavaScriptではレンダリング完了を検知することはできず。。

本当はやりたくありませんでしたが、Unityのビルド後に生成されるindex.htmlを修正してレスポンシブ対応を実現します。

実現手法

以下に修正前のindex.htmlを示します。

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | Run Game</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
    <script src="TemplateData/UnityProgress.js"></script>
    <script src="Build/UnityLoader.js"></script>
    <script>
      var gameInstance = UnityLoader.instantiate("gameContainer", "Build/fox-run-webgl2.json", {onProgress: UnityProgress});
    </script>
  </head>
  <body>
    <div class="webgl-content">
      <div id="gameContainer" style="width: 960px; height: 600px"></div>
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
        <div class="title">FOX-RUN</div>
      </div>
    </div>
  </body>
</html>

仕組みとしては、#gameContainerの要素内にゲームスクリーンにあたるcanvasタグが非同期でレンダリングされます。

これを以下のように修正します。

<!DOCTYPE html>
<html lang="en-us">

<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Unity WebGL Player | Run Game</title>
  <link rel="shortcut icon" href="TemplateData/favicon.ico">
  <link rel="stylesheet" href="TemplateData/style.css">
  <script src="TemplateData/UnityProgress.js"></script>
  <script src="Build/UnityLoader.js"></script>
  <script>
    var gameInstance = UnityLoader.instantiate("gameContainer", "Build/fox-run-webgl.json", { onProgress: UnityProgress });
  </script>

  <style>
    .webgl-container {
      margin: 0;
      padding: 0;
      position: relative;
      width: 100%;
    }

    .webgl-container::before {
      content: "";
      display: block;
      padding-top: 56.25%; /* 高さを幅の56.25%に固定(16:9の場合) */
    }

    #gameContainer {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
    }

    canvas {
      width: 100%;
      height: 100%;
    }

    .webgl-content {
      position: absolute;
      top: 100%;
      left: 0;
      bottom: 0;
      right: 0;
      transform: none !important;
    }

    .empty-block {
      width: 100%;
      height: calc(38px + 5px);
    }
  </style>
</head>

<body>
  <div class="webgl-container">
    <div id="gameContainer"></div>
    <div class="webgl-content">
      <div class="footer">
        <div class="webgl-logo"></div>
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
        <div class="title">FOX-RUN</div>
      </div>
    </div>
  </div>
  <div class="empty-block"></div>
</body>

</html>

28行目は、Unityプロジェクトのアスペクト比に依存します。本プロジェクトは16:9なため、9/16=0.5625で56.25%になっています。この法則の元、修正してみてください。

index.htmlはUnityのバージョンに依存しますので、本バージョン以外での動作保証はできかねます。

修正したindex.htmlを「3. index.htmlを本番環境で表示」を参考にアップロードしなおします。

さらに、WordPressのポートフォリオページのiframeタグも以下のように修正します。”webgl-iframe”というidを追加し、widthやheightを固定せず親要素いっぱいに広げます。

<iframe id="webgl-iframe" src="【先ほど配置したindex.htmlのURI】" scrolling="no" frameborder="0" style="width: 100%"></iframe>

このままではiframe内のゲームスクリーンの適切なheightがわからないため、ゲームスクリーンが見切れてしまうと思います。そこでWordPressの投稿内のカスタムJavaScriptに以下のスクリプトを記述します。

const webglIframe = document.getElementById("webgl-iframe");
const changeIframeHeight = () => {
  $("#webgl-iframe").height(webglIframe.contentWindow.document.body.offsetHeight + 10);
}

$(document).ready(function () {
  $("#webgl-iframe").load(function () {
    if (typeof $(this).attr("height") == "undefined") {
      changeIframeHeight();
      window.addEventListener("resize", changeIframeHeight, false);
    }
  });
  $("#webgl-iframe").triggerHandler("load");
});

これでロード時とリサイズ時に、iframeタグ内のbodyのheightをiframeタグのheightに適用することができます。

お疲れさまでした!以上がWordPressでアスペクト比をくずさずにウィンドウのリサイズが可能なUnityのWebGL公開手順でした。

コメント