「MonoGameで外部のXNBファイルを読み込む」の版間の差分

提供: MonoBook
ナビゲーションに移動 検索に移動
(ページの作成:「MonoGameで作っているゲームに起動時データ更新を実装し、プログラム以外の画像や音楽などだけであれば自動更新する...」)
 
61行目: 61行目:
 
             }
 
             }
  
            // This is primarily for editor support.
 
            // Setting the RootDirectory to an absolute path is useful in editor
 
            // situations, but TitleContainer can ONLY be passed relative paths.               
 
 
             stream = File.OpenRead(path);                 
 
             stream = File.OpenRead(path);                 
  

2016年1月14日 (木) 05:46時点における版

MonoGameで作っているゲームに起動時データ更新を実装し、プログラム以外の画像や音楽などだけであれば自動更新するようにしたいわけだ。 むしろプログラムの細かい部分もNLuaに投げるようにしてしまいたい。

そうなると外部から各種データを読み込む必要が出てくる。 しかしMonoGameで扱う各種データの基本はプログラムに組み込まれた「Content」である。

Xamarin.Android

MonoGameのContentManagerクラスのソースコードをざっと見た感じ、Xamarin.Androidではアセット以外のファイルへはアクセスできないようだ。 ContentManagerクラスのソースコードをみると幸いにもvirtualやらがチラホラ見受けられ継承してoverrideする前提の構造になっている。 なので細かいことは考えずにoverrideしてしまえ。

ついでに各種パラメータを保存したcsvjsonなどのxnb以外のファイルも同様の手順で読み込めるように、xnbパーサを経由しない裏口も用意すると捗った。 個人的な主な用途としては、OpenGL ESバーテックスシェーダーは書き込みだけで読み出せないため、モデルとは別に頂点データのcsvファイルを読み込み、それを当たり判定に用いている。

using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

public class ExternalContentManager : Microsoft.Xna.Framework.Content.ContentManager
{
    public ExternalContentManager(IServiceProvider serviceProvider, string rootDirectory)
        : base(serviceProvider, rootDirectory)
    {
    }

    public ExternalContentManager(IServiceProvider serviceProvider)
        : base(serviceProvider)
    {
    }

    protected override Stream OpenStream(string assetName)
    {
        string assetPath;
        if (Path.GetExtension(assetName) != "xnb")
        {
            assetPath = assetName + ".xnb";
        }
        else
        {
            assetPath = assetName;
        }
        return OpenRead(assetPath);
    }

    public Stream OpenRead(string fileName)
    {
        Stream stream = null;
        string path;

        try
        {
            if (Path.IsPathRooted(fileName))
            {
                path = fileName;
            }
            else
            {
                path = Path.Combine(RootDirectory, fileName);
            }

            stream = File.OpenRead(path);                

            // Read the asset into memory in one go. This results in a ~50% reduction
            // in load times on Android due to slow Android asset streams.
            var memStream = new MemoryStream();
            stream.CopyTo(memStream);
            memStream.Seek(0, SeekOrigin.Begin);
            stream.Close();
            stream = memStream;
        }
        catch (FileNotFoundException fileNotFound)
        {
            throw new ContentLoadException("The content file was not found.", fileNotFound);
        }
        catch (DirectoryNotFoundException directoryNotFound)
        {
            throw new ContentLoadException("The directory was not found.", directoryNotFound);
        }
        catch (Exception exception)
        {
            throw new ContentLoadException("Opening stream error.", exception);
        }
        return stream;
    }
}

使い方は普通のContentManagerと大して変わらない。

// Androidであれば「/data/data/アプリID/files」あたりが返ってくるはず。
var path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var cm = new ExternalContentManager(this.Content.ServiceProvider, path);
var font = cm.Load<SpriteFont>("IPA-Gothic");

関連項目