このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

Archives Details

【Unity x WebAssembly】UnityコンテンツをBlazorとFlutterでWebアプリとして扱う

Unity

2023.01.30

この記事は最終更新日から1年以上が経過しています。

どもです。

2年程前ですかね。

職場でガッツリBlazorを扱っていたのですが、パタッと触らなくなるとさすがにすっかり忘れちゃいますよねw

なんか、やっぱりBlazorというフレームワークは特殊で、普段のWeb開発での選択肢としてはあまり考えられないところもあって、扱う機会も多くはないです。

ですが、Blazorにも勿論メリットもあり、C#(.net)でWebアプリの開発が行えると言うことで、.NETやNugetパッケージなど、C#の資産がそのまま使用でき、Unityアプリとの親和性も高いと勝手に思っており(ただ言語が一緒なだけということもありますが)BlazorにUnityアプリを乗せれば、Unityエンジニアもweb開発を行うこともでき、Unity開発もweb開発もスムーズにいくのではないか?

と、思って2年前は触っていたのです。

そして、再び触る機会がありましたので、久しぶりにと触り出したのですが、

そのやり方を忘れたので(笑) メモ代わりに記事でも書くかと書いております。

あ。あけましておめでとうございます。

いやぁ。

気がつけば、2023年も1月が終わろうとしていて。

早いですね。日が経つのは。

という事で、

今回は、UnityアプリをBlazorとFlutterと2つのフレームワークを用いて、Webアプリの一部として作って行きたいと思います。

環境

  • Mac mini (M1, 2020)
  • macOS Big Sur 11.6
  • Unity 2019.3.13、2020.3.18f1
  • Visual Studio Community 2019 for Mac Version 8.10.25 (build 2)
  • .NET Core 3.1 SDK
  • .NET 5.0 SDK

Unity Build

まずは、オープンソースで公開されている「CubeWorld」を使用していきたいので、こちらをcloneします。

GitHub

https://github.com/federicodangelo/CubeWorld

CubeWorld」はマインクラフトのようなゲームのデモプロジェクトとなります。

まずは、こちらをUnityで起ち上げたいので起動しようとすると、何やらUnity 2019.3.13を使えよと警告が出たので、Unity 2019.3.13をインストールしました。

(後で分かったのですが、2020.3.18f1でも大丈夫でした。。)

Unity 2019.3.13

とりあえず、「Unity 2019.3.13」を使用。「Main」シーンを開いて Unity を再生。

再生すると、以下の様なメニューが表示されますので、「Create Random World」を選択。

続いて、「Generate」を選択。

すると、ワールドが展開され、「CubeWorld」を楽しむことができます。

今回は、web書き出しということなので、メニュー File>BuildSettingsを選択し、「Switch Platform」押下で、WebGLを選択します。

Build And Run」押下で、Chromeが立ち上がり、起動できるのが確認できました。

Buildフォルダ以下に生成された成果物を確認すると以下の様となりました。

あら、こんな、「unityweb」拡張子がついたファイルが生成されたっけ??

シンプルに以下の様なファイルだった気が。。

と、後で気がついたのですが、Unity2019.4までが、「unityweb」拡張子がついたファイルが生成され、

UnityLoader.instantiate(container, url, override)

のような形で、JSオブジェクトを扱うようで、Unity2020.1からは、「unityweb」拡張子がないシンプルなファイルが生成され、

createUnityInstance(canvas, config, onProgress).then(onSuccess).catch(onError);

のような形で、JSオブジェクトを扱うようでした。

なので、生成されたHTMLの記述も異なる。

Blazor WebAssembly

ということで、Blazorの方を扱っていきます。

Blazorは、.NET を使ってクライアント側 Web UI を構築するためのフレームワークであり、C# で SPA が作れるフレームワークであることが特徴です。

Blazor Serverなども構築することが可能ですが、今回はWebアプリの「Blazor WebAssembly」を使用していきます。

まずは、Visual Studioを起動し、「新規」を押下。

続いて、「Blazor WebAssembly アプリ」を選択。

次は、取り敢えずデフォルトのままで。

プロジェクト名は適当に「unityweb」と入力。

すると、Choromeが起動し、以下の様に「Blazor WebAssembly アプリ」が起動します。

あぁ。なんか、懐かしい感じ。

Unity側でBuildして生成された「Build」フォルダを「wwwroot」フォルダ以下に、そのまま追加します。

また、「TemplateDate」も必要でしたので、「wwwroot」フォルダ以下に追加します。

