seeseekey.net - Invictus Deus Ex Machina

Das mitt­ler­weile mit CSS Dinge wie Logos und For­men abge­bil­det wer­den, hat sich sicher­lich schon her­um­ge­spro­chen. Wit­zig wird das ganze immer dann, wenn neue Gren­zen aus­ge­lo­tet wer­den, wie dies auch bei den „CSS Crea­tures“ geschieht.

bennettfeely.com/csscreatures/

bennettfeely.com/csscreatures/

Dort wer­den kleine Mons­ter gezeigt, wel­che voll­kom­men in CSS erstellt wur­den. Dane­ben kann man sich auch eigene Mons­ter erzeu­gen. Zu fin­den ist das ganze unter http://bennettfeely.com/csscreatures/.

Bei melonJS han­delt es sich um eine Java­script Engine zur Spie­le­ent­wick­lung im Brow­ser mit­tels HTML5. Möchte man dort ein Level laden, so geschieht das in Form einer TMX Datei. In melonJS gibt es dabei zwei Metho­den zum laden der ent­spre­chen­den Daten. Diese sind „me.loader.preload“ und „me.loader.load“. Alle Bei­spiele wel­che man im Netz so fin­det nut­zen dabei immer die „pre­load“ Methode:

var g_resources= [
{ name: "desert1",          type: "image", src: "desert1.png" },
{ name: "desert",           type: "tmx",   src: "desert.tmx" },
{ name: "player_male_base", type: "image", src: "player_male_base.png" },
{ name: "fog",              type: "image", src: "fog.png" }
];

...

me.loader.preload(g_resources);

Das Pro­blem ist das man bei grö­ße­ren Spie­len mit ein paar hun­dert MiB Spiel­da­ten, das ganze schlecht kom­plett in den Spei­cher laden kann. Hier­für gibt es die „load“ Methode. Aller­dings ent­hält diese einige Feh­ler wel­che das ganze erschwe­ren. Die „pre­load“ Methode trägt jede TMX Datei in das Array „levels“ im „me.levelDirector“ ein. Bei der „load“ Methode pas­siert genau dies nicht. Des­halb muss man hier anders vor­ge­hen (bis der Feh­ler beho­ben ist). Ein Mini­mal­b­ei­spiel zum laden eines Levels sieht damit so aus:

<!DOCTYPE html>
<html>
  <head>
    <title>melonJS minimal sample</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <script type="text/javascript" src="melonJS.js"></script>

    <script type="text/javascript">
      var jsApp = {
        start: function() {
          if (!me.video.init('jsapp', 640, 480, false, '1', false))
          {
            alert("Sorry but your browser does not support html 5 canvas.");
            return;
          }

          me.loader.onload = this.loaded.bind(this);

          //lade manuell
          me.loader.load({name: "desert1",  type:"image",  src: "desert1.png"}, this.onload);
          me.loader.load({name: "desert",  type:"tmx",  src: "desert.tmx"}, this.onload);

          //zeige Ladebildschirm
          me.state.change(me.state.LOADING);
        },

        onload: function(data) {
          me.levelDirector.addTMXLevel("desert"); //Bugfix
          me.levelDirector.loadLevel("desert");
        },

        loaded: function() {
          me.state.set(me.state.PLAY, new PlayScreen());
          me.state.change(me.state.PLAY);
        }
      }

      var PlayScreen = me.ScreenObject.extend({
      });

      //starte wenn der Browser bereit ist
      window.onReady(function() {
        jsApp.start();
      });
    </script>
  </body>
</html>

Damit lädt man ein Level dyna­misch, ohne auf die „pre­load“ Methode ange­wie­sen zu sein. Mög­lich wird dies durch den klei­nen Bug­fix in der „onload“ Methode:

me.levelDirector.addTMXLevel("desert"); //Bugfix

Die­ser sorgt dafür das der level­Di­rec­tor über die ent­spre­chende TMX Datei infor­miert wird und somit die Datei beim laden des Levels auch findet.

