前回は、EaselJSについてご紹介しました。
今回は、uniSwfに使用する素材の外部化についてご紹介します。
uniSwfとは、Flashで作成したタイムラインアニメーション(以下、flashアニメ)をUnityで扱うためのアセットでStageやDisplayObjectクラス・addChild関数等、ActionScriptの基本的なものが用意されています。
しかし、扱うといってもswfファイルを直接使用することは出来ず、付属しているコンバーターを使用してUnityで扱えるファイル形式に変換する必要があります。
bytes形式のファイルと、png形式のテクスチャが作成され、uniSwfアセットで用意されているコンポーネントを使用して、GameObjectとして画面に表示させることが出来ます。
インストールやファイルの変換方法は他サイトでも紹介されているため、ここでは割愛します。
uniSwfを利用する場合、大体はMovieClipBehaviourというコンポーネントを使用すると思いますが
uniSwfには、外部に置いているswfファイルでflashアニメを表示するため、WWWMovieClipという専用のクラスが用意されています。
使用方法はとても簡単で、コンストラクタにswf素材のurlと、flashアニメを作成した際の設定したシンボル名を渡すだけで、あとは自動的にmeshやrenderの設定を内部で行ってくれる大変便利なものです。
公式サイトでは、WWWMovieClipを使用する場合は、swf変換の際にテクスチャをbytesファイルに埋め込む必要があると記載があります。
この設定を行うことによって、テクスチャデータ自体がbytsファイルに含まれ、変換後に作成されるファイルが bytesファイル一つだけになります。
テクスチャデータが埋め込まれたbytesファイルのurlをWWWMovieClipに渡すことで外部サーバーにあるswfを使用して表示することが出来ます。
サーバー上に置いてある素材を使用してflashアニメを表示することはできますが、表示するたびに外部サーバーへアクセスしていては通信回数が多くなってしまいます。
そのため、サーバーから取得した素材を内部に保存し、その保存したファイルを使用してflashアニメの表示を行うことにします。
■外部サーバーからファイルを取得して、端末内部に保存するサンプル
private IEnumerator GetAssets() { WWW www = new WWW("http://localhost/sample.swf.bytes"); while (!www.isDone) { yield return null; } string saveDir = Application.persistentDataPath + "/" + "sample.swf"; string savePath = saveDir + "/" + "sample.swf.bytes"; if (!System.IO.File.Exists(saveDir)) { Directory.CreateDirectory(saveDir); } System.IO.File.WriteAllBytes(savePath, www.bytes); }
uniSwfのルールとして、下記の構成にしなければいけないため、ディレクトリの有無を判断してなければ作成するようにしています。
——————————–
ファイル名.swf (←フォルダ)
└ファイル名.swf.bytes
——————————–
皆さんご存知かと思いますが、Unityで用意されているWWWクラスは、fileプロトコルでurlを記述することで内部のファイルを取得することもできます。
WWWMovieClipもfileプロトコルを使用したurlを指定することが可能なため、内部に保存したファイルを使用する場合は下記のように指定することが出来ます。
string saveDir = Application.persistentDataPath + "/" + "sample.swf"; //保存したbytesファイルではなく、ファイル名.swfフォルダを指定する必要があります //uniSwfでは、フォルダ名をprefixとして、.bytesファイルを決定し、フォルダ直下の対象bytesファイルを参照します WWWMovieClip wwwmc = new WWWMovieClip(saveDir, "symbolName");
WWWMovieClipはMonoBehaviourを継承したクラスではないため、表示させるにはuniSwfで用意されているDisplayObjectを継承したインスタンスにaddChildする必要があります。
今回は、MovieClipBehaviourクラスが保持しているmovieClipインスタンスにaddChildする形を使用します。
//あらかじめ配置しておいた、MovieClipBehaviourをアタッチしたGameObject GameObject mcObj = GameObject.Find("WWWMovieClipContainer"); MovieClipBehaviour mc = mcObj.GetComponent<MovieClipBehaviour>(); //MovieClipBehaviourがもつmovieClipに貼り付け mc.movieClip.addChild(wwwmc);
上記で外部サーバーに置いているswfを使用したflashアニメの表示は終了です。
ただ、表示自体は行うことが出来たのですが、1つだけ問題が発生しました。
UnityEditorのInspectorで設定したMovieClipBehaviourのオブジェクトと見比べると
なぜか、WWWMovieClipで表示したもののほうがぼやけた感じになっていて
各設定項目を見比べたところ、meshRenderに設定されている画像自体がぼけてしまっていました。
bytesファイルの埋め込みデータから画像を生成する処理はuniSwfで用意されているスクリプト側で行っているため、画像生成自体を修正することは不可能であったため
いろいろ試行錯誤した結果、Embed設定は使用せずに、通常通りにswf変換を行ったファイルを使用することで解決しました。
やりかたはとても単純で、bytesファイルと同様にテクスチャファイルもサーバーから取得し、通常変換時に作成される構成通りに保存だけです。
公式サイトに埋め込みにする必要があると記載されているのに、テクスチャファイルを置くだけで綺麗に表示されたのは少し不思議でしたが、無事に外部素材でflashアニメを表示させることが出来たので、結果オーライとします。
今回ご紹介した他にも、AssetBundleを併用することで実現することも可能だとは思います。
まだ試してはいませんが、機会があればまた記事を書いてご紹介いたします。
最後までご覧いただき有難うございました。
using UnityEngine; using System.Collections; using System.IO; using pumpkin.display; using pumpkin.events; public class WorkScene : MonoBehaviour { public void Start() { StartCoroutine(GetAssets()); } private IEnumerator GetAssets() { //サーバーからbytesファイルを取得して保存 WWW www = new WWW("http://localhost/sample.swf/sample.swf.bytes"); while (!www.isDone) { yield return null; } string saveDir = Application.persistentDataPath + "/" + "sample.swf"; if (!System.IO.File.Exists(saveDir)) { Directory.CreateDirectory(saveDir); } System.IO.File.WriteAllBytes(saveDir + "/" + "sample.swf.bytes", www.bytes); //サーバーからテクスチャを取得して保存 WWW www = new WWW("http://localhost/sample.swf/sample.swf_Tex0.bytes"); while (!www.isDone) { yield return null; } System.IO.File.WriteAllBytes(saveDir + "/" + "sample.swf_Tex0.bytes", www.bytes); //空のMovieClipBehaviourがアタッチされたGameObjectを取得 GameObject mcObj = GameObject.Find("WWWMovieClipContainer"); MovieClipBehaviour mc = mcObj.GetComponent<MovieClipBehaviour>(); WWWMovieClip wwwmc = new WWWMovieClip("file:///" + saveDir, "sample"); wwwmc.addEventListener(ErrorEvent.COMPLETE, delegate (CEvent e) { //読み込み成功時処理 }); wwwmc.addEventListener(ErrorEvent.ERROR, delegate (CEvent e) { Debug.Log("failed: " + e.toEvent<ErrorEvent>().error); }); //MovieClipBehaviourがもつmovieClipに貼り付け mc.movieClip.addChild(wwwmc); } }
弊社では全国各地の請負い(ご自宅)で作業協力頂ける、フリーランスエンジニアの方を常時探しております。
ご興味ある方は、お気軽にお問い合わせ下さい。