wwwroot」フォルダ以下のindex.htmlを修正。 以下の様に「UnityProgress.js」と「UnityLoader.js」を読み込み、UnityLoader.instantiateメソッドでインスタンスを生成します。
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
    var unityInstance = UnityLoader.instantiate("unityContainer", "Build/cube.json", {onProgress: UnityProgress});
</script>

実際には、Blazor側で使用できるように以下の様に、

今回、Unity 2019.3.13でビルドを行ったので、以下の様な記述となります。「window.jsFunctions」でwindowオブジェクトに定義し、「showUnity」と言った感じ関数追加します。

<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>window.jsFunctions = {
        showUnity: function () {
            var unityInstance = UnityLoader.instantiate("unityContainer", "Build/cube.json", { onProgress: UnityProgress });
        },
}</script>

表示させたいところに、id unityContainerの付与されたdivを配置します。

今回は、「Pages/index.razor」に追加。

index.razor

<div id="unityContainer" style="width: 100%; height: calc(100% - 10px);"></div>

JSを呼び出すため、「@inject IJSRuntime JSRuntime;」を追加。

index.razor

@page "/"
@inject IJSRuntime JSRuntime;

 

実際に呼び出す処理を「@code」内に記述。

index.razor

@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("jsFunctions.showUnity");

        }
    }

}

 

デフォルトのStyleだと、margin、paddingが適応されていますので、ちょっと修正。

app.css

.content {
    padding-top: 0;
    height: calc(100% - 56px);
}

div.main .content.px-0 {
    padding-left: 0 !important;
    padding-right: 0 !important;
}

新しく定義した、padding0を適応させるため、MainLayout.razorのCSS classを修正。

MainLayout.razor

<div class="content px-0">
     @Body
</div>

ここまで行えば、BlazorアプリにUnityコンテンツの表示が行えます。

比較的簡単で実装可能ですね。

ソースコードはこちらとなります。

GitHub

https://github.com/webcyou-org/unity-blazor

 

Flutter

続いて、みんな大好きFlutterでも同じ様にUnityコンテンツを表示させていきます。

(Flutterの概要、インストールに関しては割愛させていただきます。)

createコマンドで新しくプロジェクトを作成。

flutter create unityweb

今回はWeb書き出しとなるので、2を入力。

[1]: macOS (macos)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 2

すると、Flutterが用意してくれている、boot strap用の画面表示。

Flutterの起動確認取れましたので、Unityコンテンツを追加していきます。

こちらは、「Unity 2020.3.18f1」でのビルドでも何ら問題ななかったので、「Unity 2020.3.18f1」でビルドを行っていきます。

どうやら、Decompression fallbackを有効にした方がよさそうなので、

ProjectSettings -> Player -> WebGL -> Publishing Settings

にて、「Decompression fallback」にチェック入れ、有効化します。

Blazor同様にWebGLでビルドを行います。

Flutterでは、「web」フォルダ以下にUnityのビルド成果物を格納する形となります。

Blazor同様に、Unityビルドで生成された「Build」ディレクトリと「TemplateDate」ディレクトリと「index.html」を新たに作成した「unity」ディレクトリ以下に、そのまま追加します。

index.html」を少し修正します。

以下の2行を追加します。

window.parent.postMessage("unity_loaded", "*");
globalUnityInstance = unityInstance;

追加する箇所は、createUnityInstance関数実行後のthenの箇所となります。

