-
Notifications
You must be signed in to change notification settings - Fork 0
Program_LoadDataFromXML
I have written an article about saving and loading game data before. In Axe Man, I improve the code to make it more versatile. So here is another article on reading XML files.
If we think of the loading system as a black box, we would like it to accept a file path and a data tag as inputs and output a piece data of specific type, which could be an integer, a string or something else. We can build such a system with two components:
- XML file --> [Read any XML files] --> XElement
- XElement, Data tag --> [Retrive data from a specific XElement] --> Data
The first component, SaveLoadXML simply wraps XElement.Load()
.
public interface ISaveLoadXML
{
XElement Load(string file, string directory);
}
public class SaveLoadXML : ISaveLoadXML
{
public XElement Load(string file, string directory)
{
string path = Path.Combine(directory, file);
if (File.Exists(path))
{
return XElement.Load(path);
}
throw new FileNotFoundException();
}
}
The second component is more interesting. Ideally, we would design an interface like this:
public interface IGameData
{
int GetIntData(DataTag dataTag);
string GetStringData(DataTag dataTag);
bool GetBoolData(DataTag dataTag);
}
However, there are multiple data tags in the real game. For example, ActorDataTag
, SettingDataTag
, MainTag
and SubTag
. And the XElement
structure varies from file to file:
<Setting>
<WizardMode>true</WizardMode>
</Setting>
<ActorData>
<Dummy>
<Name>Dummy</Name>
<HP>
<Max>10</Max>
<Restore>2</Restore>
</HP>
</Dummy>
</ActorData>
In order to solve these problems, we need to design specific interfaces for each XML file. These interfaces have similar names: ISettingData
and IActorData
. They have the same method names: GetIntData()
and GetStringData()
, but the input arguments vary.
public interface ISettingData
{
bool GetBoolData(SettingDataTag settingData);
string GetStringData(SettingDataTag settingData);
}
public interface IActorData
{
int GetIntData(MainTag mainTag, SubTag subTag, ActorDataTag actorData);
string GetStringData(MainTag mainTag, SubTag subTag,
ActorDataTag actorData);
}
ActorData and SettingData implement interfaces mentioned above. They all have a private method which looks like bool TryGetData(DataTag dataTag, out XElement xElement)
. Let's take a close look at SettingData
.
public class SettingData : ISettingData
{
public bool GetBoolData(SettingDataTag settingData)
{
if (TryGetData(settingData, out XElement data))
{
return (bool)data;
}
// We can return a default value instead of throwing an exception.
throw new Exception("Setting not found.");
}
// Every `XData` class has a `TryGetData()` with different arguments.
private bool TryGetData(SettingDataTag settingData, out XElement data)
{
// Load a specific XML file.
XElement xmlFile = SaveLoadXML.Load("setting.xml", "Data");
// How to retrieve data from XElement
// is based on the structure of the XML file.
data = xmlFile.Element(settingData.ToString());
return data != null;
}
}
From an outsider's view, we call SettingData.GetBoolData()
or ActorData.GetStringData()
, which accepts certain data tags, to get the data we want, and we know nothing about the class SaveLoadXML
.
Home | Latest | Game List | Design | Programming