Über Webso­ckets kann man Binär­da­ten ver­schi­cken, lei­der ist dies nicht ganz so ein­fach wie es sein sollte. Das erste Pro­blem ist, das es in Java­Script bis vor eini­ger Zeit keine „Binär­ty­pen“ gab. Aber dank eini­ger Dinge ist es mitt­ler­weile mög­lich Binär­da­ten per Java­Script und Webso­ckets zu ver­sen­den. Mein Pro­blem an der binä­ren Daten­über­tra­gung war bis­her, das es augen­schein­lich nir­gens ein kom­plet­tes Bei­spiel gibt, wel­che diese ein­fach mal demons­triert. Dabei ist das ganze rela­tiv einfach:

<!DOCTYPE html>
<html>
  <head>
    <title>Websocket Binary Test</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <script type="text/javascript">
      websocket = new WebSocket("ws://echo.websocket.org");
      websocket.binaryType = "arraybuffer"; //Binärtyp auf arraybuffer setzen

      //OnOpen verdraten
      websocket.onopen = function (e) {
        //Array zusammenbauen
        var message = new ArrayBuffer(9);
        var dataViewMessage = new DataView(message);

        dataViewMessage.setInt8(0, 25); //Command ID
        dataViewMessage.setInt16(1, 11); //Account ID
        dataViewMessage.setInt32(5, 43333020); //Anzahl der Credits

        //message per Websocket wegschicken
        websocket.send(message);
      }

      //OnMessage verdraten
      websocket.onmessage = function (wsPackage) {
        //Datentyp ermitteln
        if(wsPackage.data instanceof ArrayBuffer) alert("ArrayBuffer");
        else if(wsPackage.data instanceof Blob) alert("Blob");
        else if(typeof wsPackage.data === "string") alert("string");

        //Daten empfangen und auseinander bauen
        var dataViewPackage = new DataView(wsPackage.data);
        alert(dataViewPackage.getInt8(0));
        alert(dataViewPackage.getInt16(1));
        alert(dataViewPackage.getInt32(5));
      }
    </script>
  </body>
</html>

Im den ers­ten Zei­len im Skript­teil wird zuerst ein Webso­cket ange­legt, wel­ches sich mit „ws://echo.websocket.org“ ver­bin­det. Die­ser Ser­ver gibt immer genau das zurück was er emp­fängt und eig­net sich somit aus­ge­zeich­net für die­sen klei­nen Test.

Danach wird der „bina­ry­Type“ des Webso­ckets auf „array­buf­fer“ gesetzt, da wir mit einem sol­chen arbei­ten wol­len. In der ver­knüpf­ten „OnO­pen“ Methode wird ein „Array­Buf­fer“ mit der pas­sen­den Größe ange­legt und mit die­sem ein „Data­View“ initia­li­siert. Mit die­sem ist es dann mög­lich pro­blem­los mög­lich die ent­spre­chen­den Werte in den „Array­Buf­fer“ zu setzen.

Dies geschieht dann mit den Zeilen:

dataViewMessage.setInt8(0, 25); //Command ID
dataViewMessage.setInt16(1, 11); //Account ID
dataViewMessage.setInt32(5, 43333020); //Anzahl der Credits

Am Ende wird das ganze weg­ge­schickt und anschlie­ßend wie­der in der „OnMes­sage“ Funk­tion emp­fan­gen. Dort wird der Daten­typ ermit­telt (für den Fall das man mit meh­re­ren Typen arbei­tet) und anschlie­ßend wird das Paket wie­der Binär aus­ein­an­der genommen.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.websocket.org/echo.html
http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/
https://developer.mozilla.org/en-US/docs/JavaScript_typed_arrays
http://msdn.microsoft.com/de-de/library/br212463%28v=vs.94%29.aspx
https://developer.mozilla.org/en-US/docs/JavaScript_typed_arrays/ArrayBuffer
http://stackoverflow.com/questions/11390021/transferring-files-with-javascript-through-websockets

In den Zei­ten von HTML5 wird uns eine neue Web­tech­nik nach der ande­ren um die Ohren geschla­gen und da sitzt man nun als Ent­wick­ler und über­legt wel­che Tech­ni­ken man davon ein­set­zen kann. Sehr hilf­reich bei die­sem Pro­blem ist die Seite http://caniuse.com bei wel­cher man nach der ent­spre­chen­den Tech­nik suchen kann (z.B. WebGL) und dann sehen kann, in wel­chen Brow­ser und Ver­sio­nen die jewei­lige Tech­nik unter­stützt wird.

