0

我一直在爲一個小團隊進行一個遊戲項目,現在我們已經打了一個塊。這款遊戲的特點之一是用戶可以通過使用遊戲內編輯器來生成自己的關卡。編輯器創建一個Level對象,該對象存儲該級別的長度和寬度以及Tile對象的二維數組。我們已經成功實現了相機系統,並且可以在沒有太多困難的情況下一起編輯一個簡單的概念級別,但成功保存級別並在稍後加載它的過程是一個難以實現的概念,我希望你們中的一個人能夠提供了一些指導以實現預期的功能。建立遊戲編輯器,需要加載和保存幫助

在當前狀態下,當用戶按下「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完全不是那麼回事,我們怎麼想工作,但我不知道如何有效地解析和存儲數據。我應該在這裏使用不同的設置嗎?

回答

1

根據我的經驗,使用BinaryWriter和BinaryReader來保存和加載基於tile的級別的最有效方法是100%。

雖然我們的層次結構與您的層次結構有很大不同,我們有很多層。每個圖層使用一個tileset並由tile的實例組成。平鋪保持其位置(Vector2D)和TileId(tileset-texture中的平鋪的索引)。

我們將對象置於水平的方式是在加載時用實際對象替換的tilesets。

總而言之,保存和加載數據的適當的通用方法是讓你的類有一個可以將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); 
} 

,如果你只有一個類加載,然後你可以簡單地說:

加載:

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(作家)之前;

,然後加載您需要:

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 

希望這有助於。並且請注意,我正在寫這個內存不足,所以語法錯誤很可能....

+0

感謝您的答覆。我們實際上使用了DataContractSerializer路由,它工作得很好。原來我們的問題是,在VS4.5中不再支持IntermediateSerializer類,DataContract庫作爲它的替代品。 – MrMagoo22 2013-02-20 20:21:27

+0

嗯,我對xml-serializers的使用經驗有限。一旦我們的水平超過10mb xml,我們發現它太慢,體積太大。 10mb的xml結束了<500kb的二進制數據:P – 2013-02-21 07:19:27