script.onload = () => {
    createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
    })
    .then((unityInstance) => {
        // ここから

その他、以下の箇所など不要で、コメントアウトしても問題なく表示しましたので、コメントアウトしております。

<!-- <div id="unity-mobile-warning">
         WebGL builds are not supported on mobile devices.
     </div>
     <div id="unity-footer">
          <div id="unity-webgl-logo"></div>
          <div id="unity-fullscreen-button"></div>
          <div id="unity-build-title">CubeWorld</div>
     </div> -->

この辺りも。

// var fullscreenButton = document.querySelector(
//     "#unity-fullscreen-button"
// );
// var mobileWarning = document.querySelector("#unity-mobile-warning");

 

flutter_unity_widget_webパッケージを利用

FlutterでUnityコンテンツを扱えるように、「flutter_unity_widget_web」パッケージを追加します。

pub.dev

https://pub.dev/packages/flutter_unity_widget_web

以下のflutterコマンドで追加。

flutter pub add flutter_unity_widget_web

http周りも利用している様子で、依存パッケージは以下の様な形となりました。

+ crypto 3.0.2
+ flutter_unity_widget_web 1.0.1
+ http 0.13.5
+ http_parser 4.0.2
+ plugin_platform_interface 2.1.3
+ pointer_interceptor 0.9.3+3
+ typed_data 1.3.1
+ uuid 3.0.7
+ webview_flutter 2.8.0 (4.0.2 available)
+ webview_flutter_android 2.10.4 (3.2.1 available)
+ webview_flutter_platform_interface 1.9.5 (2.0.1 available)
+ webview_flutter_wkwebview 2.9.5 (3.0.2 available)
+ webviewx 0.2.1

 

pubspec.yamlにも追加されております。

dependencies:
  flutter_unity_widget_web: ^1.0.1

lib/main.dartファイル(使用する場所)で、flutter_unity_widget_webのimport文を記述。

lib/main.dart

import 'package:flutter_unity_widget_web/flutter_unity_widget_web.dart';

その他はflutter_unity_widget_webの公式ドキュメントを参考に、UnityWebWidget関数などを作成します。

今回は、Flutterのscaffoldにて生成されたmain.dartをそのまま利用したので、以下の様な形となります。

class _MyHomePageState extends State<MyHomePage> {
  late UnityWebController _unityWebController;

  @override
  Widget build(BuildContext context) {
    return UnityWebWidget(
      url: 'http://localhost:${Uri.base.port}/unity/index.html',
      listenMessageFromUnity: _listenMessageFromUnity,
      onUnityLoaded: _onUnityLoaded,
    );
  }

  @override
  void dispose() {
    _unityWebController.dispose();
    super.dispose();
  }

  void _listenMessageFromUnity(String data) {
    if (data == 'load_next_scene') {
      // any message emitted from unty.
      _unityWebController.sendDataToUnity(
        gameObject: 'GameWindow',
        method: 'LoadNextScene',
        data: '0', // data sent to unity from flutter web.
      );
    }
  }

  void _onUnityLoaded(UnityWebController controller) {
    _unityWebController = controller;
    setState(() {});
  }
}

その他は、githubのソースをご参照ください。

ここまでできれば、flutterをchromeベースで起動します。

flutter run -d chrome

Flutterも起動でき、Unityコンテンツも表示されました。

flutter_unity_widget_webパッケージは、html自体を読み込んでいる様子で、こちらのstyleなどが適応されていて、Unityのコンテンツも真ん中表示となりました。

TemplateDate」以下のCSSでstyleも定義されていますので、細かいところの調整は、そちらなどのCSSファイルの修正が発生しそうです。

#unity-container.unity-desktop {
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

と言った感じで、Flutterに関しても取り敢えず問題なく表示しました。

FlutterでのUnityコンテンツ表示のソースはこちらとなります。

GitHub

https://github.com/webcyou-org/unity-flutter

というわけで、BlazorとFlutterでUnity webGLを表示させてみました。

とりあえず、現状も変わらず表示してよかったです。

UnityとWeb側で連携させつつ。っていうのが今後も発生しそうなので、ぼちぼち扱っていきます。

ではでは。

またまたぁ。

Comment

Related Article

【Unity x WebAssembly】UnityコンテンツをBlazorとFlutterでWebアプリとして扱う

2023.01.30

CATEGORY LIST

LATEST NEWS

Mac VSCodeで、SFML C++開発環境を作る。

C++

2024.09.09

Rust-SDL2 examplesをすべて試す

Rust

2024.09.01

JavaScriptで、DOMを放り投げる処理

JavaScript

2024.07.27

Rustで創る MOS 6502 CPU その2

Rust

2024.07.23

Rustで創る MOS 6502 CPU その1

Rust

2024.07.19

汎用 3D mesh/model viewerを求め。と、簡単に、FBXファイルをglTF(glb)に変換ツールを求め。

C++

2024.06.06

M1 Macで、OpenGL GLUTを使ってコンパイルする

C

2024.04.27

Rust - Actix Web mongo ユーザー登録 JWT認証

Rust

2024.03.24

Rust - Actix Web JWT 認証認可 APIの作成

Rust

2024.02.25

Rust - Actix Web × JSON 静的ファイルをAPIで返却

Rust

2024.01.19

Rust - Actix Web × MongoDB環境をサクッと起動

Rust

2024.01.18

5分で学ぶ RustでWave Function Collapse (波動関数崩壊アルゴリズム)

Rust

2024.01.15

RANKING

Follow

SPONSOR

現在、掲載募集中です。



Links

About Us

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。

Entry Profile

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、主に、ゲーム制作中心に港区六本木界隈で活動中。

FOLLOW US