The last two nights I've been awake for much longer that it is healthy, programming the tool to automatically generate the game charts, based on simple better/worse pairs. Once the ideas were established, it was only a matter of coding, learning how SVG works, remembering how to generate XMLs with Linq's XDocument -never again without it-, and using some advanced XML features.
So, I'll explain in a few words what I have done.
First of all, is the data I work with. I keep a simple XML document with games and comparisons. Games are specified as:
<games>The ID is the name the game is usually known for, the URL would point to that game's review, if I have one up, and the year... I have not verified them for this test file, so they are most probably not the year the game was released.
<game id="Dragon Age" year="2009" url="http://social.bioware.com">
<names>
<name value="Dragon Age: Origins"/>
</names>
</game>
<game id="Mass Effect 2" year="2010"/>
<game id="Mass Effect" year="2008"/>
<game id="Baldur's Gate" year="1996" url="http://www.gog.com"/>
<game id="Baldur's Gate 2" year="1997">
<names>
<name value="Baldur's Gate II"/>
<name value="Baldur's Gate II: Shadows of Amn"/>
</names>
</game>
<game id="Neverwinter Nights" year="2000"/>
<game id="Icewind Dale" year="1997"/>
<game id="KotOR" year="1999">
<names>
<name value="Knights of the Old Republic"/>
</names>
</game>
<game id="Oblivion" year="2006">
<names>
<name value="The Elder Scrolls IV: Oblivion"/>
</names>
</game>
<game id="Gothic" year="2001"/>
<game id="Fallout" year="1997"/>
<game id="Planescape: Torment" year="2000"/>
</games>
Then, I have the comparisons, which are much simpler:
<comparisons>Basically, a game is better than other by a difference margin. I have defined "Little", "Quite", "Lots" and "None". The latter is a little dirty trick =).
<comparison better="Fallout" worse="Baldur's Gate" difference="Little"/>
<comparison better="Baldur's Gate 2" worse="Baldur's Gate" difference="Little"/>
<comparison better="Mass Effect" worse="Mass Effect 2" difference="Lots"/>
<comparison better="Mass effect" worse="Dragon Age" difference="Quite"/>
<comparison better="Planescape: Torment" worse="Baldur's Gate" difference="Quite"/>
<comparison better="Dragon age" worse="Neverwinter Nights" difference="Quite"/>
<comparison better="Dragon Age" worse="Kotor" difference="None"/>
<comparison better="Baldur's Gate" worse="Icewind Dale" difference="Lots"/>
<comparison better="Baldur's Gate" worse="Mass Effect" difference="None"/>
<comparison better="Kotor" worse="Gothic" difference="Lots"/>
<comparison better="Gothic" worse="Oblivion" difference="None"/>
</comparisons>
With this info, I just request the chart for a game, with a given number of entries and how far to explore related games (4 steps could return Mass Effect -> Dragon Age -> Kotor -> Gothic). It is possible that, with time, I'll add incorrect cycles or incongruent relationships into the pairs, so I have built a safeguard which warns me when a game would be re-added far from its current position.
This operation explores all games related to the original, and places them in levels (0 is the reference level; games in level -1 are a little worse, those in level 3 are a lot better), repeats with the games just added to the chart, and so on. For my sanity's sake, if a game is already in the chart, it is not added.
Once the chart is complete, it is turned into a nice SVG, with code as simple as this:
XDocument svgDoc = new XDocument (New elements are added with things like:
new XDeclaration ("1.0", "UTF-8", "yes"),
new XDocumentType ("svg", @"-//W3C//DTD SVG 1.1//EN", @"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null),
new XElement (this.svgns + "svg",
new XAttribute ("version", 1.1),
new XAttribute (XNamespace.Xmlns + "xlink", this.xlinkns), new XAttribute ("width", this.ImageWidth),
new XAttribute ("height", this.ImageHeight),
new XAttribute ("viewBox", "0 0 " + this.ImageWidth + " " + this.ImageHeight),
new XElement (this.svgns + "defs",
this.CreateGradientElement ()),
this.CreateBackgroundElement (),
new XElement (this.svgns + "titles",
keys.Select (key =>
this.Chart.GetLevelGames (key).Select (game =>
this.CreateTitleElement (game, ++titleCount * titleDistance))))));
private XElement CreateLinkedTextElement (string text, string url, float yOffset, string colour, int size)or
{
XElement linkedText = new XElement (this.svgns + "a",
new XAttribute (this.xlinkns + "href", url),
this.CreateTextElement (text, yOffset, colour, size));
return linkedText;
}
private XElement CreateTextElement (string text, float yOffset, string colour, int size)
{
XElement textElem = new XElement (this.svgns + "text",
new XAttribute ("x", "50%"),
new XAttribute ("y", yOffset + "%"),
new XAttribute ("font-family", this.FontName),
new XAttribute ("font-size", size),
new XAttribute ("fill", colour),
new XAttribute ("text-anchor", "middle"),
text);
return textElem;
}
And the final result is something as pretty as this (note: Blogspot does not support SVG, nor does Internet Explorer, so the image is a PNG imported from the SVG; I'll try to get the SVGs to work, with links and all):
And the SVG code:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>I hope I'll put all this to some use pretty soon.
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="400" viewBox="0 0 200 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="Green" />
<stop offset="50%" stop-color="Blue" />
<stop offset="100%" stop-color="Red" />
</linearGradient>
</defs>
<rect x="0%" y="0%" width="100%" height="100%" fill="url(#gradient)" />
<titles>
<text x="50%" y="9.090909%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Planescape: Torment</text>
<text x="50%" y="18.18182%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Fallout</text>
<text x="50%" y="27.27273%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Baldur's Gate 2</text>
<text x="50%" y="36.36364%" font-family="Arial" font-size="16" fill="White" text-anchor="middle">Mass Effect</text>
<a xlink:href="http://www.gog.com">
<text x="50%" y="45.45454%" font-family="Arial" font-size="14" fill="Gold" text-anchor="middle">Baldur's Gate</text>
</a>
<a xlink:href="http://social.bioware.com">
<text x="50%" y="54.54546%" font-family="Arial" font-size="14" fill="Gold" text-anchor="middle">Dragon Age</text>
</a>
<text x="50%" y="63.63636%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">KotOR</text>
<text x="50%" y="72.72727%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Mass Effect 2</text>
<text x="50%" y="81.81818%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Icewind Dale</text>
<text x="50%" y="90.90909%" font-family="Arial" font-size="14" fill="Black" text-anchor="middle">Neverwinter Nights</text>
</titles>
</svg>
Oh my... Kawaii!!!
ReplyDeleteThe previous post link is not working... (should I have used quotes?? only you can answer that >_<)
ReplyDeletexml is so ugly :_(
"Previous post" fixed. Copy/Paste is uglier =)
ReplyDeleteAs a matter of fact, XML is like a rose: pluck it with your bare hands and hate it; use a cute pair of gardening gloves and admire the beauty. Humans were never really intended to get too dirty with XML.