I'm making a (2D) spaceship game, and I haven't been able to figure out an efficient way of saving spaceship data.
I have a "hull" (boundaries), in which all of the systems/rooms go. Rooms are contiguous, some systems are as well. I want to efficiently save the hull and room data for both easy manipulation of them (adding/subtracting space between rooms, extending and/or damaging the hull, etc.) and easily saving them in a (preferably) human-readable format.
What I see so far is two options:
If it makes any difference, I'm using (will be using) C# and Blend/WPF. If there's a component that can magically allow manipulation of children and serialize it, then I think that would be acceptable as well.
This is my first question on this site, so please mention if I did something incorrectly. Thanks for your time. :)
Considering that you probably have a number of things that would make the system of rooms more complex:
Simple size/shape and position could be represented using a bitmap style storage model, however it would not allow for more complex structures easily, without accompanying data.
I would consider using Data Contract serialization, this enables a wide range of methods to store and send your data, including but not limited to storing as XML, binary (more efficient, but not human readable), sending over network using WCF, etc. It allows to scale to pretty much infinitely complex models.
An example of a simple model and XML serialization below. (Everthing is rectangular here).
The definition of the hull, rooms, etc:
[DataContract]
class Hull
{
public int Width { get; set; }
public int Height { get; set; }
[DataMember]
public List<Component> Components { get; set; }
//read only properties will be ignored
public int SurfaceArea { get { return Width*Height; }}
//some properties can be excluded from serialization:
[IgnoreDataMember]
public int NotStoredInXml { get; set; }
public Hull()
{
this.Components = new List<Component>();
}
}
[DataContract]
[KnownType(typeof(Room))]
[KnownType(typeof(ComputerRoom))]
[KnownType(typeof(System))]
abstract class Component
{
[DataMember]
int Width { get; set; }
[DataMember]
int Height { get; set; }
[DataMember]
int X { get; set; }
[DataMember]
int Y { get; set; }
}
[DataContract] class Room : Component { }
[DataContract] class System : Component { }
[DataContract] class ComputerRoom : Room
{
[DataMember]
public int NumberOfCPUCores { get; set; }
}
Saving and loading data:
var hull = new Hull();
hull.Components.Add(new ComputerRoom { NumberOfCPUCores = 3 });
hull.Components.Add(new System());
hull.Components.Add(new Room());
var serializer = new DataContractSerializer(typeof (Hull));
using (var stream = File.Open("test.xml", FileMode.Create))
{
serializer.WriteObject(stream, hull);
}
Hull newHull;
using (var stream = File.OpenRead("test.xml"))
{
newHull = serializer.ReadObject(stream) as Hull;
}
Console.WriteLine(newHull.Components.Count); //3
The resulting XML:
<Hull xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication22"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Components>
<Component i:type="ComputerRoom">
<Height>0</Height>
<Width>0</Width>
<X>0</X>
<Y>0</Y>
<NumberOfCPUCores>3</NumberOfCPUCores>
</Component>
<Component i:type="System">
<Height>0</Height>
<Width>0</Width>
<X>0</X>
<Y>0</Y>
</Component>
<Component i:type="Room">
<Height>0</Height>
<Width>0</Width>
<X>0</X>
<Y>0</Y>
</Component>
</Components>
</Hull>
Update
If you want to support arbitrary shapes, you can look at the Path
syntax in WPF
and the Geometry Class