Building an UI system that allows you to interact with the game's core mechanisms isn't easy. It's easy to create a system where you can place buttons and other pre-defined components if the game is looking for them (i.e. hardcoded buttons that you can only specify their location and size for example). However, the system I'm aiming for is to allow you to control more than that. The game isn't expecting any particular UI, it only have list of events that can be called from the UI, and a list of functions that can return data. The tricky part is creating the connection between the UI and the Data.
I originally picked C# because I liked its layout. Now I'm especially glad that I chose it. The reason is that while looking for a method of getting a variable name that's hard-coded inside the program, C# have a relatively simple method of doing this! So I've created a test function that checks to see if I can actually retrieve the values of properties that I'm looking for inside a list of returned objects, and it worked!
Edit: Arg, it ate the greater than/lesser than brackets, so replaced those with () instead (all (T) uses those brackets)
public void FillData(T)(List(T) values, GameMain gameMain) where T : class
{
foreach (T t in values)
{
string value = t.GetType().GetProperty("GalaxyScriptName", typeof (string)).GetValue(t, null).ToString();
}
}
Basically it tells the function T is a class, and contains members. Then it loops through list of instanced classes (in this case, GalaxyScript class that only contains one string member, GalaxyScriptName) and retrieves the value of the "GalaxyScriptName" property from inside the class.
What this means is that I can return a list of ANY class (StarSystem, Planet, ShipDesign, etc), and this function will work with any of them! So I can populate UI with data! However, this is just 1/3 of the work (yet it's the most critical part)!
The other 2/3 is setting up a way where the game recongize that the UI wants certain data, and provides it with those data, and having the UI fill in its controls with those data. I've already set up a way for UI to tell the game it looks for a certain data (I'm currently in process of converting GalaxySetup screen to the new UI system):
in XML file (blue text is the UI telling the game it's looking for certain data):
Edit: Same issue as above, replacing with ()'s
(UIElement name="GalaxyDropDown" UIType="DropDown" OnSelect="UpdateGalaxyScript,[GalaxyDropDown]" DataSource="GalaxyScriptList" xPos="XMIDDLE+130" yPos="YMIDDLE-275" width="250" height="35" arrowxoffset="10" arrowyoffset="10")
(Template height="30")
(SubElement UIType="Label" xPos="10" yPos="5" content="[GalaxyScriptName]" /)
(/Template)
(/UIElement)
When the screen is refreshed, it sees that one control has a valid "DataSource" attribute, and tells the game to go get the required data as per this function:
public void RefreshData()
{
foreach (var uiType in UITypes)
{
if (!string.IsNullOrEmpty(uiType.DataSource))
{
uiType.FillData(_gameMain.GetData(uiType.DataSource), _gameMain);
}
}
}
So the UI part in letting the game know what it needs is done. Now for the last 1/3rd part, getting both to actually work together.
Notice the "Template" element in the XML section above? It basically tells the game that each row inside the parent UI follows this layout. It can define its size, the child controls, etc. Each row correspond to each class retrieved from the DataSource. So if there's 4 galaxy scripts, the drop-down will have 4 options, each corresponding to one script. Each row will have a simple text as indicated in the Template element.
The Template part isn't implemented yet however. I'm trying to think of a good way to bind the attributes of a control to a class (If you're familiar with WPF and XAML, you can get ideas of what I'm trying to do here). Hopefully soon this part will be done as well.
No comments:
Post a Comment