UnityのWebGL出力でHTMLのファイル選択ダイアログを表示して外部ファイルを読み込むのをやってみたので方法をメモしておく。
参考サイト
ここに載せた方法はほぼ以下のサイトそのまま。
How do I let the user load an image from their harddrive into a WebGL app? | Unity Community
HTML側からファイルを読み込む方法
type="file"のinput要素からファイルを読み込む。
- テンプレートに以下を追加する
<input file type="file" onchange='gameInstance.SendMessage("GameObject", "FileSelected", window.URL.createObjectURL(this.files[0]));' />
- GameObjectという名前のEmptyを作成し、以下のファイルを割り当てる
using UnityEngine;
using System.Collections;
public class ReadScript : MonoBehaviour {
IEnumerator LoadTexture (string url) {
WWW www = new WWW (url);
yield return www;
Debug.Log(www.bytes);
}
public void FileSelected (string url) {
StartCoroutine(LoadTexture (url));
}
}
WebGLテンプレートの設定
- [Unity - マニュアル: WebGL テンプレートの使用]
(https://docs.unity3d.com/ja/current/Manual/webgl-templates.html)
Custom WebGL Templates in Project Assets (do they actually work?) | Unity Community - Unity - Manual: Using WebGL Templates
デフォルトテンプレートは上記のサイトにあるように以下の場所にある(英語版のマニュアルの方にしかパスがなかったのでしばらくさがした)。
Both minimal and default templates can be found in the Unity installation folder under Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates on Windows or /PlaybackEngines/WebGLSupport/BuildTools/WebGLTemplates on Mac.
コルーチンについて
最初WWWクラスでコルーチンを利用していなかったらファイルを読み込めずにハマった。
以下にあるようにコルーチンを利用するとファイルを読み込んだ後に処理ができる。
参考サイト:【Unity】WWWクラスを利用して、JSONを読み込む | albatrus.com
uGUI上からファイルを読み込む方法
uGUIのボタンから読み込んでみる。
- Assets/Plugins/FileImporter.jslibを作成する
var FileImporterPlugin = {
FileImporterCaptureClick: function() {
if (!document.getElementById('FileImporter')) {
var fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('id', 'FileImporter');
fileInput.setAttribute('accept', '.json')
fileInput.style.visibility = 'hidden';
fileInput.onclick = function (event) {
this.value = null;
};
fileInput.onchange = function (event) {
SendMessage('ImportButton', 'FileSelected', URL.createObjectURL(event.target.files[0]));
}
document.body.appendChild(fileInput);
}
var OpenFileDialog = function() {
document.getElementById('FileImporter').click();
document.getElementById('#canvas').removeEventListener('click', OpenFileDialog);
};
document.getElementById('#canvas').addEventListener('click', OpenFileDialog, false);
}
};
mergeInto(LibraryManager.library, FileImporterPlugin);
- ImportButtonというボタンを作成する。
- ImportButtonに以下のスクリプトを割り当てる
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class ImportButton : MonoBehaviour {
[DllImport("__Internal")]
private static extern void FileImporterCaptureClick();
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnButtonPointerDown()
{
FileImporterCaptureClick();
}
public void FileSelected(string url)
{
StartCoroutine(LoadJson(url));
}
private IEnumerator LoadJson(string url)
{
WWW www = new WWW(url);
yield return www;
Debug.Log(www.bytes);
}
}
- ImportButtonにEventTrrigerコンポーネントを追加して、Pointer Downイベントに対してImportButton.OnButtonPointerDown()を割り当てる
制限
参考サイトにも書いてあるがマウスをボタン上で押したままcanvasから離れると反応しない。
その後再度canvas上をクリックするとダイアログが表示されてしまう。
Pluginでやっていること
最初はPluginを使わなくてもボタンを押したら外部javascriptと連携してinput要素をclick()すればいいんじゃないと考えていたが出来なかった。
display:noneで機能が無効化されているのかと思ったがそうではなかった。
参考サイト:[CSS] display:noneで機能が無効化されないようにする
原因は以下のようにユーザが起こしたクリックイベント中でのみinput要素のclick()を実行できるからだった。
参考サイト:<input type="file">のクリックイベントをコードから発行する作法
このため、PluginではUnityのUI上でボタンがダウンされた時にcanvasにマウスアップ時に反応するクリックイベントを設定しそこを起点にclick()を実行している。