0

少人数のグループでゲーム プロジェクトに取り組んでいますが、これで問題は解決しました。このゲームの機能の 1 つは、ユーザーがゲーム内エディターを使用して独自のレベルを生成できることです。エディターは、レベルの長さと幅を格納する Level オブジェクトと、Tile オブジェクトの 2 次元配列を作成します。カメラ システムの実装に成功し、簡単なコンセプト レベルを一緒に編集することはそれほど難しくありませんが、レベルを正常に保存し、後でそれを再度ロードするプロセスは、難しいことが証明されているコンセプトです。意図した機能を停止するためのガイダンスを提供します。

現在の状態で、ユーザーが「S」キーを押すと、LevelManager クラスは以下の SaveLevel メソッドを実行します。

    public static void SaveLevel()
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;

        using (XmlWriter writer = XmlWriter.Create("example.xml", settings))
        {
            IntermediateSerializer.Serialize(writer, CurrentLevel, null);
        }
    }

これにより、レベル (CurrentLevel) がプロジェクト内の XML ファイルにシリアル化されます (この基本的なセットアップが機能するようになった後、別のファイルに保存することについて心配します)。プログラムを実行し、小さなマップを作成して保存しました。出力は次のとおりです。結果の XML ファイルで:

    <?xml version="1.0" encoding="utf-8"?>
    <XnaContent>
      <Asset Type="LevelEditorPrototype.Level">
        <TileGrid>
          <Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>0</X>
              <Y>0</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileBlock">
              <X>0</X>
              <Y>32</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FF0000FF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileVoid">
              <X>0</X>
              <Y>64</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFF0000</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>0</X>
              <Y>96</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
          </Item>
          <Item>
            <Item Type="LevelEditorPrototype.TileVoid">
              <X>32</X>
              <Y>0</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFF0000</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>32</X>
              <Y>32</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileBlock">
              <X>32</X>
              <Y>64</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FF0000FF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileVoid">
              <X>32</X>
              <Y>96</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFF0000</Tint>
            </Item>
          </Item>
          <Item>
            <Item Type="LevelEditorPrototype.TileBlock">
              <X>64</X>
              <Y>0</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FF0000FF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileVoid">
              <X>64</X>
              <Y>32</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFF0000</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>64</X>
              <Y>64</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileBlock">
              <X>64</X>
              <Y>96</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FF0000FF</Tint>
            </Item>
          </Item>
          <Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>96</X>
              <Y>0</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileBlock">
              <X>96</X>
              <Y>32</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FF0000FF</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileVoid">
              <X>96</X>
              <Y>64</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFF0000</Tint>
            </Item>
            <Item Type="LevelEditorPrototype.TileFloor">
              <X>96</X>
              <Y>96</Y>
              <Width>32</Width>
              <Height>32</Height>
              <Origin>0 0</Origin>
              <Depth>0</Depth>
              <Tint>FFFFFFFF</Tint>
            </Item>
          </Item>
        </TileGrid>
      </Asset>
    </XnaContent>

少なくとも、レベルで生成されたタイルに関するデータ情報を持っているので、それで問題ありません。ユーザーが実行時にも保存されたレベルをロードできるようにしたいので、「L」キーをマッピングして、保存された XML ファイルをロードすると、問題が発生します。私たちの読み取りは次のようになります。

    public static void LoadLevel()
    {
        using (FileStream stream = new FileStream("example.xml", FileMode.Open))
        {
            using (XmlReader reader = XmlReader.Create(stream))
            {

                currentLevel = IntermediateSerializer.Deserialize<Level>(reader, null);
            }
        }
    }

その機能をテストしようとすると、次のエラーが発生します。

    System.MethodAccessException was unhandled
      HResult=-2146233072
      Message=Attempt by method 'DynamicClass.ReflectionEmitUtils(System.Object, System.Object)' to access method 'DynamicClass.ReflectionEmitUtils(System.Object, System.Object)' failed.

IntermediateSerializer が期待どおりに機能していないのではないかとひそかに疑っていますが、データを効果的に解析および保存する方法は他にわかりません。ここで使用する必要がある別のセットアップはありますか?

4

1 に答える 1

1

タイルベースのレベルの保存と読み込みを100%確実にする最も効果的な方法は、私の経験では、BinaryWriterとBinaryReaderを使用することです。

しかし、私たちのレベル構造はあなたのものとは大きく異なります。多くのレイヤーがあります。各レイヤーはタイルセットを使用し、タイルのインスタンスで構成されます。タイルは、その位置(Vector2D)とTileId(タイルセットテクスチャ内のタイルのインデックス)を保持します。

オブジェクトをレベルに配置する方法は、ロード時に実際のオブジェクトに置き換えられるタイルセットを使用する方法です。

とにかく、データを保存およびロードするための適切な一般的な方法は、クラスにBinaryReaderを引数として取ることができるコンストラクターと、それ自体をBinaryWriterに書き込むメソッドを持たせることです。

このような:

public Tile(BinaryReader reader)
{
    Position.X = reader.ReadFloat();
    Position.Y = reader.ReadFloat();
    TileId = reader.ReadInt32();
}

public void WriteToStream(BinaryWriter writer)
{
    writer.Write(Position.X);
    writer.Write(Position.Y);
    writer.Write(TileId);
}

ロードするクラスが1つしかない場合は、次のように簡単に実行できます。

ロード用:

var tiles = new List<Tile>();
var reader = new BinaryReader(File.Open("level.bin"));

while (reader.BaseStream.Position < reader.BaseStream.Length)
{
    var tile = new Tile(reader);
    tiles.Add(tile);
}
reader.Close();

保存する場合:

var tiles; //lets pretend this is the level
var writer = new BinaryWriter(File.Create("level.bin"));

foreach (var tile in tiles)
{
    tile.WriteToStream(writer);
}

writer.Flush(); //IMPORTANT!!!
writer.Close();

ただし、リストにさまざまなタイプのアイテムが含まれている場合は、そのタイプも保存する必要があります。これを行うためのかなり一般的な方法は、次を挿入することです。

writer.Write(tile.GetType().FullName);

tile.WriteToStream(writer);の前

次に、ロード時に次のことを行う必要があります。

var tileType = Type.GetType(reader.ReadString()); //Read the type from the stream
var constructor = tileType.GetConstructor(new [] { typeof(BinaryReader)}); //get a constructor that can use a binaryreader
var tile = constructor.Invoke(new [] { reader }); //use said constructor to create an instance

お役に立てれば。また、これをメモリから書き込んでいるため、構文エラーが発生する可能性があることに注意してください。

于 2013-02-19T10:15:49.207 に答える