LINQ to XML

Language-Integrated Query (LINQ) er en teknologi der tillader query-egenskaber direkte i C#. I query-form ligner det SQL i syntax og opbygning. Alternativet er method-syntax som vi ikke vil bruge tid på i dette indlæg. Til de interesserede kan forskellen mellem query og method syntax ses her: http://msdn.microsoft.com/en-us/library/bb397947.aspx. MS anbefaler at man bruger query syntax alle de steder man kan, frem for method syntax.

LINQ to XML er en del af LINQ, og er designet til at trække data ud af xml, fra eksempelvis en fil.

Vi skal bruge namespacet ”System.Xml.Linq”. Dette namespace indeholder klasser som XDocument, XElement, XAttribute og XNode. Det er nogle af disse vi bruger i vores query.

LINQ syntaksen minder meget om SQL og kan ses her:
http://msdn.microsoft.com/en-us/library/bb308959.aspx#linqoverview_topic5

Lad os springe ud i det.

Lad os først finde noget XML vi selektivt vil trække data ud af. Følgende er et log udtræk fra SVN:

<?xml version=”1.0″?>
<log>
  <logentry revision=”200″>
    <author>Lars</author>
    <date>2010-06-03T08:24:19.329726Z</date>
    <paths>
      <path action=”M”>/sti/Upload.ascx.cs</path>
      <path action=”D”>/sti/Projekt.csproj.user</path>
    </paths>
    <msg>Changes to upload path handling</msg>
  </logentry>
  <logentry revision=”199″>
    <author>Lars</author>
    <date>2010-05-31T14:30:23.080950Z</date>
    <paths>
      <path action=”M”>/sti/Database.mdf</path>
      <path action=”M”>/sti/Database.ldf</path>
    </paths>
    <msg>Shrinked database again</msg>
  </logentry>
  <logentry revision=”198″>
    <author>Lars</author>
    <date>2010-05-31T13:59:33.689391Z</date>
    <paths>
      <path action=”A”>/sti/Projekt.sln</path>
      <path action=”A”>/sti/Projekt.suo</path>
    </paths>
    <msg>VS2010 Solution files.</msg>
  </logentry>
  <logentry revision=”197″>
    <author>Sral</author>
    <date>2010-05-28T07:10:51.597195Z</date>
    <paths>
      <path action=”M”>/sti/</path>
    </paths>
    <msg>Added files/folders to ignore filter.</msg>
  </logentry>
</log>

Først tæller vi alle log entries grupperet på author. Det kan klares således:

var output = from logentry in SvnLog.Elements("logentry")
    group logentry by (string) logentry.Element("author")
    into logentries
    select new { 
        Author = logentries.Key,
        Entries = logentries.Count()
    };

Vi piller querien fra hinanden og ser på de enkelte dele.

from logentry in SvnLog.Elements("logentry")

Dette statement returnerer en IEnumerable liste af XElementer indeholdende alle under-noder i hvert <logentry> element. Disse bliver så placeret i en variabel kaldet “logentry”.

group logentry by (string) logentry.Element("author") into logentries

