I've been working on a game project with a small group for a bit now and we've hit a block. One of the features of this game is the ability for users to generate their own levels through the use of an in-game editor. The editor creates a Level object which stores the length and width of the level and a two-dimensional array of Tile objects. We've successfully implemented the camera system and can edit together a simple concept level without too much difficulty, but the process of successfully saving the level and loading it back up later is a concept that's proving difficult, and I was hoping one of you could offer some guidance to get the intended functionality down.
In its current state, when the user presses the 'S' key, our LevelManager class runs the SaveLevel method below:
public static void SaveLevel()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("example.xml", settings))
{
IntermediateSerializer.Serialize(writer, CurrentLevel, null);
}
}
Which serializes our level (CurrentLevel) into an XML file in the project (We'll worry about saving to different files after we get this basic setup working.) I ran the program, created a small map and saved it, and here's the output in the resulting XML file:
<?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>
So at the very least we do have data information on the tiles generated in the level, so that's something. We'd like our users to be able to load up saved levels during runtime as well, so we mapped the 'L' key to load that saved XML file, and that's where the problem shows up. Our read looks like this:
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);
}
}
}
When we try testing that functionality, we get this error:
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.
I have a sneaking suspicion that the IntermediateSerializer doesn't quite work how we want it to work, but I'm not sure how else to parse and store the data effectively. Is there a different setup I should be using here?