Das ganze wird dabei in einer über­sicht­li­chen (tabel­la­ri­schen Form) ser­viert. So sieht man dann z.B. das die Unter­stüt­zung für Web­Wor­ker aus Android ab Ver­sion 2.2 ent­fernt wurde, es in ande­ren Brow­sern aber pro­blem­los nut­zen kann.

HTML und Spie­le­ent­wick­lung ist etwas was vor ein paar Jah­ren nicht wirk­lich zusam­men­passte. Mitt­ler­weile ist dies dank HTML5, Java­script und Co. mög­lich und es gibt auch schon einige Spiele wel­che dies ein­drucks­voll zei­gen. Ein inter­es­san­ter Blog der sich rund um die­ses Thema dreht, fin­det sich unter http://www.html5gamedevs.com/. Dort wer­den neue HTML5 Spiele und inter­es­sante Neue­run­gen aus die­sem Bereich vorgestellt.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/HTML5

Rol­len­spiele in Java­script sind an sich eine schöne Sache. Man muss keine zusätz­li­che Soft­ware instal­lie­ren und das Spiel als sol­ches ist auch immer aktu­ell. Gezeigt hat dies neu­lich Mozilla mit dem MMORPG Brow­ser­Quest wel­ches kom­plett im Brow­ser läuft. Möchte man RPGs sel­ber schrei­ben so sollte man sich mal die Biblio­thek RPG JS anschauen, wel­che unter http://rpgjs.com/ zu fin­den ist. Die Engine ist dabei unter MIT und GPL dual lizenziert.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.guido-muehlwitz.de/2012/02/rollenspiele-in-html5/
http://www.golem.de/news/browserquest-mozilla-startet-browser-mmog-in-html5-1203-90802.html

Nach eini­gen Mona­ten ist es Zeit den Zwi­schen­stand für den neuen Inver­tika Ser­ver und den Cli­ent vor­zu­stel­len. Inver­tika soll somit auf einer neuen tech­ni­schen Basis ste­hen. Diese neue tech­ni­sche Basis sieht so aus, das der Ser­ver in C# geschrie­ben wird und somit unter Mono und .NET läuft. Für den Cli­ent ist eine Imple­men­ta­tion als Webap­pli­ka­tion ange­dacht. Das ganze hatte dabei meh­rere Gründe:

  • die Pro­duk­ti­vi­tät ist in C# höher als in C/C++
  • es kön­nen keine Spei­cher­lö­cher entstehen
  • durch die auto­ma­ti­sche Spei­cher­ver­wal­tung wird der Ent­wick­ler entlastet
  • moder­nes und kon­sis­ten­tes Framework
  • Anpas­sung auf eigene Bedürfnisse
  • schnel­lere Entwicklung
  • IPv6 Unter­stüt­zung ist pro­blem­los möglich
  • bes­sere Unter­stüt­zung von mobi­len Geräten

Neben die­sen Grün­den sind es auch einige Dinge wie „typedefs“ wel­che nicht unbe­dingt zum Ver­ständ­nis bei­tru­gen oder meh­rere Klas­sen und Struk­tu­ren in einer Datei, wel­che das ganze ziem­lich unüber­sicht­lich machen. Auch die Abhän­gig­keit von zu vie­len Biblio­the­ken wurde verringert.

Der Inver­tika Code in der Entwicklung

Nach einer kur­zen Pla­nung­phase ging es dann am 3. Januar los mit der Ent­wick­lung. Zuerst wurde damit begon­nen den Account­ser­ver zu por­tier­ten. Dabei wur­den im Gegen­satz zum Ori­gi­nal einige Dinge verändern:

  • das Netz­werk setzt nun statt auf der Biblio­thek „enet“ direkt auf TCP auf
  • PhysFS wurde wegrationalisiert

Am 13. Januar (einem Frei­tag ;) ) waren die größ­ten Por­tie­rung­pro­bleme beim Account­ser­ver gelöst und es wurde begon­nen den Game­ser­ver zu por­tie­ren. Am Game­ser­ver ist die ein­zige grö­ßere Ände­rung die Anpas­sung der Skript­schnitt­stelle, damit diese mit den CLR Spra­chen kom­pa­ti­bel ist. Die Road­map für die Por­tie­rung sah dabei so aus:

  • Januar 2012: Imple­men­ta­tion des Inver­tika Server
  • Februar 2012 Imple­men­ta­tion des Inver­tika Clients
  • März 2012: Test der Software