Vi grupperer her på datasættet fra før med en under-node i <logentry> ved navn <author>. Note: Det er vigtigt at huske castet til string da de fleste klasser i System.Xml.Linq har custom type converters (http://msdn.microsoft.com/en-us/library/ayybcxe5.aspx).

Et cast til string giver elementets værdi, hvor logentry.Element(“author”).ToString() ville give en string repræsentation af objektet.

Til sidst placerer vi vores gruppering i en ny variable ved navn ”logentries”.

select new { Author = logentries.Key, Entries = logentries.Count() };

Her over laver vi en anonym type indeholdende vores fundne data (Anonymous Types: http://msdn.microsoft.com/en-us/library/bb397696.aspx)
Logentries.Key er altid hvad man grupperer på. I dette eksempel laver vi en simpel count på de fundne værdier.

Vi kører det igennem en foreach løkke:

foreach (var d in output) {
     Console.WriteLine("{0}: {1} entries.", d.Author, d.Entries);
}

Resultat:

Lars: 3 entries.
Sral: 1 entries.

Lad os prøve en lidt mere avanceret query med nestede selects.

Vi prøver følgende: Vores query skal tælle attributen action (i <path>) grupperet på værdien. For at være endnu mere vanskelig grupperer vi også på author igen.
Resultatet vi søger skulle gerne se sådan ud:

Lars: A:2, M:3, D:1
Sral: A:0, M:1, D:0

Querien kommer til at se således ud:

var data =
  from logentry
  in SvnLog.Elements("logentry")
  group logentry by (string)commit.Element("author")
    into logentries
    select new
    {
      Author = logentries.Key,
      Added = (
          from path in logentries.Elements("paths").Elements("path")
          where (string)path.Attribute("action") == "A"
          select path
      ).Count(),
      Modified = (
        from path in logentries.Elements("paths").Elements("path")
        where (string)path.Attribute("action") == "M"
        select path
      ).Count(),
      Deleted = (
        from path in logentries.Elements("paths").Elements("path")
        where (string)path.Attribute("action") == "D"
        select path
      ).Count()
    };

Det første i querien ligner statementet fra før: vi grupperer blot på author. Inde i vores anonyme type har vi nu 3 næsten ens selects:

from path in logentries.Elements("paths").Elements("path")

Vi finder alle ”path” noder som vores gruppering i det ydre scope indeholder.

where (string)path.Attribute("action") == "A"

Af de fundne path noder, finder vi alle dem der har attributten ”A”.

select path

Dem der matcher vores where clause selecter vi, plus pakker det hele ind til sidst, så vi kan lave en Count() på det.

foreach (var user in data) {
   Console.WriteLine("{0}: A:{1}, M:{2}, D:{3}",
      user.Author, user.Added, user.Modified, user.Deleted);
}

Og nu får vi det output vi søgte:

Lars: A:2, M:3, D:1
Sral: A:0, M:1, D:0

Unity - 3D i browsere

Unity’s 3D engine blev sidste år gratis og da 3D grafik er sjovt, og 3D grafik gjort nemt er endnu sjovere, skulle den naturligvis prøves.

Og Unity har gjort det rigtig nemt at lave 3D. En af de største styrker ved Unity er at brugeren kan lave projektet en gang og så udgive det til flere forskellige platforme, så som OS X, windows eller deres egen webplayer. Med Unity Pro kan man også udgive til Wii og iPhone/iPad.

Derudover er selve editoren nem at bruge, hvor objektor i verdenen, så som geometri og lyskilder, kan skabes som GameObjets. Fysik og scriptet adfærd er hellere ikke længere end et klik væk.

Et sjovt projekt der kombinere fysik, simpel geometri og en introduktion til scripting er xkcd’s Hell. Desuden er point systemet utroligt nemt.

Først skal blokkene laves. Under menuen GameObject -> CreateOther findes Cube, som skaber en kube i verdenen. Disse kuber kan så skaleres og placeres til at skabe alle de kendte tetris blokke.

Blocks

For at kunne arbejde med blokkene som et stykke geometry skabes der et nyt tomt GameObject og geometrien for hver blok placeres under hver deres tomme GameObject. Tyngdekraft og kollision tilføjes som beskrevet blot ved at tilføje en rigidbody komponent til GameObjectet.

Til sidst skal geometrien gemmes som en struktur hvorfra et nyt objekt kan instantieres hver gang en ny blok skal dale ned. Til dette bruges Unity’s Prefabs, prefabrikeret geometry. At obrette en ny blok kan nu gøres ved simpel drag ‘n drop fra prefab’en og over i scenen, eller ved at instantiere prefab’en i et script.

Selve banens geometri er ligeledes lavet ud fra 7 kuber. Hele geometrien samles så til et fungerende spil gennem 3 scripts.

Det første script TetrisGod.js, hvis navn er inspireret herfra. Formålet
med dette script er at skabe en tilfældig og muligvis spejlvendt blok.

Det andet script er StartGame.js. Dette scripts eneste formål er at bede den almægtige tetris gud om at starte spillet ved at skabe den første blok. Scriptet bliver sammen med TetrisGod.js placeret på kameraet og sat til at starte når kameraet “vågner”.

Det sidste script hedder MoveBlocks.js og er tilføjet på alle vores blocke. MoveBlocks er ansvarlig for at spilleren kan flytte blokken, at blokkene ikke falder udenfor banen og at en ny blok bliver spawnet når blokken kolliderer med et andet objekt. Desuden fjerner scriptet blokke når de ikke længere kan ses af kameraet.

Resultatet kan ses her. Et lille ekstra touch af smerte og pinsel er tilføjet ved ikke at teste for om der plads til at blokkene kan spawne. Hvis en blok derfor spawner oven i en anden blok resulterer det i at en sværm af blokke spawnes og spilleren må siges at have tabt.

For at finde ud af mere om Unity og hvordan man nemt kommer igang med at lave 3D projekter, kan man klikke ind på Unity3D.com’s resource sektion eller se en af de mange tutorials, der er tilgængelige på youtube.