UnityでStreamingAssetsに置いたLive2Dモデルを動的ロードさせる処理がAndroidでは失敗する件

スポンサーリンク
Live2D
スポンサーリンク
↑管理人が個人でUnity+Live2Dで作成しているスマホゲームです

前回の記事では、UnityでLive2Dモデルをスクリプトから動的にロードする方法について紹介しましたが、なぜかAndroid実機で確認するとモデルの読み込みが失敗してしまいます。monitor.batでログを確認すると「DirectoryNoFoundException: Counld not find a part of the path “/jar:file:/data/app/***-***/base.apk!/assets/***.***”」というようなエラーが出てしまっています。
調べてみると、どうやらAndroidでは特殊なファイル格納を行っているらしく、ファイルを参照する為にApplication.StreemingAssetsPathだけでは駄目なのだそう。

スポンサーリンク

何だか色々なやり方があるらしい

調べて見た所、
WWWクラスを使ってアクセスする方法その① 参照

  private HogeXmlData GetSerializedXmlHoge(string path)
    {
        var streamingPath= System.IO.Path.Combine(Application.streamingAssetsPath, path)
        HogeXmlData hoge = null;

#if UNITY_ANDROID && !UNITY_EDITOR
        //wwwを使用する方法
        WWW www = new WWW(streamingPath);
        while (!www.isDone) { }
        using (var sr = new StringReader(www.text))
        {
            hoge = (HogeXmlData) serializer.Deserialize(sr);
        }       
#else 
        //通常のファイルアクセス
        using (var fs = File.OpenRead(streamingPath))
        {
            hoge = (HogeXmlData) serializer.Deserialize(fs);
        }
#endif
        return hoge ;
    }

WWWクラスを使う方法② 参照

             string filePath = Application.streamingAssetsPath + "/Items.json";
             string jsonString;
             
             if (Application.platform == RuntimePlatform.Android)
             {
                 WWW reader = new WWW(filePath);
                 while (!reader.isDone) { }
     
                 jsonString = reader.text;
             }
             else
             {
                 jsonString = File.ReadAllText(filePath);
             }
     
             JsonData itemData = JsonMapper.ToObject(jsonString);

WWWクラスを使う方法③ 参照

    void Start () {
        StartCoroutine(GetPng ());
    } 

    public IEnumerator GetPng() {
        // URLを指定してダウンロード
        WWW wwwTexture = new WWW ("http://www.test/sample.png");

        // ダウンロード完了まで待つ
        while (!wwwTexture.isDone) {
            yield return null;
        }

        // uGUIのテクスチャに設定
        RawImage img = gameObject.GetComponent<RawImage>();
        img.texture = wwwTexture.texture;

    } 

WWWクラスを使う方法④ 参照

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile");
    public string result = "";
    IEnumerator Example() {
        if (filePath.Contains("://")) {
            WWW www = new WWW(filePath);
            yield return www;
            result = www.text;
        } else
            result = System.IO.File.ReadAllText(filePath);
    }
}

UnityWebRequestを使ったやり方 参照

private IEnumerator AndroidMoviePath(){
   string filePath = "";
   string moviePath = "";
   filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "ファイル名");

   if(filePath.Contains("://"){
      var www = UnityWebRequest.Get(filePath);
      yield return www.SendWebRequest();
      moviePath = www.downloadHandler.text;
   }else{
      moviePath = System.IO.File.ReadAllText(filePath);
   }
}

Application.PersistentDataPathにコピーする?方法 参照

string FilePath;
#if UNITY_IPHONE
  FilePath = Application.dataPath + "/Raw/" + filename;
#else
  string fullPath = "jar:file://" + Application.dataPath + "/!/assets/" + filename;
  WWW www = new WWW (fullPath);
    while (!www.isDone) {
  }
  FilePath = Application.persistentDataPath + filename;
  File.WriteAllBytes (toPath,www.bytes);
#endif

など色々なやり方が出てきます。

困った事

WWWクラスを使ったやり方が多く出てきますし、Unity公式でもWWWを使ったサンプルを置いてますが、WWWクラスは現在非推奨らしいです。
しかし、現在推奨されるUnityWebRequest でのやり方はコルーチンを使ったやり方しか書かれておらず、その辺あまり詳しくないので(Live2Dのライブラリ内の読み込み部分で勝手にStartCoroutine()やると変な事になりそう)WWWクラスを使う事にしました。

どういう実装にしたか

こちらの記事で紹介したBuiltinLoadAssetAtPath()を以下のようにいじりました。

    public object BuiltinLoadAssetAtPath(Type assetType, string absolutePath)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        

        if (assetType == typeof(byte[]))
        {
            WWW reader = new WWW(absolutePath);
            while (!reader.isDone) { }
            return reader.bytes;
        }
        else if (assetType == typeof(string))
        {
            WWW reader = new WWW(absolutePath);
            while (!reader.isDone) { }
            return reader.text;
        }
        else if (assetType == typeof(Texture2D))
        {
            var texture = new Texture2D(1, 1);
            WWW reader = new WWW(absolutePath.Replace(defaultCostume, nowCostume));
            while (!reader.isDone) { }
            texture.LoadImage(reader.bytes);

            return texture;
        }
#else 
        if (assetType == typeof(byte[]))
        {
            return File.ReadAllBytes(absolutePath);
        }
        else if (assetType == typeof(string))
        {
            return File.ReadAllText(absolutePath);
        }
        else if (assetType == typeof(Texture2D))
        {
            var texture = new Texture2D(1, 1);
            texture.LoadImage(File.ReadAllBytes(absolutePath.Replace(defaultCostume, nowCostume)));

            return texture;
        }
#endif




        throw new NotSupportedException();
    }

WWWクラスなんて使った事も無かったのですが、Fileクラスを使っているサンプルの方で使われてたReadAllBytes(),ReadAllText()に対応してそうなbytesプロパティとtextプロパティがあったので、それを使ってみると無事にAndroid実機で動きました!

注意点

最初テクスチャ読み込みの部分でwhile(!reader.isDone)を書き忘れていたのですが、この場合読み込み失敗したテクスチャは

f:id:sugar_affordance:20161026111630p:plain

のようになります。結果、

モデルがこういう悲惨な事になります。モデルが紅白模様になってしまった場合はテクスチャ読み込み完了をちゃんと待っているか確認しましょう。

1 Star2 Stars3 Stars4 Stars5 Stars (まだ投票されていません)
読み込み中...

コメント

広告ブロッカーを無効にしてください。

タイトルとURLをコピーしました