Wie sich das für eine ordent­li­che Road­map gehört wurde sie nicht ein­ge­hal­ten. So ist eini­ges noch nicht fer­tig und auch am Cli­ent muss noch viel getan wer­den. Der Cli­ent sollte ursprüng­lich auch in C# geschrie­ben wer­den und es wurde damit auch begon­nen. Theo­re­tisch ließe sich diese Cli­ent­va­ri­ante auf die Platt­for­men Win­dows, Linux, Mac OS X, iOS und Android brin­gen, prak­tisch ist es mit klei­ne­ren und grö­ße­ren Pro­ble­men verbunden.

Ein gene­rel­les Pro­blem an einem sol­chen Cli­ent ist, das er auf der jewei­li­gen Ziel­platt­form erst instal­liert (oder auch kom­pi­liert) wer­den und außer­dem vom Nut­zer aktu­ell gehal­ten wer­den muss. Schö­ner wäre es, wenn man diese Hürde aus dem Weg geschafft wird. Mitt­ler­weile ist es dank Tech­ni­ken wie Webso­ckets, Web­wor­kern und Can­vas mög­lich, den Cli­ent kom­plett als Webap­pli­ka­tion zu schreiben.

Die Anfänge des neuen Cli­ents basie­ren dabei auf der Tech­demo „mana.js“ wel­che unter https://github.com/bjorn/mana.js zu fin­den ist. Der Vor­teil der web­ba­sier­ten Lösung ist dabei die große Kom­pa­ti­bi­li­tät mit unter­schied­lichs­ten Gerä­ten solange sie über einen aktu­el­len Brow­ser verfügen.

Die Tech­demo des Cli­ents auf einem iPad

Wäh­rend der Ent­wick­lung beka­men die ein­zel­nen Teile auch Namen die wie folgt lauten:

  • inver­tika (Client)
  • invertika-account (Account­ser­ver)
  • invertika-game (Game­ser­ver)

Der Quell­text sollte in den nächs­ten Tagen im Repo­sitory (http://source.invertika.org) erschei­nen und zur Mit­ar­beit ein­la­den ;)

Wei­tere Infor­ma­tio­nen gibt es unter:
http://invertika.org

Wer ein Spiel für ein Mobil­ge­rät schrei­ben möchte hat das Pro­blem das es eine ganze Menge die­ser Sys­teme gibt. Die bekann­te­ren sind sicher­lich Android und iOS. Möchte man für diese Sys­teme ein Spiel schrei­ben, so wäre eine Abs­trak­ti­ons­schicht eine feine Sache. Eine sol­che bie­tet Google mit „PlayN“ unter der Apa­che Lizenz an. Mit die­sem Frame­work wurde unter ande­rem die Google Chrome Ver­sion von Angry Birds geschrie­ben. Aktu­ell wer­den fol­gende Platt­for­men unterstützt:

  • Java
  • HTML5
  • Android
  • iOS

Auch Flash wird unter­stützt, wobei das Backend dafür im Moment einen Main­tai­ner sucht und des­halb in die­ser Liste nicht auf­taucht. Her­un­ter­la­den kann man sich PlayN unter http://code.google.com/p/playn/.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://code.google.com/p/playn/wiki/PlatformStatus
http://www.schockwellenreiter.de/blog/2012/03/12/playn/

Ges­tern gab es einen Arti­kel über einen Game­boy Color Emu­la­tor und schon lese ich bei Golem (http://www.golem.de/1106/84265.html) etwas über PDF Ren­de­ring in Java­script. Es han­delt sich dabei um die Java­script Biblio­thek pdf.js.Mit die­ser Biblio­thek kann man PDF Doku­mente im Brow­ser ohne Plugins oder der­glei­chen ren­dern. Sie ist dabei bei wei­tem noch nicht Fea­ture kom­plett aber schon ein sehr schö­nes Proof of Con­cept. Der Quell­code ist dabei unter https://github.com/andreasgal/pdf.js zu finden.