Entwicklung eines 2D Tiled Map LibGDX Game Framework

Größe: px
Ab Seite anzeigen:

Download "Entwicklung eines 2D Tiled Map LibGDX Game Framework"

Transkript

1 DHBW KARLSRUHE TINF12B5 STUDIENARBEIT Entwicklung eines 2D Tiled Map LibGDX Game Framework Author: Armin Benz & Mike Schwörer Betreuer: Prof. PhD. Kay Berkling & April 2015

2 Inhaltsverzeichnis 1 Vorwort 1 2 Plattformunabhängigkeit Cocos2D-x MonoGame Unity3D LibGDX Unsere Entscheidung Umsetzung Umgebung Git und Github Gradle junit Tests Continuous Integration Metrics JavaDoc Das Framework Tiled Map Entity System Layer System Kollisionserkennung Settings Debugging Hintergründe Der Menü Layer Performance Optimizations Entity Liste Immutable Objects Der GarbageCollector Fazit 78 I

3 Listings 1 Eclipse Optionen in gradle setzen Gradle in der Kommandozeile Eine Assert Methode für zwe Vektoren TravisCI Konfiguration Gradle in der Kommandozeile TravisCI Konfiguration für das Erzeugen von JavaDoc Das Javadoc Publish Bashscript Ermitteln der aktuell sichtbare Tiles Beipiel einer TMX Datei Framerate unabhängiges bewegen eines Entities Die Klasse EntityCollisionGeometry Erkennen von Kollisionen (Kreis-Kreis) Erkennen von Kollisionen (Kreis-Dreieck) Erkennen von Kollisionen (Box-Box) Erkennen von Kollisionen (Kreis-Box) Erkennen von Kollisionen (Box-Dreieck) Erkennen von Kollisionen (Dreieck-Dreieck) Berechnen der CollisionMap-Position aus der Tile-Position Bewegen einer Geometrie in der CollisionMap Kommutative Eigenschaft von cancollidewith Eine Beispiel AGDXML Menü Definition II

4 Abbildungsverzeichnis 1 Git Network Graph mit smartgit Screenshot SmartGit Gradle Dependency Graph absgdx Beispiel der junit Test Anzeige Beispiel der Online Ansicht von TravisCI absgdx Metrics absgdx Test Coverage Visualisierung einer Tiled Map Visualisierung des FixedMapScaleResolver Visualisierung des ShowCompleteMapScaleResolver Visualisierung des MaximumBoundaryMapScaleResolver Visualisierung des MinimumBoundaryMapScaleResolver Visualisierung des LimitedMinimumBoundaryMapScaleResolver Visualisierung des SectionMapScaleResolver Lebenszyklus eines einzelnen Entities Riemann-Integral über die Beschleunigung eiens Entities Spezielle Entities Der Layer Stack Beispiel eines Entities mit mehreren Hitboxen Möglichkeiten einer Kreis-Dreieck Kollision Kollisionserkennung Kreis-Rechteck (1) Kollisionserkennung Kreis-Rechteck (2) Performance Graph der CollisionMap Berechnung des minimalen X-Abstands zweier Kreise Berechnung des minimalen X-Abstands eines Kreises und eines Rechtecks Berechnung des minimalen X-Abstands zweier Rechtecke Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (1) Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (2) Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (3) Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (4) Discrete-Time-Issue: Ein Objekt "phased" durch ein anderes Die absgdx Einstellungen in Baumdarstellung Beispiel der Debugansicht (In-Game) Beispiel der Debugansicht (In-Menu) III

5 35 Eine Seitensansichts-Map mit Hintergrund Erklärung zu Hintergründen mit Bewegungsparallaxe Klassendiagramm der Menü Elemente Die neun Texturen einer Menüfläche Der AGDXML Tag Tree Screenshot des AGDXML Menudesigner Performancevergleich LinkedList vs. ArrayList Verlauf des RAMs unter Betrachtung des GC IV

6 Erklärung gemäss ğ 5 (3) der Studien- und Prüfungsordnung DHBW Technik vom 22. September Ich habe die vorliegende Arbeit selbstständig verfasst und keine anderen als die angegebenen Quellen und Hilfsmittel verwendet. Ort Datum Unterschrift V

7 1 Vorwort Eine grosse Anzahl von Spielen, vor allem sogenannte mobile Games teilen sich eine Reihe von Merkmalen. So ist ein GroSSteil dieser Spiele zumindest von der Spiellogik her zweidimensional und die Karte ist in einem Grid angeordnet. Neben der gerasterten Karte gibt es eine Reihe von Entities die sich frei auf dieser bewegen können. Die Welt ist demnach entweder eine Draufsicht oder eine Seitenansicht. Im letzteren wird oft einfache zweidimensionale Physik und Kollisionserkennung benötigt. Da dies Merkmale sind, welche diese Gruppe von Spielen gemeinsam haben, ist es unsere Idee ein Framework zu entwickeln, dass diese Funktionalitäten abstrahiert und es dem Entwickler somit einfacher macht Spiele dieser Art zu entwickeln. Solche einfacheren 2D Spiele wie oben beschrieben findet man besonders häufig auf Handys und Tablets. Dies liegt einerseits an den schwächeren Geräten, welche es nicht ohne weiteres schaffen grafisch aufwendigere 3D Umgebungen darzustellen und andererseits daran, dass von solchen Gelegenheitsspielen einfache und schnell begreifbare Spielprinzipien erwartet werden. Von technischer Seite haben wir uns dagegen entschieden ein Framework von Grund auf, ohne jede Basis zu schreiben. Denn in dieser Richtung gibt es schon mehrere fertige Produkte und es wäre unnötig hier das Rad neu zu erfinden. Die Basis die wir für unser Projekt gewählt haben ist LibGDX. LibGDX ist ein OpenGL Framework mit dem Ziel Programme für unterschiedliche Plattformen zu kompilieren. Unterstützt werden unter anderen auch Android Geräte und Desktop PCs. Dies bietet den Vorteil, dass man seine Programme auf dem Rechner schnell testen und debuggen kann und nur ab und zu auch auf ein echtes Android Gerät exportieren muss. Hauptsächlich aus diesem Grund haben wir uns entschieden LibGDX als Grundlage für unser Framework zu verwenden Das Ziel, dass wir uns für unser Produkt gesetzt haben, ist es damit einfache 2D Spiele mit einer Tilemap und einem Entity-System entwickeln zu können. Unser Framework übernimmt die Verwaltung von Map, Entities und optional Elementen wie Menü und Netzwerk. Und durch LibGDX kann man das Projekt direkt am PC testen. 2 Plattformunabhängigkeit Ein entscheidender Vorteil das unser Framework von Anfang an haben soll ist die Möglichkeit den Code sowohl für Android als auch für Windows zu kompilieren. Da wir mit Java arbeiten bedeutet dies, dass 1

8 wir einerseits Bytecode für die DalvikVM (Android) und die JVM (Windows) erzeugen müssen. Trotzdem ist unser Ziel nicht Spiele zu erstellen die man auf beiden Plattformen vertreiben kann. Denn neben den verschiedenen Java Umgebungen gibt es zwischen der Plattform PC und der Plattform Smartphone auch noch andere wichtige Unterschiede. Vor allem die unterschiedliche BildschirmgröSSe und die verschiedenen Eingabemethoden sorgen dafür, dass eine Handyspiel nicht einfach auf den Rechner zu portieren ist ohne auf diesem fremd zu wirken. Trotzdem bietet die Möglichkeit eine App, welche speziell für Smartphones entwickelt wurde, auf dem PC auszuführen einige Vorteile. Hauptsächlich führt es zu einem einfacheren Arbeitszyklus des Entwicklers. Möchte man normalerweise eine App testen muss man sie entweder, mehr oder weniger umständlich, auf sie echte Hardware kopieren und dort ausführen oder einen Emulator benutzen welcher oft Anforderungen wie Geschwindigkeit und Korrektheit nicht gerecht wird. AuSSerdem wird das Finden von Fehlern und das Debuggen des Programms vereinfacht wenn man es direkt auf der Maschine ausführen kann auf der es auch entwickelt wird. Die Möglichkeit das Projekt auch auf einem PC auszuführen ist somit für den Entwickler gedacht und idealerweise verlässt ein solches Build niemals den internen Entwicklerkreis. Obwohl sowohl Android als auch Windows (und Mac/Linux) die Möglichkeit besitzen Java Code auszuführen ist es dennoch nicht einfach Code zu schreiben der ohne Veränderungen auf beiden Plattformen läuft. Ebenfalls ist der plattformunabhängige Zugriff auf die OpenGL Treiber nicht einfach da es hier viele kleinere Unterschiede gibt. Die Aufgabe ein Framework zu schreiben welches die Aufgabe übernimmt Code soweit zu abstrahieren, dass er sowohl in der DalvikVM als auch in der JVM lauffähig ist, würde den Umfang dieser Studienarbeit sprengen - wir haben uns deshalb dafür entschieden ein schon bestehendes Framework zu benutzen. IM folgenden werden einige unserer Optionen vorgestellt. 2.1 Cocos2D-x Cocos2D-x ist ein Open-Source C++ Framework. Dies ist unter Android ein besonderer Vorteil weil die DalvikVM umgangen wird und nativer Code auf dem Gerät ausgeführt wird. Man verliert dadurch jedoch einige Features der VM wie Garbage Collecting, gewinnt aber unter Umständen an Performance weil eine Zwischenschicht wegfällt. Cocos2D-x kann neben Windows und Android auch nach ios kompilieren und auch mittels Javascript und HTML5 Browser spiele erzeugen. 2

9 Neben der Fähigkeit Programme für verschiedene Systeme zu erzeugen kommt Cocos2D-x auch mit einer Vielzahl an Bibliotheken und Werkzeugen um Spiele zu entwickeln an. 2.2 MonoGame MonoGame ist ein Open-Source C# Framework. Es unterstützt, ebenso wie Cocos2D-x, mehrere Zielplattformen. Neben Windows, Android und ios kann man hier seine Programme aber auch auf der Playstation oder XBox ausführen. MonoGame sieht sich selbst als Nachfolger des jetzt nicht mehr weiterentwickelten 1 XNA Framework 4. Zu diesem Zweck wurde das Interface von Microsoft XNA 4 fast vollständig implementiert und in neueren Versionen auch erweitert. Ein grosser Vorteil von MonoGame ist.net Framework. Microsoft stellt mit dem.net 4.5 ein sehr mächtiges Framework zur Verfügung und mit MonoGame ist man in der Lage all seine Features zu nutzen. 2.3 Unity3D Unity3D ist das wohl grösste Framework, dass wir uns angeschaut haben. Es ist nicht nur eine Ansammlung von Bibliotheken sondern stellt auch eine Vielzahl an Werkzeugen und Editoren zur Verfügung. Der zentrale Code wird in C# geschrieben jedoch fliessen weitere Skriptsprachen wie Boo oder UnityScript in die Projekte mit ein. Zusätzlich zu einer speziell für Unity3D entwickelten IDE gibt es auch Editoren für die verschiedenen Modellformate die Unity3D benutzt. Unity3D ist - wie der Name es schon sagt - primär eine dreidimensionale Spieleengine, kann jedoch auch auf zwei Dimensionen reduziert werden. Unity3D unterstützt eine Vielzahl an Zielplattformen. Nicht nur Windows, Mac, Linux, Android und ios sondern auch Konsolen wie die Playstation 3, Playstation 4, XBox360 und die Wii. Zwar ist es nicht möglich die Spiele nach Javascript zu kompilieren jedoch könne sie über den Unity-WebPlayer ähnlich wie Flash Inhalte in eine HTML Seite eingebunden werden. 2.4 LibGDX Als letztes schauen wir uns LibGDX an. LibGDX ist ein OpenSource Java-Framework. Es ist primär auf Android, PC und Browser ausgelegt obwohl es auch Möglichkeiten gibt den Code nach ios zu portieren. 1 3

10 LibGDX ist im Vergleich zu den bisher vorgestellten Framework eher leicht gehalten, obwohl es eine Reihe an Bibliotheken gibt um seine Funktionen zu erweitern. 2.5 Unsere Entscheidung Aus diesen verschiedenen Möglichkeiten haben wir als Basis für unser Framework LibGDX ausgewählt. Wir haben uns dagegen entschieden Cocos2D zu verwenden, da der native Code zwar Vorteile hat, eines unserer Ziele es jedoch war das Entwickeln von Spielen für den Entwickler zu vereinfachen, und dies geht mit einer interpretierten Sprache einfacher. AuSSerdem kommt Cocos2D schon mit einer so gut ausgebauten Sammlung an Werkzeugen für zweidimensionale Spiele, dass wir entweder nur sehr wenig selber zu programmieren hätten oder an vielen Stellen schon bestehende Funktionalitäten neu Schreiben müssten. MonoGame wäre unsere beste Wahl gewesen wenn es nicht einen starken Nachteil unter Android gäbe: Für Android gibt es keine kostenlose.net VM und somit keinen kostenlosen Weg Programme die mit MonoGame geschrieben wurden auf Android auszuführen. Die einzigen bestehenden.net Implementierungen unter Android sind kostenpflichtig und scheiden somit für uns aus. Unity ist zwar eine sehr potente Spiele Engine, macht es jedoch durch das abgeschlossene Ökosystem mit eigener IDE etc. nicht besonders einfach etwas eigenes darauf aufzubauen. AuSSerdem ist es primär eine 3D Engine mit sehr vielen Features für den dreidimensionalen Raum. Hier eine 2D Engine aufzubauen würde primär bedeuten Features wegzuschneiden und deshalb haben wir uns gegen Unity3D als Basis für unser Framework entschieden. Zum Schluss blieb nur noch LibGDX übrig: Wir haben uns für LibGDX entschieden weil es all unseren Anforderungen gerecht wurde, man kann Code (in Java) schreiben und sowohl für die DalvikVM als auch für die JVM kompilieren. LibGDX ermöglicht es mittels eines eigenen Wrappers plattformunabhängig auf OpenGL zuzugreifen, Trotzdem haben wir noch relativ direkten Zugriff auf die OpenGL API und können unser eigenes Rendering betreiben. Dies sorgt auch dafür, dass es leicht für uns ist OpenGL als zweidimensionalen Renderer zu benutzen. Da LibGDX Gradle als Build Tool verwendet ist es ebenfalls einfach LibGDX als Dependency in unserem eigenen Projekt einzubinden und somit stellt es kein Problem dar ein eigenes Framework zu bauen welches LibGDX als Grundlage für seine Plattformunabhängigkeit nimmt. 4

11 Es ist noch zu erwähnen, dass LibGDX durchaus ein paar allgemein gehaltene Funktionen besitzt um die Spiele Entwicklung zu vereinfachen. Diese Benutzen wir jedoch nicht, da dass Ziel mit unserem Framework ist, einen viel spezielleren Fall (2D Tiled Games) abzudecken. 3 Umsetzung 3.1 Umgebung Git und Github Da wir an diesem Projekt zu zweit programmieren war es notwendig den Code zentral auf einem Server zu haben so dass wir beide Zugriff darauf haben. AuSSerdem brauchten wir ein System um Konflikte zu regeln falls wir zum Beispiel zeitgleich die gleiche Datei verändern wollten. Deshalb haben wir beschlossen ein Revision Control System zu verwenden. Genauer gesagt git 1. Mittels git ist der Code in einer Repository organisiert in der die Änderungen jeweils mit Commits eingepflegt werden. Auf Github haben wir ein Remote-Repository angelegt auf das wir beide unsere Änderungen pushen. Somit bekommt jeder die Änderungen des jeweils anderen mit und falls ein Konflikt auftritt kann und muss dieser ebenfalls in git oder mit einem externen Tools gelöst werden. Dieses System sorgt damit dafür, dass man einfach zusammen an einem Projekt arbeiten kann. 1 5

12 Abbildung 1: Git Network Graph mit smartgit AuSSerdem bietet git noch den Vorteil dass man Änderungen durch die einzelnen Commits zurückverfolgen kann und den Code unter Umständen auch auf einen alten Stand zurücksetzen kann. Besonders beim Suchen nach Fehlern kann man so den Commit identifiziern bei dem dieser das erste mal aufgetreten ist. Git ist an sich ein dezentrales Protokoll und jeder Teilnehmer hat eine eigenständige Kopie der Repository auf seinem Gerät. Das bedeutet falls einer unserer Rechner ausfällt - oder sogar der zentrale Server von Github, sind keine Daten verloren gegangen da der Code und die komplette History immer noch bei den übrigen Personen vorhanden ist. Dies ist jedoch kein Ersatz für ein Backup, da es trotzdem möglich ist die Repository zu zerstören oder die History zu fälschen. (3) S 5f Zwar kann man git direkt über eine Kommandozeile bedienen, jedoch ist es oft einfacher und übersichtlicher dafür spezielle Programme zu benutzen die einem Änderungen und die History visualisieren können. Wir benutzen dafür das Programm smartgit, da dies für Open Source Projekte kostenlos ist. 6

13 Abbildung 2: Screenshot SmartGit Gradle Zwar commiten wir unser Code mit git in unsere Repository, jedoch nicht alle Dateien. Es gibt eine Reihe an Dateien die nur temporär sind und beispielsweise bei jedem Kompiliervorgang neu erzeugt werden. Es wäre sinnlos solche Dateien in die Versionskontrolle aufzunehmen, vor allem da sie sich immer ändern würden und so die History mit unnötigen Daten belasten würden. Es gibt jedoch auch Dateien die zwar wichtig sind, trotzdem aber nicht in die Versionskontrolle gehören. Dies sind einerseits Konfigurationsdateien mit lokalen Pfaden die ungültig auf anderen System wären, IDE spezifische Dateien die unnütz für Nutzer anderer IDE s wären oder externe Libraries die oftmals zu gross sind um sie alle in die Repository zu commiten. Trotzdem sind Libraries und IDE-Dateien wichtig und eine dritte Person, die das Projekt zum ersten mal öffnet sollte diese Dateien nicht erst selbst erstellen beziehungsweise manuell herunterladen müssen. Um diese Probleme kümmert sich nun ein weiteres Tool namens gradle 1. Gradle ist ein Build- Managment-Automatisierung-Tool was bedeutet, dass wir in unser Git-Repository nur noch die gradle Konfigurationsdateien commiten und diese dann jeweils auf den Entwicklerrechnern ausführen. Diese löst dann die Projektabhängigkeiten auf und lädt fehlende Libraries automatisch nach und erstellt au- SSerdem Dateien wie die IDE-Projektdateien automatisch. 1 7

14 Dependency Management In gradle kann man angeben von welchen Bibliotheken oder Projekten ein Programm abhängig ist. Diese Bibliotheken können dann wiederum von anderen Bibliotheken abhängig sein und so bildet sich ein Abhängigkeitsbaum ausgehen vom Anfangsprojekt. Gradle lädt dann diese Bibliotheken, falls sie noch nicht auf dem Rechner vorhanden sind. Dies hat auch den Vorteil, dass wenn eine Bibliothek öfters im Abhängigkeitsbaum auftaucht sie trotzdem nur einmal geladen werden muss. (1) S. 55 Gradle unterstützt viele verschiedene Repositories in welcher nach fehlenden Bibliotheken gesucht werden kann, standardmässig wird jedoch die Maven Central Repository 1 benutzt. In dieser Repository sind sehr viele der frei verfügbaren java Libraries in vielen Versionen enthalten und können zum Beispiel einfach über gradle geladen werden. Konfiguration Die Konfiguration geschieht über build.gradle Dateien welche in der Sprache Groovy geschrieben sind. absgdx ist ein Multiprojekt, dies bedeutet, dass es aus mehreren Gradle Projekten besteht mit jeweils eigenen Konfigurationen die voneinander abhängen. (1) S. 79ff In der folgenden Grafik kann man unseren Abhängigkeitsbaum sehen. Die orange markierten Felder sind unsere Projekte und die anderen sind externe Abhängigkeiten. 1 8

15 Abbildung 3: Gradle Dependency Graph absgdx Das Projekt absgdx-framework ist hierbei das eigentliche Framework das wir entwickeln. asgdxtest ist das Testprojekt, es enthält alle Unit-tests für das Framework. absgdx-core und die beiden Plattformprojekte desktop und android sind zum testen und debuggen. Wird das Framework später für ein Projekt benutzt kommen in diese Projekte der eigentliche Code und absgdx-framework wird als Dependency eingebunden. Während wir jedoch das Framework noch entwickeln sind diese Projekte notwendig damit wir es auch ausprobieren können. Da wir alle an dem Projekt mit der Eclipse IDE entwickeln haben wir ein paar extra Eclipse Einstellungen in die build.gradle Dateien ausgelagert: eclipse.jdt.file.withproperties { props -> props.setproperty( org.eclipse.jdt.core.formatter. number_of_blank_lines_at_beginning_of_method_body, 0 ) props.setproperty( org.eclipse.jdt.core.formatter. number_of_empty_lines_to_preserve, 1 ) props.setproperty( org.eclipse.jdt.core.formatter. put_empty_statement_on_new_line, true ) props.setproperty( org.eclipse.jdt.core.formatter.tabulation.char, tab ) props.setproperty( org.eclipse.jdt.core.formatter.tabulation.size, 4 ) 9

16 } props.setproperty( org.eclipse.jdt.core.formatter.use_on_off_tags, false ) props.setproperty( org.eclipse.jdt.core.formatter. use_tabs_only_for_leading_indentations, false ) props.setproperty( org.eclipse.jdt.core.formatter. wrap_before_binary_operator, true ) props.setproperty( org.eclipse.jdt.core.formatter. wrap_before_or_operator_multicatch, true ) props.setproperty( org.eclipse.jdt.core.formatter. wrap_outer_expressions_when_nested, true ) //... Dies ist ein gutes Beispiel wie mächtig die Groovy Konfigurationsdateien sind, wir fügen in die generierten Eclipse property files hier noch unsere eigenen Felder ein. In diesem Beispiel setzen wir die Einstellungen für projektspezifische Formatierungen, damit der automatische Quellcodeformattierer bei allen die das Projekt in Eclipse laden gleich funktioniert. Verwendung in unserem Projekt Um Problemen mit verschiedenen Versionen von gradle entgegen zu wirken ist in unserer git Repository nicht nur die build.gradle Dateien vorhanden sondern auch der gradle Wrapper. Dies ist eine vollständige unabhängige Version von gradle die man anstatt der lokal installierten verwenden soll. Damit ist garantiert, dass jeder die gleiche Version von gradle verwendet. Ausgeführt wird sie dann über die Kommandozeile mit Befehlen wie > gradlew cleaneclipse eclipse afterclipseimport Dieses Beispiel führt zuerst den Task cleaneclispe aus um alle Dateien die mit der Eclipse IDE zusammenhängen zu löschen, dann werden sie mit eclipse neu aus den gradle Einstellungen erzeugt und zuletzt werden mit aftereclipseimport einige Änderungen vorgenommen. Der letzte Task ist von LibGDX vorgegeben damit das Android Projekt richtig konfiguriert ist. 10

17 3.1.3 junit Tests Um die Codequalität zu erhöhen haben wir uns entschieden unseren Code mit Unittests abzusichern. Die Unittests schreiben wir mit Test-Framework junit 4 1. Dies hat den Vorteil, dass es schon fertige Eclipse Plugins gibt um die Tests auszuführen und die Ergebnisse zu visualisieren. Abbildung 4: Beispiel der junit Test Anzeige Das Ziel der Unittests ist es einen GroSSteil der Funktionen und Methoden des Frameworks zu testen in dem sie mit verschiedenen Parametern getestet werden und dann überprüft wird ob die Ergebnisse stimmen. Besonders bei der Kollisionserkennung ist dies nützlich, da wir so überprüfen können ob nach Änderungen an der Collisionmap beispielsweise noch alle Kollisionen erkannt werden. Und es gibt sehr viele verschiedene Fälle von Kollisionen die überprüft werden müssen. Eigene Asserts Da das Ergebnis meist in Form eines Vector2 vorliegt haben wir eine Assert Methode geschrieben, welche überprüft ob zwei Vektoren gleich sind 1 11

18 public static void assertequalsext(rectangle expected, Rectangle actual, float epsilon) { boolean a =!fcomp(expected.x, actual.x, epsilon); boolean b =!fcomp(expected.y, actual.y, epsilon); boolean c =!fcomp(expected.width, actual.width, epsilon); boolean d =!fcomp(expected.height, actual.height, epsilon); } if (a b c d) { throw new AssertionFailedError("expected:<" + expected + "> but was:<" + actual + ">" ); } private static boolean fcomp(float expected, float actual, float delta) { return Float.compare(expected, actual) == 0 (Math.abs( expected - actual) <= delta); } Da wir hier Gleitkommazahlen vergleichen, welche eine endliche Genauigkeit haben, muss ein epsilon Wert eingeführt werden. Dieser ist die maximale Abweichung die zwei floats haben dürfen um noch als gleich angesehen zu werden. Parametrisierte Tests Ein Feature von junit 4, dass wir benutzen sind die parametrisierten Tests 1. Hierbei führt man einen Test mehrmals unter verschiedenen Voraussetzungen aus. Wir benutzen dies intensiv bei den Tests der Kollisionserkennung. Jeder Kollisionstest wird mit mehreren verschiedenen Collisionmap-GröSSen ausgeführt. Einmal mit normal grosser Map, einmal mit einer Map der GröSSe 1x1 und auch noch mit verschiedenen anderen GröSSen. Dies erhöht zwar die Anzahl der auszuführenden Tests stark, sorgt jedoch dafür, dass es wahrscheinlicher wird Fehler zu erkennen. Und bei Unittests ist die Performance in soweit nicht sehr wichtig da sie nur ab und zu auf dem Entwicklerrechner oder dem CI-Server ausgeführt werden. Android Build Probleme Ein Problem, dass wir mit junit jedoch hatten war der Android Build Vorgang. Anfangs waren all unsere Unittests in dem absgdx-framework Projekt. Deshalb war dieses Projekt von junit abhängig und 1 https://github.com/junit-team/junit/wiki/parameterized-tests 12

19 junit ist seinerseits von der Hamcrest Bibliothek abhängig 1. Das Android Projekt android, dass wir zum Kompilieren für Android verwenden ist von den Android Libraries und absgdx-framework abhängig. Problematisch wird es hier jedoch da auch die Standard Android Libraries Hamcrest enthalten und Hamcrest im root Ordner der jar/apk eine Datei LICENSE.txt anlegen will. Der Android Compiler verbietet es jedoch, dass zwei Libraries die gleiche Datei anlegen wollen (auch wenn es in diesem Fall zweimal die gleiche Bibliothek ist). Gradle hat hierfür eine Lösung. Mit der Einstellung packagingoptions.exclude kann man Dateien aus dem Paket ausschliessen. Der Eclipse Compiler ist jedoch nicht so intelligent und somit führt das alles dazu, dass wir nur noch mit gradle das Android projekt bauen können und nicht mehr direkt in Eclipse. Die Lösung hierfür bestand darin die Unittests in ein eigenes Projekt absgdx-test auszulagern welches von absgdx-framework abhängig ist. Somit ist absgdx-framework selbst nicht mehr von junit und hamcrest abhängig und das Projekt android bekommt die hamcrest-bibliothek nur noch einmal eingebunden Continuous Integration gzusammen mit den Unittests und Git wenden wir auch noch eine dritte Praktik an: Continuous Integration. Jedes mal wenn jemand auf den main-branch unseres Repositories pushed wird automatisch ein Skript auf einem Buildserver ausgeführt. Dieses Skript cloned die Repository lokal auf den Buildserver und versucht den Code zu kompilieren. Dies wird zusätzlich vereinfacht durch unsere Benutzung von Gradle und dem gradlewrapper. Wir müssen nur gradlew mit den jeweiligen Parametern aufrufen und Gradle lädt automatisch alle benötigten Dependencies nach und buildet das Projekt. Als Buildserver benutzen wir den kostenlosen Online-Buildservice TravisCI 2 welcher mit einer Textdatei ".travis.yml" im Repository root konfiguriert wird. language: java before_install: - chmod +x gradlew install:./gradlew desktop:assemble 1 2 https://travis-ci.org/mikescher/absgdx 13

20 script: -./gradlew absgdx framework:check -./gradlew absgdx test:check -./gradlew core:check -./gradlew desktop:check notifications: recipients: - - on_success: always on_failure: always Unser Skript ruft zuerst das OS command chmod -x auf der gradlewrapper Datei auf um sicherzustellen, dass wir die Rechte haben die Datei auszuführen. Dies ist nötig da unser CI Server Linux als Betriebssystem hat. Danach wird als erster Befehl gradlew desktop:assemble aufgerufen. Dies führt den gradle Task desktop:assemble aus, es wird versucht das Projekt zu einer jar zu kompilieren. Schlägt dies fehl, weil zum Beispiel gepushed wurde ohne den Code vorher getestet zu haben, dann schlägt das ganze Skript fehl und es wird eine an alle recipients geschickt. Eigentlich müsste an dieser Stelle auch android:assemble aufgerufen werden, leider ist dies auf dem Linux Server von Travis nicht möglich. Den Fall, dass das Projekt nur auf Android nicht mehr lauffähig ist haben wir also nicht automatische abgedeckt und dies müssen wir manuell testen. Nach dem erfolgreichen Build Vorgang werden die anderen Punkte unter script abgearbeitet. Hier liegt die zweite Stärke von Continuous Integration wir führen für alle Subprojekte die Unittests aus, vor allem für absgdx-test, in welchem sich alle Tests unseres Frameworks befinden. Es ist also gesichert, dass bei jedem Push auf den Main Branch automatisiert überprüft wird, ob das Projekt "broken" ist, sowohl vom reinen Compiler Standpunkt als auch von den Unittests her und in beiden Fällen werden alle Teilnehmer des Projektes jeweils per über den Zustand informiert. Zusätzlich können sowohl Teilnehmer des Projektes als auch Personen die es benutzen wollen sich online den aktuellen Zustand ansehen: 14

21 Abbildung 5: Beispiel der Online Ansicht von TravisCI Metrics Code Metrics Um eine Übersicht über den aktuellen Stand unseres Codes zu erhalten setzten wir das Metrics Tool Metrics ein. Abbildung 6: absgdx Metrics Es zeigt eine Reihe an Statistiken über den Quellcode an und warnt wenn Teile des Codes komplex 15

22 werden. Die Warnungen sind jedoch nicht immer korrekt, in unserem Beispiel sind drei Methoden mit Problemen markiert, wir haben uns jedoch bei allen drei entschieden sie so zu lassen. Zwar sehen sie rein statistisch sehr komplex aus, jedoch sind sie aus einer menschlichen Sichtweise sehr gut zu lesen. Trotzdem sind die Metriken nützlich um schnell und einfach einen Überblick über den aktuellen Stand zu bekommen und eventuelle Problemstellen zu identifizieren Test Coverage Da wir Unit Tests mit junit einsetzen, ist eine interessante Frage wie viele Statements von den Unit Tests abgedeckt werden. Das Code Coverage Tool EclEmma analysiert hierfür unsere Tests und zeigt - nach Paket sortiert - jeweils an wie viele Statements abgedeckt sind Abbildung 7: absgdx Test Coverage Wie hier zu sehen ist haben wir keine hundert prozentige Testabdeckung. Trotzdem sind wichtige und fehleranfällige Pakete wie collisiondetection, math oder mapscaleresolver fast vollständig abgedeckt. Für die Zukunft kann es durchaus von Vorteil sein noch mehr des Quellcodes mit Tests abzudecken. Jedoch sind vorerst die wichtigsten Methoden schon abgedeckt JavaDoc Da unser Ziel es ist ein Framework zu entwickeln, dass auch von anderen Entwicklern genutzt wird dokumentieren wir alle öffentlichen Methoden. Mithilfe des Dokumentationswerkzeugs javadoc kann man aus diesen Quellcode Kommentaren HTML Dokumentationsseiten erzeugen. Im nachfolgenden möchte ich 16

23 die verschiedenen Schritte und Werkzeuge aufzeigen welche wir benutzen um eine Dokumentationsseite automatisch online zu hosten. Die eigentlichen Dokumentationskommentare sind als Kommentare in den Quellcodedateien vorhanden und werden somit auch in unser git Repository commited. Unsere IDE Eclipse hilft uns dabei die Kommentare syntaktisch korrekt nach den javadoc Vorgaben zu schreiben, so dass diese später geparsed werden können. Das Erzeugen der entsprechenden HTML, CSS, und JS Dateien wird komfortabler Weise von gradle übernommen. Im gradle Plugin java gibt es den Task javadoc und mit dem folgenden Befehl kann man sich einfach eine javadoc Webseite generieren lassen: > gradlew absgdx-framework:javadoc Die nächste Frage ist wo man das javadoc hosten soll. Hierfür gibt es bei unserem git Hoster GitHub die sogenannten GitHub-pages. Mit ihnen kann man eine beliebige HTML Seite für jede Repository anlegen. Dafür pushed man die entsprechenden Dateien in ein eigenen Branch gh-pages. Unter der URL kann man dann auf diese Webseite zugreifen. In unserem Fall kann man unter online die Dokumentation einsehen. Trotzdem ist es müssig nach jeder Änderung die Dokumentation neu zu erstellen und hochzuladen. Dieser Prozess wartet nur darauf, dass man dies irgendwann einmal vergisst. Wir können jedoch unser Continuous Integration Skript verwenden um nicht nur das Projekt zu überprüfen sondern auch um automatisiert bei jedem push auf das Repository die javadoc Dateien zu aktualisieren. Hierfür legen wir in dem Ordner ".utility" das Bash Skript "push-javadoc-to-gh-pages.sh" an. In unserer ".travis.yml" Konfigurationsdatei müssen wir dann nach einem erfolgreichen Test zuerst das javadoc erzeugen und dann die Dateien per git commiten. Ein Problem ist dabei, dass wir vom TravisCI Server aus keine Rechte haben auf unser Repository zu pushen. Deshalb generieren wir für unser Repository ein Access Token und geben dieses verschlüsselt in unserem Skript an. Dies ist möglich da TravisCI automatisch für jede Repository ein RSA Schlüsselpaar generiert. Unser Token haben wir nun mit dem Public Key verschlüsselt und nur Travis kann ihn mit dem Private Key wieder entschlüsseln. Somit sind wir sicher davor, dass sich jemand anders die (öffentliche) ".travis.yml" Datei ansieht und den Access Token missbraucht. language: java env: global: 17

24 - secure: "?? encrypted??" before_install: - chmod +x gradlew - chmod +x.utility/push-javadoc-to-gh-pages.sh after_success: -./gradlew absgdx-framework:javadoc -.utility/push-javadoc-to-gh-pages.sh In unserem eigentlichen Skript überprüfen wir zuerst einmal ob wir auch wirklich die aktuelle Dokumentation commiten wollen. Zuerst muss der Commit auf dem richtigen Repository erfolgt sein, zur Sicherheit damit niemand aus versehen das Skript forked und dann auf seiner Repository ausführt. Au- SSerdem muss es ein Commit auf dem Branch master sein und ein echter push (nicht nur ein Pull Request). Danach kopieren wir die generierten Dateien in das Verzeichnis "tmp_jd" und klonen mit dem imaginären Benutzer "travis-ci" und unserem Access Token den aktuellen Zustand der Branch gh-pages. Die gerade geklonten Dateien löschen wir jedoch sofort wieder und ersetzen sie mit den Neuen. Für unveränderte Dateien ist das effektiv eine No-Operation, nur geänderte Dateien wurden mit den neueren Versionen ersetzt. Diese geänderten Exemplare werden dann mit "git add" zum index hinzugefügt. Danach werden sie mit "git commit" committed und mit "git push" zum Remote (Github) gepushed. if [ "$TRAVIS_REPO_SLUG" == "Mikescher/absGDX" ] && [ " $TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == " master" ]; then cp -R absgdx-framework/build/docs/javadoc $HOME/tmp_jd cd $HOME git config --global user. git config --global user.name "travis-ci" git clone --branch=gh-pages Mikescher/absGDX gh-pages cd gh-pages git rm -rf./javadoc cp -Rf $HOME/tmp_jd./javadoc git add -f. git status git commit -m "Lastest javadoc on successful travis build 18

25 fi $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages" git push -f origin gh-pages 3.2 Das Framework Tiled Map Als Karte benutzt absgdx ein Tiled-Map System. Die Karte ist unterteilt in viele einzelne quadratische Tiles. Jedes Tile hat eine eigene Textur und zusammen bilden sie die Karte. Die Texturen kommen meist aus einer sogenannten Tilemap in der eine grosse Anzahl an Texturen in einer einzigen Datei zusammengefasst sind. Abbildung 8: Visualisierung einer Tiled Map In absgdx wird eine solche Map durch eine Instanz der Klasse TileMap repräsentiert. Diese Klasse verwaltet intern seine einzelnen Tiles in einem zweidimensionalen Array und bietet Methoden um Tiles 19

26 abzufragen oder zu ändern. Die einzelnen Tiles müssen von der abstrakten Klasse Tile abgeleitet werden. Man kann seine Tiles entweder direkt von dieser Klasse ableiten oder eine Unterklasse benutzen die jeweils für speziellere Fälle zugeschnitten sind: AnimationTile Wenn von AnimationTile abgeleitet wird kann man der Tile nicht nur eine statische Textur zuweisen sondern eine sich wiederholende Animation EmptyTile EmptyTiles sind Tiles ohne Textur oder Logik - sie werden standardmässig für neue Maps eingesetzt StaticTile StaticTiles haben eine statische Textur und keine Logik, rein-grafische Tiles könne hiervon abgeleitet werden AutoTile AutoTiles sind nützlich in Zusammenhang mit aus Dateien geladenen Maps, sie beziehen ihre Textur automatisch aus der gegebenen Tilemap Ermitteln der absoluten GröSSe Intern besitzen alle Tiles die Dimension 1.0 x 1.0. Beim eigentlichen Anzeigen müssen diese Werte jedoch auf eine konkrete Pixelzahl skaliert werden. Dies kann komplex werden da besonders mobile Geräte in einer Vielzahl an Auflösungen und Verhältnissen kommen. AuSSerdem kann es anwendungsspezifische Vorgaben geben, wie beispielsweise eine minimale Anzahl an Tiles die auf jeden Fall sichtbar sein sollten. Um dies zu lösen gibt es verschiedene Ansätze, jeweils repräsentiert durch eine Klasse abgeleitet von AbstractMapScaleResolver. Ein MapScaleResolver berechnet aus den Kartendimensionen und den Dimensionen des Anzeigegerätes die echte Höhe und Breite eines Tiles in pixel. StandardmäSSig sind in absgdx sechs verschiedene MapScaleResolver enthalten: FixedMapScaleResolver Dies ist der einfachste MapScaleResolver, er gibt immer eine konstante, vorher bestimmte GröSSe zurück. (zum Beispiel 60px) 20

27 Abbildung 9: Visualisierung des FixedMapScaleResolver ShowCompleteMapScaleResolver Hier wird immer die komplette Karte angezeigt, falls das Verhältnis von Kartenbreite und Höhe nicht mit dem des Anzeigegerätes übereinstimmt gibt es Teile des Bildschirms die nicht von der Karte bedeckt sind. 21

28 Abbildung 10: Visualisierung des ShowCompleteMapScaleResolver MaximumBoundaryMapScaleResolver Bei dieser Lösung wird eine Grenzfläche festgelegt die immer angezeigt wird, beispielsweise drei mal drei Tiles. Es kann vorkommen dass mehr Tiles angezeigt werden (z.b.: 3x3.5 Tiles), es ist jedoch garantiert, dass die Grenzfläche selbst immer zu sehen ist. 22

29 Abbildung 11: Visualisierung des MaximumBoundaryMapScaleResolver MinimumBoundaryMapScaleResolver Dies ist das Gegenstück zum MaximumBoundaryMapScaleResolver. Hier wird eine Grenzfläche festgelegt die nie überschritten wird. Ist diese zum Beispiel 10x5 Tiles kann es sein, dass nur 10x3 angezeigt werden - es wird aber nie mehr als die Grenzfläche gezeigt und immer versucht sich dieser soweit wie möglich anzunähern ohne die Karte zu verzerren. 23

30 Abbildung 12: Visualisierung des MinimumBoundaryMapScaleResolver LimitedMinimumBoundaryMapScaleResolver Dieser MapScaleResolver baut auf dem MinimumBoundaryMapScaleResolver auf. Er nimmt zuerst die gleichen Regeln wie dieser, beinhaltet aber einen Ausnahmefall. Es ist wird niemals mehr als x Prozent der ursprünglichen Grenzfläche weggeschnitten. Diese Regel hat eine höhere Priorität als die minimale Grenzfläche und somit kann es dazu kommen, dass eben doch mehr als die Grenzfläche gezeigt wird. 24

31 Abbildung 13: Visualisierung des LimitedMinimumBoundaryMapScaleResolver SectionMapScaleResolver Dies ist eine nochmalige Erweiterung des LimitedMinimumBoundaryMapScaleResolver. Neben der maximalen Schnittfläche gibt es hier jetzt auch noch eine minimale GröSSe eines Tiles. Ein Tile kann niemals kleiner als eine angegebene Anzahl Pixel werden, diese Regel hat die höchste Priorität und kann gegebenenfalls die anderen beiden ausser Kraft setzen. 25

32 Abbildung 14: Visualisierung des SectionMapScaleResolver Das Rendern Das Rendern der Karte wird von dem aktuellen Layer übernommen, dies ist in den meisten Fällen ein GameLayer da nur dieser eine TiledMap besitzt. In den meisten Fällen ist nicht die ganze Map sichtbar da der aktuelle MapScaleResolver die Tiles gross genug macht um mehr als das gesamte Display auszufüllen. Deshalb gibt es im GameLayer einen MapOffset. Dieser gibt an wie weit die Karte in X und Y Richtung verschoben ist. Beim Rendern ist nun darauf zu achten, dass man nur die Tiles rendert die ganz oder teilweise sichtbar sind, man könnte zwar auch einfach alle anzeigen dies wäre jedoch nicht sehr performant. Es ist jedoch einfach zu berechnen welche Tiles aktuell sichtbar sind: (2) S 232f. public Rectangle getvisiblemapbox() { float tilesize = mapscaleresolver.gettilesize(owner. getscreenwidth(), owner.getscreenheight(), map.height, map. width); 26

33 Rectangle view = new Rectangle(map_offset.x, map_offset.y, owner.getscreenwidth() / tilesize, owner.getscreenheight() / tilesize); } return view; Laden aus dem TMX Format TileMaps kann man mit dem Programm Tiled erstellen 1 welche TMX Dateien erstellt. Da dies ein bekanntes Format ist habe wir auch in absgdx die Funktion implementiert solche Dateien zu laden. Eine TMX Datei ist eine einfache xml Datei mit einem vorgegebenen Format 2 : <?xml version="1.0" encoding="utf-8"?> <map version="1.0" orientation="orthogonal" width="128" height="128" tilewidth="16" tileheight="16"> <layer name="kachelebene 1" width="128" height="128"> <data encoding="base64" compression="gzip"> H4sIAAAAAAAAC72d2Z5r13HeD/DtFs1zlMFJbjLcA== </data> </layer> </map> TMX unterstützt verschiedene Karten und TilegröSSen, mehrere Layer und auch fest eingebundene Tilesets. Die eigentlichen Daten sind entweder in XML, CSV oder als base64-binär Daten kodiert. Zusätzlich kann entweder keine, gzip oder zlib Kompression vorliegen 3. Als XML Parser haben wir uns für die XMLReader Library entschieden, welche schon in LibGDX integriert ist und auf allen Zielplattformen funktioniert. XMLReader ist ein java-xml-dom Parser, dies bedeutet, dass die komplette Datei analysiert und in den Speicher geladen wird. Dies macht das Auswerten der Datei sehr einfach, verbraucht aber mehr Arbeitsspeicher als beispielsweise ein SAX-Parser. Da die TMX Dateien jedoch nicht sehr gross sind im Verhältnis zum gewöhnlich verfügbaren Arbeitsspeicher sollte dies keine Probleme bereiten. Das Parsen einer TMX Datei wird von der Klasse TmxParser übernommen. Nach dem Laden der XML Datei geht dieser zuerst die einzelnen Layer von dem niedrigsten angefangen durch. Für jeden https://github.com/bjorn/tiled/wiki/tmx-map-format#data 27

34 Layer müssen die Daten dekodiert werden. Sind sie in gzip oder zlib komprimiert muss man sie zuerst dekomprimieren. Sind die Daten dann in XML kodiert kann der XOM Parser einfach ebenfalls die Daten parsen. Auch CSV kodierte Daten können recht einfach mit der in java enthaltenen String.split Funktion analysiert werden. Bei Base64 Daten ist der Prozess jedoch komplizierter. Zuerst muss der String als Reihe von Bytes interpretiert werden. Danach gruppiert man jeweils 3 bytes zusammen und interpretiert sie als Little-Endian unsigned 32bit-Integer. Der entstehende Int32-Array sind dann die GIDs der Tiles. In allen 3 Fällen erhält man einen Integer Array. Die einzelnen Integer sind die sogenannten GIDs, welche den Tiletyp eindeutig identifiziern (anhand der Texturposition im Tileset). Die GIDs fangen bei 1 an, eine 0 bedeutet "kein Tile". Unser TmxParser erstellt dann für jede GID die entsprechende Tile und bildet aus ihnen eine TileMap. Die Zuordnung von GID und Tile-Klasse muss der Entwickler bestimmen. Er kann dafür mit der Methode addmapping(int, class) eine GID einer bestimmten Tile-Klasse zuordnen. Beim Erstellen der Map wird dann jeweils nach einer solchen Zuordnung gesucht. Falls es eine gibt wird mittels java Reflection der Konstruktor der Klasse ermittelt und eine neue Instanz erzeugt. Dafür ist es notwendig dass alle Klassen die von Tile ableiten entweder einen Konstruktor ohne Parameter haben oder einen der eine Settingsmap nimmt. Eine Settingsmap ist eine Hashmap<String, String> in welcher verschiedene Informationen über das Tile enthalten sind wie Position, GID, MapgröSSe etc. Falls vorhanden wird immer der Konstruktor mit der Hashmap genommen, nur falls dieser nicht existiert wird der leere benutzt. Eine geschickte Verwendung dieser Mechanik ist beispielsweise die AutoTile Klasse. Setzt man im Mapping diese Klasse als Default Mapping ein und sonst keine andere Klasse werden alle GIDs auf AutoTile gemappt. Die AutoTile Klasse hat dann einen Konstruktor mit einer Settingsmap und berechnet aus der darin enthaltenen GID zurück welche Textur im TILED MapEditor verwendet wurde. Man verliert zwar somit die Möglichkeit unterschiedlichen Tiles speziellen Code zuzuordnen, braucht jedoch bei einem grossen Tileset nicht sehr viele Klassen die sich kaum unterscheiden. Man muss dem Programm nur die Tilmap und das Tileset zur Verfügung stellen und kann die Karte direkt mit Grafiken in das Programm laden Entity System Unser GameLayer besteht bisher nur aus einer Karte, dem Hintergrund. Zusätzlich werden aber auch noch Objekte auf dem Spielfeld benötigt, wir nennen diese Objekte die Entities. Jede Entity ist von der 28

35 Klasse Entity abgeleitet und muss im aktuell aktiven GameLayer über die Methode addentity(entity e) hinzugefügt wird. Der GameLayer übernimmt dann die Verwaltung des Lebenszyklus aller Entities. Abbildung 15: Lebenszyklus eines einzelnen Entities Jede Entity hat ein alive Feld welches am Anfang auf true gesetzt wird, das Entity ist solange aktive bis das Feld auf false gesetzt wird und das Entity im nächsten Zyklus entfernt. Entities besitzen, neben dem alive Attribut, eine Reihe weiterer Eigenschaften welche sie definieren. Sie besitzen eine eindeutige zweidimensionale Position und eine Höhe und Breite, ihre Grundform ist somit ein einfaches Rechteck. AuSSerdem verwalten sie ihre aktuelle Geschwindigkeit und Beschleunigung um ein einfaches Interface zur flüssigen Bewegung zu bieten. Zuletzt kenne sie auch noch die Textur, oder Texturen, welche sie zeichnen sollen. 29

36 Rendering Jedes Entity bestimmt selbst wie es gerendert wird, hierfür kann ein Entity entweder eine einzelne statische Textur haben oder einen Array von Texturen welcher als Animation gerendert wird. AuSSerdem stehen Optionen zur Verfügung wie Drehung oder Verzerrung der Textur. Auch muss die gezeichnete Textur nicht mit der Position oder den AusmaSSen des eigentlichen Entities übereinstimmen, theoretisch kann vollkommen frei auf dem aktuellen OpenGL Kontext gezeichnet werden. Zusätzlich hat jede Entity auch noch einen Z-Layer gesetzt welcher bestimmt welche Entities im Vordergrund und welche im Hintergrund gezeichnet werden. Besetzen zwei Entities, beziehungsweise deren Texturen, ganz oder teilweise den selben Punkt wird die Entity mit dem grösseren T-Layer über der anderen gezeichnet. Die Verwaltung hiervon übernimmt der GameLayer. Collision Detection Ein wichtiges Feature der Entities ist es Kollisionen mit anderen Entities zu erkennen, auf die technischen Einzelheiten wird im Paragraph Kollisionserkennung genauer eingegangen. Aus der Sicht eines Entities ist es einfach, so dass man mithilfe der Methode addcollisiongeo(float relativex, float relativey, CollisionGeometry geo) dem Entity eine Kollisionsgeometrie zuordnen kann. Diese kann Kollisionen mit anderen Kollisionsgeometrien erkennen. Der Vorteil dieser Methode ist es, dass Programme die ganz oder teilweise keine Kollisionserkennung brauchen keinen Performance Nachteil haben wenn diese (unnütz) im Hintergrund berechnet wird. In den meisten Fällen werden jedoch keine sonderlich komplexen Geometrien eingesetzt und noch seltener hat ein Entity mehrere Geometrien, die ihm zugeordnet sind. Deshalb gibt es drei Methoden um schnell und einfach die gebräuchlichsten Fälle abzudecken: addfullcollisionbox(): Fügt ein Kollisions Rechteck hinzu mit gleichen AusmaSSen wie das Entity addfullcollisioncircle(): Fügt ein Kollisions Kreis hinzu, welcher das Entity komplett ausfüllt addfullcollisiontriangle(aligncorner4 align): Fügt ein Kollisions Dreieck hinzu, welches drei Ecken des Entities benutzt (Abhängig von dem übergebenen Alignment). 30

37 Jede dieser Geometrien wird zwar wiederum vom GameLayer verwaltet, kennt aber sein jeweiliges Vater-Entity. Und sobald eine Kollision erkannt wird, wird das Entity über eine Event-Methode benachrichtigt. Dies ist im Grunde ein Listener-Pattern bei dem das Entity automatisch als Listener als seiner Geometrien eingetragen wird, hierfür besitzt jedes Entity auch die Interfaces CollisionListener und CollisionGeometryOwner. Über das Interface CollisionListener werden vier Methoden implementiert: onactivecollide onpassivecollide onactivemovementcollide onpassivemovementcollide Das active bedeutet jeweils, dass die Kollision durch eine Bewegung der eigenen Geometrie ausgelöst wurde, und das passiv entsprechend dass der Grund die Bewegung der anderen Geometrie war. Ist die Veränderung der Position Teil einer Bewegung wird die Methode onactivemovementcollide oder on- PassiveMovementCollide aufgerufen. Wurde vorher festgelegt, dass die beiden Entities sich nicht überschneiden dann entspricht dies einem ZusammenstoSS, bei dem das bewegende Entity zum Stillstand gekommen ist und als Resultat beide Entity sich nur berühren nicht schneiden. Ist dies andererseits das Resultat eines direkten Aufrufs von setposition(float x, float y), dann werden die Methoden onactivecollide oder onpassivcollide aufgerufen. Framerate unabhängige Bewegung Eine der grundsätzlichen Aufgaben eines Entities ist es sich zu bewegen. Als Benutzer dieses Frameworks hat man dazu zwei grundsätzliche Optionen. Einerseits kann man über setposition(float x, float y) das Entity in jedem Update Zyklus manuell auf eine Position setzen. Dies hat jedoch Nachteile. Man muss sich bei dieser Methode selbst darum kümmern, dass die Bewegung unabhängig von der Updaterate ist, denn auch mit nur halb so vielen Updates pro Sekunde sollte sich jedes Entity immer noch gleich schnell bewegen. Andernfalls wäre das Spiel nur auf einem Rechner mit gleichen oder ähnlichen UPS Updates per second wie denen des Entwicklerrechners spielbar. AuSSerdem erschwert dies das Programmieren der allgemeinen Spiellogik. In den meisten Fällen denkt man über Objekte nicht in der Form von "An 31

38 diesem Zeitpunkt sind sie an diesem Ort" sondern eher mit welcher Geschwindigkeit sie sich in welche Richtung bewegen oder wie stark sie beschleunigen. Um dies zu Lösen hat unser Entity - wie oben schon erwähnt - die Eigenschaften speed und List<accelerations>. Als Programmierer kann man nun entweder den Vektor Geschwindigkeit (speed) beeinflussen um dem Entity eine Geschwindigkeit und eine Richtung vorzugeben, oder man gibt ihm eine oder mehrere Beschleunigungen (accelerations) welche ihrerseits wiederum Vektoren sind welche die Geschwindigkeit beeinflussen. Die genaue Berechnung der Position wird dann von Entity selber übernommen und Framerate unabhängig berechnet. Ein zusätzlicher Vorteil dieses Weges ist, dass man besser mit Kollisionen arbeiten kann. Hat man festgelegt, dass sich zwei Entities nicht überschneiden dürfen, dann bewegen sich diese nicht ineinander. Es werden die Entities stattdessen nur soweit bewegt bis sie sich berühren und danach wird die Geschwindigkeit auf null gesetzt. Intern wird deshalb nach jedem update() die Methode updatemovements(float delta) aufgerufen. delta ist hierbei die Zeit (in millisekunden) die seit dem letzten Update vergangen ist, bei 60 FPS sollte die ungefähr 17 ms sein. Zur Sicherheit ist dieser Wert bei 100ms gedeckelt. Damit einzelne Lag Spikes nicht dazu führen, dass innerhalb eines Frames Objekte eine sehr grosse Distanz zurücklegen, dies würde auch die Kollisionserkennung stark beeinträchtigen. Beweis Korrektheit Die Bewegung ist im Framework wie folgt implementiert: private void updatemovement(float delta) { for (Vector2 acc : accelerations) { speed.x += acc.x * delta; speed.y += acc.y * delta; } if (movepositionx(this.speed.x * delta)) { // Collision appeared speed.x = 0; } if (movepositiony(this.speed.y * delta)) { // Collision appeared speed.y = 0; } } 32

39 Das erste was wir uns klarmachen müssen ist, dass wir die Bewegungen beziehungsweise Beschleunigungen in X und Y Richtung unabhängig betrachten. Somit können wir das Problem auf eindimensionale herunterbrechen. Fassen wir zusammen was wir im obigen Code tun: Zuerst bilden wir die Summe aus allen Beschleunigungen um eine Gesamtbeschleunigung zu erhalten Die Geschwindigkeit erhalten wir dann indem wir die Beschleunigung mit delta multiplizieren und zur bisherigen Geschwindigkeit addieren. Genauso erhalten wir die neue Position in dem wir zur alten Position die aktuelle Geschwindigkeit multipliziert mit delta addieren a = k a i i=1 v n = v n 1 + a n t x n = x n 1 + v n t Schauen wir uns im Vergleich dazu die echten physikalischen Zusammenhänge an. Der wesentliche Unterschied ist, dass diese sich in einem kontinuierlichen System befinden und wir in unserer Simulation nur diskrete Zeitabschnitte haben (von der Breite 16ms). a(t) = k i=1 v(t) = v 0 + x(t) = x 0 + a i (t) t 0 t 0 a(t) dt v(t) dt Die Berechnung von Geschwindigkeit v und Position x benötigt jeweils ein Integral über eine kontinuierliche Funktion, da wir uns aber in einem Zeit diskreten Raum befinden könne wir hierfür das Riemann-Integral einsetzen (4). 33

40 Abbildung 16: Riemann-Integral über die Beschleunigung eiens Entities Dies berechnet ein Integral indem es in Abschnitte unterteilt wird und für diese Abschnitte Rechtecke bildet. Da wir in unserem Fall im Zeitpunkt t immer die Werte im Zeitraum [t t,t) berechnen brauchen wir das Obersummen Riemann Integral. a(t) = k i=1 v(t) = v 0 + x(t) = x 0 + a i (t) t 0 t 0 a(t) dt v(t) dt Aktuell sind dies jedoch noch zeit kontinuierliche Gleichungen, wir wollen diese in zeit diskrete Sequenzen mit SchrittgröSSe t umwandeln. Aus der Variable t wird dabei der Schrittzähler n. Aus dem Riemann Integral wird die Summe über alle bisherigen Rechtecke, also jeweils Wert an der Position i mal Breite des i-ten Schrittes. 34

41 a n = k a n,i i=1 n v n = v 0 + x n = x 0 + i=1 n i=1 a i t i v i t i Als letzten Schritt können wir eine Vereinfachung vornehmen. (1) können wir auch als (2) schreiben indem wir das Riemann Integral aufteilen. Und der vordere Teil von (2) ist äquivalent zu v n 1 womit man (1) auch als (3) schreiben kann. v n = v 0 + n i=1 a i t i (1) n 1 v n = v 0 + a i t i + a n t (2) i=1 v n = v n 1 + a n t (3) Daraus ergeben sich dann also die Formeln a n = k a i i=1 v n = v n 1 + a n t x n = x n 1 + v n t Welches wieder unserem ursprünglichen Algorithmus entspricht. Wir haben also bewiesen, dass unabhängig von der Update rate unser Algorithmus im Zeit diskreten Raum für t 0 korrekt ist. Zwar ist t in unserem Fall grösser null, jedoch stimmt unsere Simulation annähernd immer noch mit der Realität überein, und mehr wollten wir ja auch nicht erreichen. Es ist noch festzuhalten, dass damit auch die Einheiten der einzelnen Attribute klar ist. Die Position wird in Tiles festgehalten und die Geschwindigkeit somit in Tiles s und die Beschleunigung entsprechend 35

42 in Tiles s 2. Spezielle Entities Wie schon zuvor gesagt müssen alle Entities von der Stammklasse Entity abgeleitet werden. Zur Vereinfachung gebräuchlicher Fälle gibt es schon vorbereitet abstrakte Kindklassen, von welchen man wieder ableiten kann. Abbildung 17: Spezielle Entities SimpleEntity Leitet man von der Klasse Entity muss man eine Vielzahl an Methoden zwangsweise Überschreiben (da diese als abstract markiert sind). Möchte man jedoch ein simples, statisches, rein visuelles Entity implementieren kommt man in die Situation alle oder viele überschriebene Methoden einfach leer zu lassen. Stattdessen kann man von SimpleEntity ableiten, diese Klasse hat alle sinnvollen Methoden schon überschrieben und Handler/Listener leer gelassen beziehungsweise Standardwerte zurückgeben lassen. Möchte man trotzdem auf einige diese Events reagieren oder bei einigen Methoden andere Werte zurückgeben kann man diese immer noch überschreiben, standardmässig existiert jedoch kein Zwang diese zu 36

43 implementieren. Gerade deshalb sollte man dies jedoch nur machen wenn man schon Erfahrung mit dem Framework hat und mit Sicherheit weiss was es bedeutet auf keines der Events sinnvoll zu reagieren. PhysicsEntity Die PhysicsEntity implementiert zusätzlich einige physikalische Eigenschaften auf die Entities. Aktuell ist es jedoch nur die Schwerkraft. Diese wird als eigene Beschleunigung in die Liste der Beschleunigungen aufgenommen und erhält einen Wert entsprechend der gesetzten Masse. Setzt man die Masse des PhysicEntities auf null, entspricht es komplett einem normalen Entity, da die Gewichtskraft ein Nullvektor ist Layer System Unser Spiel kann sich während seiner Laufzeit in verschiedenen Phasen befinden. Darunter zum Beispiel eine Level laden Phase, eine Hauptmenü Phase oder eine Spiel Phase. Die Verwaltung dieser Phasen erfolgt über die sogenannten Layer. Alles in einem absgdx Programm muss sich innerhalb eines Layers befinden, standardmässig gibt es den MenuLayer und den GameLayer es können jedoch auch eigene Layer von der Stammklasse AgdxLayer abgeleitet werden. Zu jedem Zeitpunkt ist nur ein Layer aktiv, dieser bekommt sämtliche Eingabe Events mit und dessen update() und render() Methoden werden aufgerufen. Organisiert werden die verschiedenen Layer in einem Stack. 37

44 Abbildung 18: Der Layer Stack Diese Organisation hat vor allem beim Menübaum Vorteile: Geht man - wie im obigen Beispiel - vom Hauptmenü in das Levelmenü ist das Hauptmenü immer noch auf dem Stack, jedoch nicht mehr TOS (Top of Stack) und wird somit nicht gerendert. Verlässt man nun aber das Levelmenü wieder, beispielsweise über den Zurück Knopf muss nur der oberste MenuLayer vom Stack entfernt werden und man ist wieder zurück auf dem Hauptmenü. Auch wenn man im oberen Beispiel das Spiel verlässt landet man automatisch wieder zurück im Levelmenü um von dort aus entweder ins Hauptmenü zu gehen oder ein neues Level zu starten. Für diese Operationen gibt es in der Klasse AgdxGame die Methoden pushlayer() und poplayer(). Falls diese ganze Funktionalität nicht erwünscht ist, kann auch einfach die Methode setlayer() benutzt werden. Diese leert den kompletten Stack und setzt den neuen Layer als einziges Element auf ihn. Verwendet man konsistent nur die Methode setlayer() hat man keinerlei Funktionalitäten des Stacks und kann arbeiten als gäbe es eine einzige Variable welche festlegt welcher Layer aktuell benutzt wird. 38

45 Der GameLayer Der wohl wichtigste Layer ist der GameLayer. In ihm spielt sich das eigentliche Spiel ab. Um ein eigenes Spiel zu entwickeln muss man zuerst eine Klasse von GameLayer ableiten und auf den Layer Stack pushen. Der GameLayer sorgt für die Verwaltung der Entities, der Karte und auch der Kollisionsgeometrien auf welche in einem späteren Kapitel genauer eingegangen wird. Der Menü Layer Der MenuLayer stellt eine einzelne Menüseite dar. Er verwaltet seine einzelnen Komponenten und dessen Events. In einem späteren Kapitel wird genauer darauf eingegangen wie man ihn benutzt Kollisionserkennung Eine wichtige Funktionalität, die unser Framework übernehmen soll ist es Kollisionen zwischen Entities zu erkennen. Beispielsweise muss ein Spiel erkennen ob das Spieler-Entity gerade mit einem Gegner kollidiert oder ob die Kugel-Entities etwas treffen. Eine solche Kollisionserkennung kann man unterschiedlich komplex implementieren, da unser Framework als primäre Zielplattform jedoch mobile Geräte hat ist hierbei die Performance besonders wichtig. Das Ziel ist es nun ein Algorithmus zu entwickeln, welcher folgende Eigenschaften erfüllt: Der Algorithmus sollte auch bei vielen Entities auf der Karte noch schnell sein und die Update-Time nicht unnötig erhöhen Der Algorithmus sollte genau sein und weder False-Positives noch False-Negatives haben. Zwar kann es Anwendungen geben, wo eine genaue Erkennung nicht immer nötig ist, doch da unser Framework für eine Vielzahl an Anwendungen funktionieren soll muss der Algorithmus exakt sein. Es sollte möglich sein Entities ohne Kollisionserkennung hinzuzufügen ohne dass diese Einfluss auf die Update-Time haben. 39

46 Die CollisionGeometry Klasse Wir haben uns in unserem Ansatz dagegen entschieden die Kollision zwischen Entities direkt zu berechnen. Dies würde zwar die Handhabung des Frameworks vereinfachen würde aber auch zu einigen Problemen führen: Einerseits könnte es keine rein-visuellen Entities geben welche mit nichts kollidieren und keinen Einfluss auf die Performance haben. AuSSerdem kann es auf der anderen Seite auch keine Entities mit mehreren Bereichen geben welche jeweils einzeln kollidieren können. Stattdessen gibt es neben den Entities auf der Karte auch noch sogenannte CollisionGeometries welches die Elemente sind die miteinander kollidieren. Ein Entity kann nun ein- / kein-, oder mehrere CollisionGeometries haben und auf deren Kollisionen reagieren. Beispielsweise kann der Kopf einer Figur eine andere Hitbox als der Körper haben und anders auf eintreffende Kugeln reagieren. Jede Entity hat eine Liste mit von EntityCollisionGeometry. Dies ist ein einfacher Wrapper über die Klasse CollisionGeometry, die die Geometrie zusammen mit der relativen Position zum Entity enthält. public class EntityCollisionGeometry { public final Vector2 relativeposition; public final CollisionGeometry geometry; public EntityCollisionGeometry(Vector2 relativepos, CollisionGeometry geo) { super(); } this.relativeposition = relativepos; this.geometry = geo; } public void updateposition(float x, float y) { geometry.setcenter(x + relativeposition.x, y + relativeposition.y); } Jedes mal wenn das Entity eine Veränderung seiner Position erfährt wird updateposition() aufgerufen und auch die CollisionGeometry bewegt sich mit. Mit dieser Technik kann man auch komplexere Geometrie Gebilde bauen welche die Form des Entities beliebig genau annähern kann. (2) S

47 Abbildung 19: Beispiel eines Entities mit mehreren Hitboxen Aktuell gibt es drei verschiedene Arten von CollisionGeometry: CollisionCircle, CollisionBox und CollisionTriangle. In den meisten Fällen möchte man Hitboxen in der Form von Rechtecken, es kann jedoch überlegenswert sein nur Kreise zu verwenden da bei diesen die Kollisionsberechnung schneller ist. Oder eben Dreiecke da man aus diesen beliebige Polynome zusammenbauen kann. Dreiecke sollten jedoch nicht im ÜbermaSS verwendet werden da deren Kollisionen am aufwendigsten zu berechnen sind. CollisionCircle Der Kreis ist die einfachste CollisionGeometry, und bei Programmen mit vielen Entities sollte darüber nachgedacht werden nur Kreisgeometrien zu verwenden. Für den Fall Kollision Kreis-Kreis ist die Formel um zu berechnen ob sie sich schneiden sehr einfach: Abstand < (Radius 1 +Radius 2 ) was in unserem 41

48 Fall zu sqrt((x 1 x 2 ) 2 +(y 1 y 2 ) 2 ) < (r 1 +r 2 ) wird. Dies kann noch weiter optimiert werden indem man beide Seiten quadriert: x 1 x 2 ) 2 +(y 1 y 2 ) 2 < (r 1 +r 2 ) 2 (2) S 499. Dies liegt daran, dass eine Multiplikation um mehrere GröSSenordnungen schneller als eine Quadratwurzel ist, ersteres ist meist ein einzelner Maschinenbefehl. In unserem Projekt wird mit folgender Methode überprüft ob sich zwei Kreise schneiden: public boolean dogeometriesintersect(collcircle a, CollCircle b) { return fsquare(a.centerx-b.centerx) + fsquare(a.centery-b. centery) < fsquare(a.radius + b.radius); } Den Vorteil einer Kreis-Kreis Kollision kann man auch auf alle anderen Geometrien anwenden indem man alle Geometrien als umschliessende Kreise abschätzt und diese zuerst kollidieren lässt. Nur wenn die umschliessenden Kreise sich überschneiden muss man dann den komplizierteren Schritt machen und die genauen Geometrien kollidieren lassen. AuSSer der Kreis-Kreis Kollision gibt es auch noch das Problem zu erkennen ob sich eine Kreisgeometrie und einen Rechtecksgeometrie schneiden. Den Algorithmus um diese Kollision zu erkennen ist im nachfolgenden Paragraph "CollisionBox" beschrieben. Der dritte Fall ist die Kollision des Kreises mit einem Dreieck. Hier muss man 3 Fälle beachten. Entweder der Kreis schneidet einer der Ecken, eine der Kanten oder der Kreis ist komplett innerhalb des Dreieckes. Wieder verwenden wir hier den Trick den Abstand in quadriertem Zustand zu vergleichen da dies 2 Aufrufe von sqrt spart. Abbildung 20: 3 Möglichkeiten einer Kreis-Dreieck Kollision 42

49 public boolean dogeometriesintersect(collisiontriangle a, CollisionCircle b) { return b.containspoint(a.p1_x, a.p1_y) b.containspoint(a.p2_x, a.p2_y) b.containspoint(a.p3_x, a.p3_y) getlinepointdistancesquared(b.centerx, b.centery, a.p1_x, a.p1_y, a.p2_x, a.p2_y) <= (b.radius*b.radius) getlinepointdistancesquared(b.centerx, b.centery, a.p2_x, a.p2_y, a.p3_x, a.p3_y) <= (b.radius*b.radius) getlinepointdistancesquared(b.centerx, b.centery, a.p3_x, a.p3_y, a.p1_x, a.p1_y) <= (b.radius*b.radius) } a.containspoint(b.centerx, b.centery); CollisionBox Unsere zweite Standard Geometrie ist das Rechteck. Es ist zu beachten, dass dies kein frei drehbares Rechteck ist sondern eines, dass an den Koordinatenachsen ausgerichtet ist. Deshalb wird es auch nur von width, height und center definiert. Diese Geometrie wird wohl am meisten verwendet da einerseits Kollisionen zwischen zwei Rechtecken sehr schnell zu berechnen sind und andererseits es sich oft natürlich anfühlt Objekte in ein Rechteck zusammenzufassen. Um zu erkennen ob zwei Rechtecke sich überschneiden dreht man die Frage zuerst um. Zwei Rechtecke überschneiden sich nicht wenn die Rechtecke übereinander/untereinander oder nebeneinander liegen. Negiert man dies bekommt man ganz einfach heraus ob sich zwei Rechtecke schneiden: public boolean isintersectingwith(collisionbox other) { return! (this.rightx < other.x other.rightx < this.x this.topy < other.y other.topy < this.y); } Falls man auf Performance wert legt sollte man Rechtecke nicht (zu oft) mit anderen Geometrien kollidieren lassen. Beispielsweise ist die Kollisionserkennung mit einem Kreis schon komplizierter. Zuerst muss man bestimmen ob der Kreis neben, über oder unter dem Rechteck liegt, falls ja bestimmt man den Abstand der jeweiligen Seite und des Kreismittelpunktes. Wenn dieser Abstand kleiner als der Kreisradius ist schneiden sich die beiden Geometrien. 43

50 Abbildung 21: Kollisionserkennung Kreis-Rechteck (1) Wenn der Kreis andererseits schräg im Verhältnis zum Rechteck liegt muss man schauen ob das jeweilige Eck innerhalb des Kreises liegt, hierfür bestimmt man den Abstand Eck-Kreismittelpunkt und überprüft ob dieser kleiner dem Kreisradius ist. Abbildung 22: Kollisionserkennung Kreis-Rechteck (2) public boolean dogeometriesintersect(collisioncircle a, CollisionBox b) { if (a.centery > b.y && a.centery < b.topy) return a.centerx > (b.x - a.radius) && a.centerx < (b. rightx + a.radius); else if (a.centerx > b.x && a.centerx < b.rightx) return a.centery > (b.y - a.radius) && a.centery < (b. topy + a.radius); else return fsquare(a.centerx-b.x) + fsquare(a.centery-b.y) < fsquare(a.radius) fsquare(a.centerx-b.rightx) + fsquare(a.centery-b.y ) < fsquare(a.radius) fsquare(a.centerx-b.rightx) + fsquare(a.centery-b. topy) < fsquare(a.radius) fsquare(a.centerx-b.x) + fsquare(a.centery-b.topy) < fsquare(a.radius); 44

51 } Als letztes müssen wir wiederum auch die Kollision mit einem Dreieck erkennen. Hierbei nutzen wir aus das sich in jedem Fall mindestens zwei Seiten der zwei Geometrien überschneiden müssen. Dies gilt aber nicht in den Spezialfällen wo das Rechteck komplett innerhalb des Dreiecks ist, oder umgekehrt. Diese beiden Möglichkeiten müssen als Sonderfälle ebenfalls überprüft werden. public boolean dogeometriesintersect(collisiontriangle a, CollisionBox b) {od return dolinesintersect(a.p1_x, a.p1_y,a.p2_x, a.p2_y, b.x, b.y, b.x, b.topy) /*... */ dolinesintersect(a.p3_x, a.p3_y,a.p1_x, a.p1_y, rightx, b.y, b.x, b.y) b.containspoint(a.p1_x, a.p1_y) a.containspoint(b.x, b.y); } CollisionTriangle Kollisionsgeometrien in der Form von Dreiecken sind unsere letzte Möglichkeit. Es ist zu Beachten, dass diese auch am aufwendigsten zu berechnen sind. Trotzdem kann man mit ihrer Hilfe nahezu beliebig komplexe Strukturen darstellen. Genauer gesagt ist es mit Polynom Triangulation möglich jedes Polygon in Dreiecke zu zerlegen. Den Fall Kollision mit einem Kreis beziehungsweise mit einem Rechteck haben wir in den vorherigen Kapiteln schon besprochen. Das einzige was noch übrig bleibt ist die Kollision mit einem anderen Dreieck. Hierbei ist die Vorgehensweise jedoch die Gleiche wie bei der Dreieck-Rechteck Kollision. Wir suchen nach Kanten die sich überschneiden und beachten die beiden Sonderfälle in denen eine Geometrie komplett innerhalb der anderen liegt. public boolean isintersectingwith(collisiontriangle other) { return ShapeMath.doLinesIntersect(p1_x, p1_y, p2_x, p2_y, other. p1_x, other.p1_y, other.p2_x, other.p2_y) /*... */ ShapeMath.doLinesIntersect(p3_x, p3_y, p1_x, p1_y, other. p3_x, other.p3_y, other.p1_x, other.p1_y) containspoint(other.p1_x, other.p1_y) 45

52 } other.containspoint(p1_x, p1_y); Optimierung mit der Collisionmap Das grundlegende Problem, dass dieser Algorithmus bis jetzt noch hat ist dass mit steigender Geometrie Anzahl die Anzahl der Vergleiche quadratisch ansteigt. Es müssen aktuell nämlich jede CollisionGeometry mit jeder anderen getestet werden und überprüft werden ob sie sich überschneiden. Dies hat den Aufwand O(n 2 ). Die meisten dieser Operationen sind offensichtlich unnötig - wenn sich zwei Geometrien auf unterschiedlichen Seiten der Karte befinden können sie in keinem Fall miteinander kollidieren (den Fall von Entities die fast so gross wie die Karte sind ausgeschlossen). Unsere Lösung liegt darin die Datenstruktur zu ändern. Bisher wurden die CollisionGeometrien in einer einzigen grossen Liste gespeichert, jetzt speichern wir sie in einem zweidimensionalen Raster. Man muss sich das so vorstellen, dass man die Karte in ein Raster unterteilt ähnlich dem Vorgehen bei der TileMap. Jedes dieser Raster-Felder wird von einem Objekt der Klasse CollisionMapTile dargestellt und jedes Objekt enthält eine Liste der CollisionGeometrien die auf diesem Tile sind. Das bedeutet, dass jedes mal wenn eine CollisionGeometry hinzugefügt wird oder sich bewegt, die Tiles berechnet werden auf denen die Geometrie sich befindet. Die CollisionGeometry wird dann in die Listen aller dieser Tiles hinzugefügt. Möchte man nun wissen ob eine Geometrie mit einer anderen kollidiert geht man alle Tiles durch auf denen diese Geometrie liegt. Den eigentlichen Überschneidung-Test-Code führt man dann auf allen Geometrien aus die man in diesem Tiles findet. Die vorherigen Optimierungen, wie dass man zuerst eine Kreiskollision durchführt, bleiben immer noch intakt. Mit dieser Methode haben wir die Anzahl der zu überprüfenden Geometrien von allen enthaltenen auf ein paar in der Nähe eingeschränkt. Diese CollisionMap muss jedoch immer aktuell gehalten werden, jedes mal wenn eine Geometrie hinzugefügt/bewegt/entfernt wird muss die jeweilige Methode aufgerufen werden um die CollisionMap zu aktualisieren. Dies ist auch der technische Grund warum sowohl bei Entity als auch bei CollisionGeometry der position-vektor nicht öffentlich ist sondern nur durch Setter verändert werden kann. Denn dadurch kann man diese Events abfangen und an die CollisionMap weitergeben. Eine Frage ist nun wie die CollisionMapTiles skaliert werden sollen. Der Standard Ansatz unseres Frameworks ist es die CollisionMapTiles gleich gross wie die normalen Map Tiles zu haben. Dies ist 46

53 als Standard Ansatz in soweit gut, dass normalerweise eine Map weder nur ein paar Tiles noch eine extreme Anzahl Tiles hat und meist sind maximal eine Hand voll Entities gleichzeitig auf einer Tile. Trotzdem bieten wir dem Benutzer die Möglichkeit die TilegröSSe manuell anzupassen. Dafür gibt es im CollisionMap-Konstruktor den Parameter exptilescale. Dieser ist das Verhältnis von MapTiles zu CollisionTiles in der Form 2 n. Der Wert 0 ist hierbei Standard und beschreibt den Fall MapTiles == CollisionTiles. Ein Wert von 1 würde CollisionTiles bewirken die doppelt so gross sind wie die MapTiles (2 1 = 2) und ein Wert von -1 halb so grosse (2 1 = 1 2 ) Um dies nun implementieren zu können muss man für eine Geometrie berechnen können auf welchen Tiles sie sich befindet. Zuerst muss man die Position auf den Map Tiles in eine Position auf den CollisionTiles umwandeln: private int gettilex(float x) { if (exptilescale < 0) { return (int) (x * 1d * (1 << -exptilescale)); } else if (exptilescale == 0) { return (int) x; } else { return (int) (x * 1d / (1 << exptilescale)); } } private int gettiley(float y) { if (exptilescale < 0) { return (int) (y * 1d * (1 << -exptilescale)); } else if (exptilescale == 0) { return (int) y; } else { return (int) (y * 1d / (1 << exptilescale)); } } Jedoch muss man hier auch den Ausnahmefall beachten. Eine Geometrie muss nicht zwangsweise auf der Karte sein, theoretisch kann sie sich auch daneben befinden. Für diesen Fall haben wir einen zweiten 3x3 CollisionMapTile-Array welcher die 8 Bereiche um die Karte herum bezeichnet (Oben, Oben-Rechts, Rechts, Unten-Rechts, Unten, Unten-Link, Links, Oben-Links). Zwar hat man für den Fall von Kollisionen ausserhalb der Karte keinen Vorteil durch die CollisionMap, sondern effektiv wieder den gleichen Fall wie vor deren Einführung. Aber dafür sind auch dort Kollisionserkennung möglich. Neben der Tile-Position muss nun auch der Radius berechnet werden, alle CollisionTiles innerhalb 47

54 dieses Radius werden dann mit der entsprechenden Geometrie gefüllt. Dieser Collision-Radius berechnet sich aus dem umschliessenden Radius der Geometrie mit der Formel ceil(r geometry 2 exptilescale ). Dieser Radius ist immer mindestens 1, was dazu führt, dass jede Geometrie immer mindestens auf 9 Tiles liegt. In den meisten Fällen liegt die Geometrie nicht wirklich auf allen diesen Tiles. Dies ist jedoch kein Problem da die endgültige Kollisionserkennung immer noch durch die genauen Formeln berechnet wird. Es ist nur wichtig, dass es keine Tiles gibt auf denen die Geometrie liegt, die aber nicht diese enthalten. Eine weitere Optimierung kann man beim Bewegen von Geometrien implementieren. Normalerweise werden, wenn eine Geometrie bewegt werden bei allen Tiles auf denen sie vorher gelegen ist die Einträge entfernt und bei allen neuen die Einträge hinzugefügt. Falls die Geometrie jedoch auf der gleichen CollisionMapTile bleibt muss die Map nicht aktualisiert werden. Deshalb wird in der Methode move- Geometry() zuerst überprüft ob eine Änderung passiert ist und nur dann die Map aktualisiert: public boolean movegeometry(float prevcenterx, float prevcentery, CollisionGeometry geo) { if (gettilex(prevcenterx) == gettilex(geo.getcenterx()) && gettiley(prevcentery) == gettiley(geo.getcentery())) return true; boolean success = removegeometry(geo, prevcenterx, prevcentery) ; addgeometry(geo); } return success; Eine weitere Möglichkeit die Kollisionserkennung zu optimieren ist durch Einführung von Pseudo- Geometrien. Möchte eine Geometrie nur selbst mit anderen kollidieren aber nicht als Kollisionsobjekt dienen, muss es sich nicht in die CollisionMap eintragen. Ein Beispiel hierfür wäre eine Kugel-Entity. Diese besitzt eine CollisionGeometry um zu erkennen wann sie etwas getroffen hat. Jedoch gibt es normalerweise kein Fall in dem eine andere Entity wissen müsste ob die mit einer Kugel kollidiert. Deshalb kann man einen Performancevorteil erlangen indem man die Kugel-Geometrie nicht in die CollisionMap einträgt und stattdessen selber verwaltet. Es gilt zu beachten dass man dies nicht mit zu vielen Entity- Typen machen sollten um nicht den Überblick zu verlieren wer mit wem kollidieren kann. AuSSerdem muss die Kugel in jedem Schritt selbst ihre Kollisionen überprüfen, da es sonst keiner für sie tut. 48

55 Verwendung mit Entities In den meisten Fällen werden CollisionGeometries nicht alleinstehend benutzt sondern in Zusammenhang mit einer Entity. Aus diesem Grund sind die beiden Klassen auch eng miteinander verknüpft. So kann man einer Entity eine Liste an Geometrien hinzufügen, die diese Geometrie verwaltet. Wenn sich das Entity bewegt werden auch die Geometrien bewegt. Hierfür wird den Geometrien eine relative Position im Verhältnis zum Entity gegeben. AuSSerdem wird jedes mal wenn die Entity sich bewegt, auf Kollisionen überprüft. Falls eine Kollision geschieht wird auf der bewegten Entity die Methode onactivecollide() aufgerufen und auf der anderen Entity onpassivecollide(). Diese beiden Methoden werden im Interface CollisionListener implementiert - welches die Klasse Entity standardmässig hat. AuSSerdem wird, wenn man eine Geometrie zu einem Entity hinzufügt, dieses automatisch in den listener-array der Geometrie aufgenommen. Dies ist der Array mit allen Klassen die benachrichtigt werden wenn eine Kollision stattfindet. Analyse der Performance Um die Vorteile der einzelnen Optimierungen darzustellen, hier eine Tabelle mit Messwerten unter verschiedenen Bedingungen. In jedem Test wurden eine gewisse Anzahl an Entities mit jeweils einer CollisionGeometry erstellt und gleichmässig auf einer 128x128 Karte verteilt. Jedes mal wird die Zeit gemessen die ein Update- Vorgang braucht, in dem für jede Geometrie berechnet wird mit welchen anderen Geometrien sie kollidiert. Falls die Zeit so gross war, dass wir kein Ergebnis bekamen, wurde NaN eingetragen Test 1: Rechteckige Hitboxen Test 2: Kreis Hitboxen (mit sqrt) Test 3: Kreis Hitboxen (ohne sqrt) Test 4: Rechteckige Hitboxen (mit vorheriger Kreis Abschätzung) Test 5: Rechteckige Hitboxen in einer vollständigen CollisionMap 49

56 Anzahl Geo s Test 1 Test 2 Test 3 Test 4 Test ms 0.95 ms 0.76 ms 0.66 ms 0.28 ms ms ms ms ms 1.10 ms ms ms ms ms ms NaN NaN NaN NaN ms NaN NaN NaN NaN ms NaN NaN NaN NaN ms Ein paar Dinge kann man direkt aus dieser Tabelle erkennen. Einerseits den offensichtlich extremen Vorteil der CollisionMap im Gegensatz zu allen anderen Ansätzen. AuSSerdem gibt es einen erkennbaren Performance Einbruch durch Verwendung von sqrt. Der Unterschied zwischen Kreis und Rechteck Kollision ist fast nicht da - dies ist in soweit erklärbar, dass beides mathematisch einfach zu berechnen ist. Abbildung 23: Performance Graph der CollisionMap 50

57 Bewegung mit Kollisionen Kollisionserkennung ist nicht nur gut um zu erkennen wann zwei Entities kollidieren, sondern auch um dies zu verhindern. Hat man beispielsweise eine vom Spieler gesteuerte Figur möchte man nicht, dass diese stirbt wenn sie in einer Wand endet, sondern dass sie dies überhaupt nicht kann. Dafür hat die Klasse Entity ausser der setposition() Methode auch noch die moveposition()-methode. Diese bewegt das Entity entweder die komplette Strecke oder nur partiell falls zwischenzeitlich eine Kollision stattfindet. Um dies zu zu schaffen bewegt man das Entity und all seine Geometrien zuerst die komplette Strecke. Dann sucht man die erste fremde Geometrie mit denen eine eigene Geometrie kollidiert. Für diese Geometrie berechnet man dann die Entfernung die man rückwärts gehen muss, bis sich die beiden Geometrien nicht mehr überschneiden. Dies wiederholt man solange bis es für keine eigene Geometrie mehr eine Überschneidung gibt. Jedoch führt man dies nicht für die ganze Bewegung aus sondern einmal für die Bewegung in X-Richtung und dann noch einmal in Y-Richtung. X und Y Bewegung sind somit unabhängig und es ist möglich beispielsweise an einer Wand "entlang zu gleiten" indem die X-Bewegung verhindert wird aber die Y-Bewegung immer noch ausgeführt. Mathematisch interessant ist hierbei die Algorithmen um den minimalen Abstand zu berechnen. Wir brauchen eine Methode die zwei Geometrien, positioniert durch ihren Mittelpunkt, bekommt und uns den minimalen Abstand in X oder Y Richtung sagt bei denen dies sich gerade nicht schneiden. Dies führt zu unterschiedlichen Methoden für jede Art der Kollision: Kreis-Kreis Abstand Der Kreis-Kreis Abstand lässt sich einfach durch diese Formel berechnen: d x = (r 1 + r 2 ) 2 (y 2 y 1 ) signum(x 2 x 1 ) : 51

58 Abbildung 24: Berechnung des minimalen X-Abstands zweier Kreise Kreis-Rechteck Abstand Der Kreis-Rechteck Abstand muss wieder zwei Fälle abdecken. Wenn der Kreis neben dem Rechteck ist, ist die Formel:. d x = (r 1 + width 2 ) signum(x 2 x 1 ) 2 Befindet sich der Kreis über oder unter dem Rechteck ist die Formel die gleiche wie bei dem Kreis- Kreis Abstand: d x = (r 1 ) 2 (y 2bl y 1 ) signum(x 2 x 1 ) 52

59 Abbildung 25: Berechnung des minimalen X-Abstands eines Kreises und eines Rechtecks Der Rechteck-Kreis Fall ist der selbe wie Kreis-Rechteck nur mit getauschten Vorzeichen. Dies gilt auch später für alle symmetrischen Fälle wie Kreis-Dreieck oder Dreieck-Rechteck. Rechteck-Rechteck Abstand Beim Rechteck-Rechteck Fall bestimmt man den Abstand mit: d x = width 1 + width 2 2 Abbildung 26: Berechnung des minimalen X-Abstands zweier Rechtecke Es ist interessant, dass dies der einzige Fall bei dem der minimal X-Abstand unabhängig von der Y Position ist (solange es überhaupt eine Kollision gibt) 53

60 Dreieck-Kreis Abstand Den Abstand zwischen einem Dreieck und einem Kreis zu berechnen ist etwas komplizierter als die vorangegangenen Beispiele. Zur Vereinfachung brechen wir das Problem in drei Kreis-Strecke Abstände auf. Aus allen validen Abständen die wir so bekommen nehmen wir dann den, dessen absoluter Wert minimal ist. Hierbei ist es wichtig, dass man nur die validen Abstände betrachtet. Kollidiert der Kreis zum Beispiel niemals mit der dritten Kante, egal wie weit er sich auf der X-Achse bewegt, darf dieser Abstand auch nicht beachtet werden. Da wir bereits mit Gleitkommazahlen arbeiten, haben für den Keine-Kollision Fall den Wert NaN genommen. Abbildung 27: Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (1) Zuerst berechnen wird den Winkel αden die Gerade (definiert durch P1 und P2) mit der X-Achse hat. Dies geschieht über die Funktion atan2 aus der Math-Bibliothek von java. Der Winkel βist der Komplementwinkel zu α, es gilt also α + β = 90 54

61 Abbildung 28: Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (2) Als nächstes möchten wir den Punkt ausrechnen an dem der Kreis die Strecke berühren würde. An dieser Stelle liegt die Gerade tangential zum Kreis. Mittels des Winkels βkönnen wir also diesen Punkt ermitteln und auch seine Lage relativ zum Kreismittelpunkt (dcx und dcy). Zwar kann es immer zwei Punkte auf gegenüberliegenden Seiten des Kreises geben, dies kann jedoch unterschieden werden indem man sich anschaut ob der Kreis rechts oder links neben der Strecke liegt. Je nachdem muss dcx positiv oder negativ sein. Abbildung 29: Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (3) Da wir nun die Y-Position der Kollisionspunkte haben müssen wir noch den X-Anteil des Punktes auf der Strecke berechnen, dies ist in soweit kein Problem da wir ja dessen Y-Anteil schon kennen. In diesem Schritt können wir auch erkennen ob es überhaupt eine Kollision und somit einen minimalen X-Abstand gibt. Falls der berechnete Punkt auf der Strecke nicht zwischen P1 und P2 gibt es auch keine Kollision. 55

62 Abbildung 30: Berechnung des minimalen X-Abstands eines Kreises und eines Dreieckes (4) Als letzten Schritt muss man nur noch Pcc.x von Pcl.x abziehen. Dies ist jetzt der minimale Weg den der Kreis sich bewegen darf um nicht mit dem Dreieck zu kollidieren. Da wir aber bisher immer den minimalen Abstand gesucht haben muss dieser noch daraus berechnet werden indem man ihm vom absoluten Abstand der beiden Geometrien abzieht: minx = abs(g1.x g2.x) dx Dreieck-Dreieck Abstand Der Abstand Dreieck-Dreieck kann auf mehrere Punkt-Strecke Abstände vereinfacht werden. Denn bei jeder Kollision muss eine Ecke eines Dreiecks auf eine Kante des anderen treffen. Wieder benutzt man den Ansatz von Kreis-Dreieck und berechnet alle gültigen Abstände und nimmt dann denjenigen dessen absoluter Wert am kleinsten ist. Insgesamt sind das 18 Punkt-Strecke Berechnungen. Jeweils drei Ecken des einen Dreiecks mal 3 Kanten des anderen mal zwei Dreiecke. Zwar könnte man dies noch optimieren, jedoch ist die Punkt-Strecke Berechnung so schnell, dass wir eine Optimierung noch nicht für nötig befunden haben. Dreieck-Rechteck Abstand Der Dreieck-Rechteck Abstand ist effektiv genau das gleiche wie der Dreieck-Dreieck Abstand. Man kann ihn mit dem gleichen Ansatz berechnen, nur dass man anstatt achtzehn vierundzwanzig Punkt- Strecke Berechnungen durchführen muss. Dies liegt an der einen Kante und Ecke die das Rechteck mehr 56

63 als das Dreieck hat. Praktische Probleme Nun gibt es in der Klasse CollisionListener auch noch Events für solche verhinderten Kollisionen. Kollidiert eine Geometrie in ihrer eigenen Bewegung wird die Methode onactivemovementcollide() bei dem bewegten Entity aufgerufen und bei dem anderen onpassivemovementcollide. Ein Problem können hier Entities mit mehreren CollisonGeometries sein. Hierbei muss drauf geachtet werden, dass alle Geometrien in der Kollision beachtet werden und jeweils der grösste "Rücksetz- Wert" benutzt wird. Ein weiteres Problem sind entstehende Rundungsfehler bei Verwendung von FloatingPoint Zahlen. Führt man den Algorithmus exakt so wie oben beschrieben aus kann es vorkommen, dass sich die beiden Geometrien auch nach dem Rücksetzen immer noch leicht schneiden. Der einzige Weg um dieses Problem herum ist es einen delta Wert in der Berechnung des minimalen Abstands einzuführen. Damit wird nicht mehr der minimale Abstand zurückgeliefert sondern der minimale Abstand plus einen delta Wert. Somit können sich Entities nicht mehr "wirklich" berühren sondern nur noch bis maximal delta Einheiten nähern. Ein letztes Problem ist das sogenannte Discrete-Time-Issue (2) S 503. Falls die Update rate niedrig genug ist kann es vorkommen, dass ein Objekt links neben einem anderen ist und sich dann schnell genug nach rechts bewegt um im nächsten Schritt rechts neben dem Objekt zu sein. Obwohl sich das Entity nun direkt durch ein anderes bewegt hat, wurde an keiner Stelle eine Kollision bemerkt. Zwar gibt es mathematische Ansätze dieses Problem zu lösen, diese gehen jedoch auf Kosten der Performance. Einfacher ist es eine konstante Update-Rate aufrecht zu erhalten und keine extrem dünne Entities zu verwenden, wo Kollisionen wichtig sind. 57

64 Abbildung 31: Discrete-Time-Issue: Ein Objekt "phased" durch ein anderes Limitierte Kollisionen In unserer aktuellen Implementation kollidiere noch all Entities mit allen. Das ist in soweit kein Problem, dass man in den Event-Handlern überprüfen kann ob die Kollision Sinn macht und wenn nicht sie einfach verwirft. Jedoch kann es trotzdem hilfreich sein die Kollisionen im Vorfeld zu Filtern. Dafür gibt es in der Klasse CollisionGeometryOwner die Methode cancollidewith(). Bevor eine Kollision ausgeführt wird, wird überprüft ob die beiden Geometrien auch wirklich miteinander kollidieren können. Problematisch wird es jedoch, da die Methode kommutativ sein soll. Dies bedeutet, dass a.cancollidewith(b) das gleiche Ergebnis wie b.cancollidewith(a) liefert. Assert.True(a.CanCollideWith(b) == b.cancollidewith(a)) Dass diese Bedingung erfüllt ist liegt in der Verantwortung des Programmierers. Eine zweite Methode ist die canmovecollide() Methode. Welche bestimmt mit welchen Entities in der moveposition() Methode kollidiert wird. Ohne diese Methode würde das Entity mit jeder anderen CollisionBox kollidieren. Mit ihr 58

65 lässt sich dies auf die Objekte einschränken mit der das Entity auch wirklich zusammenstossen soll. Es ist jedoch zu beachten, dass cancollidewith() eine höhere Priorität hat als canmovecollide(). Wenn also cancollidewith() false ist, dann wird canmovecollide() überhaupt nicht mehr abgefragt. Kollisionen mit der Karte Im Gegensatz zu Kollisionen mit anderen Geometrien sind Kollisionen mit der Karte sehr einfach und sogar in konstanter Zeit zu überprüfen (der einzige Faktor ist hier die GeometriegröSSe). Wir haben zuvor für die CollisionMap schon eine Methode entwickelt um festzustellen auf welchen (CollisionMap- )tiles eine Geometrie eventuell liegen kann. Die gleiche Methode könne wir nun wiederverwenden um zu ermitteln mit welchen MapTiles eine Geometrie eventuell kollidieren kann. Zur exakten Ermittlung erstellen wir CollisionGeometrien für die einzelnen Tiles und lassen sie mit unserer Geometrie kollidieren. Da es eine von Anfang an bekannte Anzahl an Tiles gibt können wir diese Geometrien gleich am Anfang des Programms erzeugen und dann für später speichern. Jedoch fügen wir sie nicht einfach in die CollisionMap ein. Dies würde zwar funktionieren, jedoch würden die vielen Geometrien unserer Kollisionserkennung stark verlangsamen und wie oben schon besprochen müssen sie ja nicht in der Map sein um zu erkennen wann mit ihnen kollidiert wird. Da auch hier eine Entity nicht mit allen Tiles kollidieren möchte implementiert die Klasse Tile das Interface CollisionGeometryOwner. Und so kann unsere normale Methodik zur Limitierung von Kollisionen angewandt werden. Die Tiles werden dabei automatisch als CollisionGeometryOwner eingetragen Settings In absgdx gibt es zwei Arten von Einstellungen: Anwendungseinstellungen und Frameworkoptionen. Anwendungseinstellungen sind Einstellungen im eigentlichen Spiel, ihre Verwaltung liegt in der Hand des Entwicklers. Zusätzlich gibt es verschiedene Optionen die angeben wie das Framework sich verhält. Für beide Dinge werden DependentProperty Objekte verwendet. 59

66 Framework Optionen Eine Instanz der Klasse DependentProperty repräsentiert einen einzelnen Wert. Dies ist meist ein Wahrheitswert kann aber auch ein String, eine Farbe oder eine Zahl sein. Der besondere Vorteil ist, dass jede Property von einer anderen abhängig sein kann. Eine Einstellung ist nur dann aktiv wenn alle Einstellungen von denen er abhängig ist ebenfalls aktiv sind. Daraus entsteht dann ein Abhängigkeitsbaum der einzelnen Einstellungen. Abbildung 32: Die absgdx Einstellungen in Baumdarstellung Dies ist beispielsweise für die Debugoptionen in absgdx nützlich: Wird die übergeordnete Option debugmode deaktiviert sind auch alle anderen untergeordneten Debugoptionen deaktiviert. Ist die Einstellung ein Boolean entscheidet sich ob sie aktiv ist einfach mittels ihres Wertes. Bei String-Properties werden alle Werte ausser null als wahr gewertet und Zahlen werden immer als wahr gewertet. Zusätzlich zu den normalen DependentProperties gibt es auch noch speziellere Subklassen: ConstantBooleanProperty: Dies ist eine BooleanProperty die nicht mehr veränderlich ist. Dies ist nützlich für zur Compilezeit festgelegte Werte (wie ob der Debugmode überhaupt möglich ist) MetaProperty: Diese Einstellung ist immer wahr und dient der Kategorisierung mehrere anderer Einstellungen unter sich. 60

67 RootProperty: Dies ist ähnlich einer MetaProperty kann jedoch keine Abhängigkeiten haben und bildet somit die Wurzel des Baumes Debugging Es ist oftmals nötig ein Programm zu debuggen. Hierfür gibt es zwei Ansätze, einerseits kann man das Programm mit einem Debugger an einer bestimmten Stelle anhalten, den Speicher auslesen und den Code Zeile für Zeile durchlaufen. Dies ist nützlich bei Programmen welche etwas berechnen. Da wir hier jedoch ein fortwährend laufendes Programm haben ist es manchmal nötig das Programm live zu beobachten. Hierfür haben wir den DebugTextRenderer. Mit ihm kann man, ohne das Programm anzuhalten, im Bildschirm Debuginformationen anzeigen lassen. Abbildung 33: Beispiel der Debugansicht (In-Game) AuSSerdem können die Abgrenzungen von Entities, Tiles und Kollisionsgeometrien angezeigt werden. Zusätzlich werden die aktuellen physikalischen Eingenschaften (Position, Geschwindigkeit, Beschleunigung) von Entities mittels Pfeilen visualisiert. Ähnliche Anzeigen sind auch im MenuLayer für MenuElements vorhanden und können wenn nötig vom Benutzer um eigene erweitert werden. 61

68 Abbildung 34: Beispiel der Debugansicht (In-Menu) Die Anzeige der Debugansicht wird über die DependentProperties geregelt. Die Root Property debugenabled regelt ob die Debugansicht aktiv ist. Mit eventuellen Unterproperties kann man verschiedene Ansichten aktivieren oder deaktivieren. Es ist nützlich das Ein/Ausschalten der Debugansicht auf eine Tastaturtaste oder einen Menüknopf zu legen (aufrufen der doswitch() Methode) Hintergründe In verschiedenen Fällen kann es vorkommen, dass Bildschirmbereiche nicht von einer Textur bedeckt sind. Zum Beispiel sorgt der ShowCompleteMapScaleResolver fast immer dafür, dass man den Hintergrund hinter den MapTiles sieht. AuSSerdem haben EmptyTiles keine Textur zum rendern und so kann man auch durch sie hindurchsehen. Auch normale Tile Texturen könne transparente Stellen besitzen. Die Frage ist also, was hinter den Tiles ist: Hierfür gibt es die Hintergrundobjekte, mit ihnen kann man einen Hintergrund definieren. Dies kann zum Beispiel bei Maps aus der Seitenansicht benutzt werden, um einen Himmel darzustellen. 62

69 Abbildung 35: Eine Seitensansichts-Map mit Hintergrund Ein Hintergrund kann ebenfalls transparente Bereiche beinhalten und so kann man mehrere Hintergründe hintereinander anzeigen. Ein einzelner GameLayer kann somit beliebig viele Hintergründe besitzen, welche hintereinander angezeigt werden. Man kann eigene Hintergrundtypen definieren indem man von der Klasse MapBackground ableitet, vom Framework aus sind jedoch schon drei verschiedene Typen definiert: SingleBackground Der SingleBackground ist der einfachste Hintergrund. Er besitzt eine einzelne Textur welche unbeweglich an der gleichen Position angezeigt wird. Dies erzeugt die Illusion eines sehr weit entfernten Hintergundes, zum Beispiel könnte man hier die Textur eines Himmels mit SOnne und Wolken benutzen. RepeatingBackground Der RepeatingBackground besteht ebenfalls aus einer einzigen Textur, diese wird jedoch so oft in X und Y Richtung wiederholt bis der ganze Bildschirm ausgefüllt ist, ausserdem bewegt sich der Hintergrund mit der Karte mit. Dies erzeugt die Wahrnehmung, dass der Hintergrund auf der gleichen Ebene wie die Karte liegt. Man könnte hier zum Beispiel Hintergründe wie Büsche oder Häuser einfügen. AuSSerdem kann man diesen Hintergrund benutzen um einfach eine einfarbige Fläche als Hintergrund zu erhalten ohne eine extrem grosse Textur in den SingleBackground zu laden. 63

70 ParallaxBackground Dieser Hintergrundtyp ist ein parallax-scrollender Hintergrund. Dies bedeutet, dass er aus nur einer einzigen Textur besteht, welche sich mit dem Kartenoffset zusammen bewegt. Um einen echten parallaxen Effekt zu bekommen muss man mehrere dieser Hintergründe benutzen, welche sich unterschiedlich schnell bewegen. Dies erzeugt dann die Illusion von mehreren Ebenen, die unterschiedlich weit weg vom Spieler sind. Die Geschwindigkeit mit der sich ein Hintergrund im Verhältnis zum Spieler (und damit im Verhältnis zur Karte) bewegt hängt von seinen Dimensionen ab. Der Hintergund scrollt genau so schnell, dass er bei einem X-Offset von 0% links am Bildschirm anliegt und bei einem Offset von 100% rechts am Bildschirm. Abbildung 36: Erklärung zu Hintergründen mit Bewegungsparallaxe Wie man sieht ist es für die Textur wichtig mindestens so breit und hoch wie der Bildschirm zu sein. Für einen normalen parallaxen Effekt sollte die Textur auch kleiner als die Karte sein. Ist sie im Gegensatz breiter (oder höher) als die Karte gelten immer noch die gleichen Regeln wie zuvor, was dazu führt, dass der Hintergrund sich in die entgegengesetzte Richtung wie die Karte bewegt. 64

71 3.2.8 Der Menü Layer Neben dem GameLayer ist der MenuLayer der zweite wichtige Layer Typ. Mit ihm kann man eine einzelne Menüseite darstellen. Ein Menü besteht aus einem MenuFrame welcher verschiedene Menüelemente enthält, wie zum Beispiel Buttons, Edits, Label, Images etc. Mit einem MenuLayer kann man beispielsweise das Hauptmenü gestalten oder auch die Levelauswahl. Unser Layersystem ist dabei eine grosse Hilfe, denn wenn man auf den Layerstack ein Untermenü pushed muss man dieses nur wieder vom Stack entfernen um auf dem Obermenü zu landen. Komponenten Sämtliche Komponenten sind von der Klasse MenuBaseElement abgeleitet. Jedes MenuElement hat eine feste Position, GröSSe und eine eindeutige ID. Vom Framework aus sind schon eine Reihe an Standard Komponenten definiert, jedoch können auch eigene neue erstellt werden. Alle Komponenten befinden sich immer innerhalb eines MenuFrames (ausgenommen der MenuFrame selbst) und dieser befindet sich innerhalb eines MenuLayers. In einem Layer ist immer eine Komponente aktuell fokusiert. Der Fokus wird gewechselt wenn auf eine neue Komponente geklickt wird. Die Bedeutung des Fokus ist von der entsprechenden Komponente abhängig und kann sowohl visuelle als auch funktionelle Veränderung bedeuten. Abbildung 37: Klassendiagramm der Menü Elemente Die meisten Komponenten werden durch Komposition anderer Komponenten gebildet. So zeigt der MenuButton beispielsweise seinen Text nicht selbst an, sondern besitzt intern ein Label mit dem Text des 65

72 Buttons. Indem man das rendern immer wieder auf Subkomponenten auslagert kann man relativ einfach auch komplexere Komponenten bilden. So besteht beispielsweise der MenuSettingsTree aus mehreren MenuImages. MenuLabels und MenuCheckboxes. Klasse MenuButton Funktion Ein einfacher Knopf zum Drücken. Das OnClick-Event kann mittels eines ButtonListeners abgefangen werden. MenuCheckBox MenuRadioButton Eine Optionsbox, welche entweder aktiviert oder deaktiviert ist Eine Optionsbox, welche entweder aktiviert oder deaktiviert ist. Im Kontext des übergeordneten Containers ist immer nur maximal ein RadioButton aktiviert MenuEdit Ein Text Eingabefeld. Es sind nur Eingaben möglich die von der übergebenen BitmapFont dargestellt werden können. Bei Eingaben länger als die Komponentenbreite entsteht ein Scrolleffekt. MenuImage Zeigt entweder eine statische Textur an oder eine sich wiederholende Animation MenuLabel Zeigt einen Text an. Der Text ist entweder fest skaliert oder passt sich den Dimensionen des Labels an MenuContainer Ein Container welcher mehrere Kindelemente enthält. Die Positionen der Kinder sind relativ zu der des Containers. Möchte man einen Container zum reinen Zweck der logischen Gruppierung kann man direkt diese Klasse verwenden. Ist eine visuelle Gruppierung erwünscht sollte man die Klasse MenuPanel verwenden. MenuPanel MenuFrame Ein Container welcher eine eigene Textur besitzt. Der Wurzelcontainer jedes MenuLayers. Er besitzt immer die Breite des aktuellen Anzeigegerätes und kann nicht ausgetauscht werden. MenuSettingsTree Eine Komponente um einen Baum von DepenedentProperties anzuzeigen. Die einzelnen Knoten könne individuell aktiviert/deaktiviert werden und die einzelnen Unterbäume zusammengeklappt oder ausgeklappt werden. Einige Elemente benötigen einen Möglichkeit um Schrift anzuzeigen. Hierfür hat jedes MenuElement ein Feld font welches vom Typ BitmapFont ist. Dieses Feld wird von den Komponenten an ihre 66

73 Kinder weitervererbt. Es reicht also theoretisch dem MenuFrame ein Font zu geben und der Frame wird es an alle seine Kinder weitergeben. Hat eines der Kinder jedoch einenen eigenen Font definiert erhält dieser Priorität. So ist es auch möglich, zwei Containern jeweils unterschiedliche Fonts zu geben und damit ihnen und all ihren Kindern ein unterschiedlichen Aussehen zu spendieren. Texturen und GUITextureProvider AuSSer dem MenuContainer werden alle Komponenten angezeigt. StandardmäSSig haben die Komponenten eine Renderroutine welcher allein mit dem ShapeRenderer auskommt. Dies bedeutet, dass die Komponenten mittels farbigen Rechtecken und Linien gezeichnet werden. Dies ist jedoch eigentlich nur zum Debuggen gedacht. Im Produktiveinsatz braucht jede Komponente eine Reihe an Texturen um gezeichnet zu werden. Ein MenuButton beispielsweise braucht insgesamt 36 Texturen um gezeichnet zu werden. Er besitzt vier Zustände (normal, gedrückt, fokusiert, deaktiviert) und Jeder dieser Zustände braucht neun Texturen: Die vier Ecken, die vier Kanten und eine für die eigentliche Fläche. Abbildung 38: Die neun Texturen einer Menüfläche Diese Unterteilung in neun Texturen sorgt dafür, dass man Elemente in beliebiger Dimensionierung anzeigen kann, ohne die Texturen verzerren zu müssen. AuSSerdem ist es hier relativ einfach ein neues UI Kit zur Verfügung zu stellen - alles was man hierfür tun muss ist die Texturen auszutauschen. Die Verteilung der Texturen erfolgt über eine Instanz der Klasse GUITextureProvider. Dies ist primäre eine HashMap welche einem 3-Tupel aus Klasse, Identifier und Modifier eine Textur zuordnet. So ist beispielsweise der Klasse MenuButton, dem Identifier texture-topleft und dem Modifier focused eine spezielle Textur zugeordnet. Den Weg über diese Klasse hat den Vorteil, dass man allen Buttons den gleichen TextureProvider geben kann und sie alle damit die gleiche Button-Textur bekommen. Möchte man einen Button welcher eine andere Textur hat, muss man ihm nur einen eigenen TextureProvider geben. Die Identifikation über die Klasse ermöglicht es auch verschiedene Texturen für verschiedene Subklassen 67

74 von MenuButton zur Verfügung zu stellen und eine einfache Unterscheidung zwischen den Texturen von zum Beispiel einer CheckBox und einem RadioButton zu haben. Die einzige Ausnahme bilden MenuImages. Da diese im Normalfall alle eine eigene Textur haben wird ihre Anzeigetextur über die Methode setimage() gesetzt wird und nicht über den TextureProvider. Events Jedes MenuElement hat eine Liste von MenuElementListener. In diesem Listener sind alle Events integriert welche Element unabhängig auftreten: onpointerdown Die Maus/der Touchpointer drückt auf dieses Element onpointerup Die Maus/der Touchpointer löst sich von diesem Element onclicked Die Maus/der Touchpointer führt ein vollständiges Klick-Manöver aus (PointerDown + PointerUp) onhover Die Maus/der Touchpointer betritt die Abgrenzung dieser Komponente onhoverend Die Maus/der Touchpointer verlässt die Abgrenzung dieser Komponente onfocus Diese Komponente erhält den Fokus onfocuslost Diese Komponente verliert den Fokus Zusätzlich können Elemente von dem Interface MenuElementListener erben und somit neue Events einführen welche speziell für ein Element gedacht sind. So gibt es beispielsweise das Interface MenuCheckboxListener welches zu den vorhandenen Methoden noch die Methode onchecked hinzufügt. 68

75 Menüs mit AGDXML definieren Bisher haben wir Menüs manuell im Code erstellt. Dies hat zwei Nachteile. Einerseits kann es sehr kompliziert werden komplexere Menüs zusammenzustellen- Andererseits sind diese Menüs statisch und können sich nicht an verschiedene GröSSen oder dynamische GröSSenänderungen anpassen. Als Lösung hierfür gibt es den AgdxmlLayer, welcher vom MenuLayer ableitet. Dieser bekommt eine Menüdefinition in Form einer speziellen XML Datei. Mittels dieser Definition wird dann dynamisch ein Menü erstellt. Die Menüdefinition kann entweder auf fixen MaSSen beruhen oder die Komponenten dynamisch und relativ zur verfügbaren Fläche definieren. 69

76 Das AGDXML Format Abbildung 39: Der AGDXML Tag Tree Das AGDXML Format besteht aktuell aus acht verschiedenen Tags die jeweils einem MenuElement zugeordnet sind. Der Root-Tag des AGDXML Dokumentes muss immer <frame> sein. Darunter kann man mittels anderer Tags Menükomponenten erzeugen. Es gibt einige Attribute, welche alle Tags (ausser dem <frame> Tag) haben. Zum Beispiel kann man für alle Komponenten die Position, Höhe und Breite festlegen. Hierbei kann man entweder ein konstantes MaSS in der Einheit Pixel angeben oder einen Prozentwert, welcher relativ zum übergeordneten Element interpretiert wird. Diese Prozentwerte sind die 70

77 erste Möglichkeit um dynamische Menüs zu erzeugen. AuSSerdem kann man für alle Komponenten die ID festlegen, so wie den GUITextureProvider und die Sichtbarkeit. Der TextureProvider wird in einem AGDXML Baum automatisch vererbt. Möchte man also allen Komponenten den gleichen Provider zur Verfügung stellen so muss man diesen nur im <frame> Tag definieren und er wird nach unten im Baum an alle Komponenten weitergegeben. Angegeben wird der GUITextureProvider. über einen identifier Dieser muss im Programmcode mittels der Methode addagdxmlguitextureprovider(string key, GUITextureProvider value) einem TextureProvider zugeordnet werden. Auch Events kann man in AGDXML registrieren, hierzu muss man in der AGDXML Datei nur den Methodennamen angeben. Über Type Introspection wird automatisch die passende Methode in der Klasse welche von AgdxmlLayer ableitet gesucht. Dabei ist zu beachten, dass eine Methode mit richtigem Namen und richtiger Parameterliste existieren muss, sonst wird eine Exception vom Type AgdxmlParsingException geworfen. Dies vereinfacht die Definition von Events erheblich - da man Methoden nicht umständlich doppelt registrieren muss, sondern sie einfach deklarieren kann und in der AGDXML Datei angeben. Der wirklich grosse Vorteil von AGDXML ist jedoch der <grid> Tag. Mit ihm kann man einen dynamischen Container erzeugen. Mithilfe der Tags <columndefinitions> und <rowdefinitions> kann man das Grid in ein Raster unterteilen. Und mit den Pseudo-Attributen grid.row und grid.column können Elemente in dieses Raster eingebettet werden. Sind keine zusätzlichen Attribute angegeben füllt ein Element immer seine gesamte Rasterzelle aus. Jedoch kann dies auch mit den Attributen position, width und height manipuliert werden. Als Spalten-/ZellenmaSSe gibt es drei verschiedene Definitionsmöglichkeiten: 71

78 Name Schreibweise Funktion PIXEL Zahlenwert alleine angeben Die Spalte/Reihe bekommt exakte die festgelegten MaSSe PERCENTAGE Zahlenwert mit angefügtem Prozentzeichen Die GröSSe der Spalte/Reihe ist prozentual abhängig von der Breite/Höhe des gesamten Grid- Elements WEIGHT Zahlenwert mit angefügtem Stern Der verbleibende Freiraum (nach PIXEL und PERCENTAGE) wird gemäss der Gewichtung verteilt. Eine Reihe mit doppeltem Gewicht ist auf jeden Fall doppelt so hoch wie eine mit nur einfachem Gewicht. Die einzelnen Definitionen werden am beste in Kombination genutzt. So kann man ein Grid mit 3 Reihen definieren bei dem zwei gleich gross sind und die dritte hundert Pixel hoch. Einige Attribute sind Farbdefinitionen. Hier kann man entweder direkt einen Hexadezimal-Wert angeben (zum Beispiel #FF8800). Alternativ kann man auch direkt einen Wert aus einer Liste an vordefinierten Farbkonstanten benutzen (zum Beispiel BLACK oder MAGENTA). Zuletzt gibt es einige Attribute welche ein Padding definieren. Dies sind vier Werte welche den vier Seiten eines Rechtecks entsprechen. Diese Werte kann man in unterschiedlichen Formaten angeben: 2, 8, 2, 8 Man gibt alle vier Werte in der Reihenfolge top - left - bottom - right an. 2, 8 Man gibt zuerst den top-bottom Wert an und dann den left-right Wert. 2 Man setzt alle vier Attribute auf den gleichen Wert. 2%, 4%, 2%, 4% Man kann die oberen Methoden auch mit den Prozent Schreibweise kombinieren Eine (extrem einfach gehaltene) AGDXML Datei könnte beispielsweise so aussehen: <?xml version="1.0" encoding="utf-8"?> <frame textures="provider1" > 72

79 <grid container="true"> <grid.columndefinitions width="20, 2*, 10, 1*, 20" /> <grid.rowdefinitions height="8\%, 40, 4\%, 1*, 4\%" /> <label grid.row="1" grid.column="1" content="hello, World!"/> <image grid.row="3" grid.column="3" texture="ani_01" animation="750" id="myimage"/> <edit grid.row="3" grid.column="1" text="playername" textcolor="black" halign="left" /> </grid> </frame> Der AGDXML Menudesigner Als zusätzliches Hilfsmittel für AGDXML Dateien gibt es den AGDXML-Menudesigner. Die ist ein WY- SIWYG Editor für AGDXML Dateien. Abbildung 40: Screenshot des AGDXML Menudesigner Der Vorteil des Menudesigners ist es, dass man direkt - während dem Schreiben - sehen kann ob ein syntaktischer Fehler in der AGDXML Datei ist und wie das resultierende Format ungefähr Aussehen 73

Entwicklung eines 2D Tiled Map LibGDX Game Framework

Entwicklung eines 2D Tiled Map LibGDX Game Framework DHBW KARLSRUHE TINF12B5 STUDIENARBEIT Entwicklung eines 2D Tiled Map LibGDX Game Framework Author: Armin Benz & Mike Schwörer Betreuer: Prof. PhD. Kay Berkling 6712294 & 8045949 7. April 2015 Inhaltsverzeichnis

Mehr

Entwicklung eines 2D Tiled Map LibGDX Game Framework

Entwicklung eines 2D Tiled Map LibGDX Game Framework DHBW KARLSRUHE TINF12B5 STUDIENARBEIT Entwicklung eines 2D Tiled Map LibGDX Game Framework Author: Armin Benz & Mike Schwörer Betreuerin: Prof. PhD. Kay Berkling 6712294 & 8045949 6. Mai 2015 Inhaltsverzeichnis

Mehr

Projekt AGB-10 Fremdprojektanalyse

Projekt AGB-10 Fremdprojektanalyse Projekt AGB-10 Fremdprojektanalyse 17. Mai 2010 1 Inhaltsverzeichnis 1 Allgemeines 3 2 Produktübersicht 3 3 Grundsätzliche Struktur und Entwurfsprinzipien für das Gesamtsystem 3 3.1 Die Prefuse Library...............................

Mehr

Einführung in git. Ben Oswald. 27. April 2014. Im Rahmen der Vorlesung Entwicklung mobiler Anwendungen

Einführung in git. Ben Oswald. 27. April 2014. Im Rahmen der Vorlesung Entwicklung mobiler Anwendungen Einführung in git Im Rahmen der Vorlesung Entwicklung mobiler Anwendungen Ben Oswald 27. April 2014 Inhaltsverzeichnis 1 Einleitung 1 1.1 Was ist git?..................................... 1 1.2 Warum sollten

Mehr

Lehrstuhl für Datenverarbeitung. Technische Universität München. Grundkurs C++ Buildsysteme

Lehrstuhl für Datenverarbeitung. Technische Universität München. Grundkurs C++ Buildsysteme Grundkurs C++ Buildsysteme Buildsysteme Beispielhaftes Übersetzungsszenario: Verzeichnis tutorial7/ main.cpp, lcdrange.cpp, lcdrange.h *.cpp Kompilieren *.o *.h Grundkurs C++ 2 Headerdateien //blackbox.h

Mehr

Autor: Michael Spahn Version: 1.0 1/10 Vertraulichkeit: öffentlich Status: Final Metaways Infosystems GmbH

Autor: Michael Spahn Version: 1.0 1/10 Vertraulichkeit: öffentlich Status: Final Metaways Infosystems GmbH Java Einleitung - Handout Kurzbeschreibung: Eine kleine Einführung in die Programmierung mit Java. Dokument: Autor: Michael Spahn Version 1.0 Status: Final Datum: 23.10.2012 Vertraulichkeit: öffentlich

Mehr

Grundlagen der Verwendung von make

Grundlagen der Verwendung von make Kurzskript zum Thema: Grundlagen der Verwendung von make Stefan Junghans Gregor Gilka 16. November 2012 1 Einleitung In diesem Teilskript sollen die Grundlagen der Verwendung des Programmes make und der

Mehr

CocoaPods Schnelleinstieg

CocoaPods Schnelleinstieg CocoaPods Schnelleinstieg Moritz Haarmann, Software for mobile devices CocoaPods ist das Tool der Wahl, wenn es darum geht, Abhängigkeiten eines Projekts zu verknüpfen. CocoaPods ist kostenlos und quelloffen

Mehr

Tutorium Java Ein Überblick. Helge Janicke

Tutorium Java Ein Überblick. Helge Janicke Tutorium Java Ein Überblick Helge Janicke 26. Oktober 2000 1 VORRAUSSETZUNGEN ZUM PROGRAMMIEREN MIT JAVA. 1 1 Vorraussetzungen zum Programmieren mit Java. Was braucht man, wenn man mit Java programmieren

Mehr

Mobile Application Development

Mobile Application Development Mobile Application Development Android: Einführung Jürg Luthiger University of Applied Sciences Northwestern Switzerland Institute for Mobile and Distributed Systems Lernziele Der/die Kursbesucher/in kann

Mehr

Enigma2 Plugin Entwicklung mit Eclipse

Enigma2 Plugin Entwicklung mit Eclipse Enigma2 Plugin Entwicklung mit Eclipse Enigma2 Plugin Entwicklung mit Eclipse 1/15 Inhaltsverzeichnis 1 ÜBER... 3 2 INSTALLATION... 4 2.1 INSTALLATION VON ECLIPSE... 4 2.2 INSTALLATION VON PYDEV... 4 3

Mehr

Git II. Dezentrale Versionsverwaltung im Team

Git II. Dezentrale Versionsverwaltung im Team Git II Dezentrale Versionsverwaltung im Team Themenbereiche Arbeit mit Remote Repositories Austausch zwischen Repositories Änderungen rückgängig machen Zusammenarbeit über Workflows Git hat mehr als nur

Mehr

Installation und Benutzung AD.NAV.ZipTools

Installation und Benutzung AD.NAV.ZipTools Installation und Benutzung AD.NAV.ZipTools Version 1.0.0.0 ALTENBRAND Datentechnik GmbH Am Gelicht 5 35279 Neustadt (Hessen) Tel: 06692/202 290 Fax: 06692/204 741 email: support@altenbrand.de Die Komponente

Mehr

Programmierprojekt. Anne0e Bieniusa Sommersemester 2014

Programmierprojekt. Anne0e Bieniusa Sommersemester 2014 Programmierprojekt Anne0e Bieniusa Sommersemester 2014 Phasen der So;ware- Entwicklung Planungsphase DefiniConsphase Entwurfsphase ImplemenCerungsphase Testphase Wasserfall- Modell Einführungs- und Wartungsphase

Mehr

31.01.2013. Vorlesung Programmieren. Versionskontrollsysteme. Ziele von VCS. Versionskontrolle

31.01.2013. Vorlesung Programmieren. Versionskontrollsysteme. Ziele von VCS. Versionskontrolle Vorlesung Programmieren Versionskontrolle Dr. Dennis Pfisterer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/pfisterer Versionskontrollsysteme Wie organisiert man die

Mehr

Cross-Platform Apps mit HTML5/JS/CSS/PhoneGap

Cross-Platform Apps mit HTML5/JS/CSS/PhoneGap Cross-Platform Apps mit HTML5/JS/CSS/PhoneGap Proseminar Objektorientiertes Programmieren mit.net und C# Florian Schulz Institut für Informatik Software & Systems Engineering Einführung Was hat Cross-Plattform

Mehr

Kapitel 6. Vererbung

Kapitel 6. Vererbung 1 Kapitel 6 2 Ziele Das sprinzip der objektorientierten Programmierung verstehen Und in Java umsetzen können Insbesondere folgende Begriffe verstehen und anwenden können: Ober/Unterklassen Subtyping Überschreiben

Mehr

Kapitel 6. Vererbung

Kapitel 6. Vererbung 1 Kapitel 6 2 Ziele Das sprinzip der objektorientierten Programmierung verstehen Und in Java umsetzen können Insbesondere folgende Begriffe verstehen und anwenden können: Ober/Unterklassen Subtyping Überschreiben

Mehr

Die Projek*ools. Files, Git, Tickets & Time

Die Projek*ools. Files, Git, Tickets & Time Die Projek*ools Files, Git, Tickets & Time Agenda Die Abgabe von Dokumenten: Files Das Pflegen von Software: Versionskontrolle mit Git Management von Anforderungen: Tickets Management von Zeit: Time Files

Mehr

Allgemeines. Architektur der Anwendung. Server starten. Anmeldung

Allgemeines. Architektur der Anwendung. Server starten. Anmeldung Allgemeines Architektur der Anwendung Grundsätzlich führen viele Wege nach Rom bzw. es gibt nicht den einen Weg, wie die gestellte Aufgabe mit Magnolia gelöst werden muss. Es wäre problemlos möglich, eine

Mehr

Hochschule Niederrhein Grundlagen der Prof. Dr. Nitsche Fachbereich 03 Java Programmierung Bachelor Informatik SS 2015 Übung 1. Grundlagen von Java

Hochschule Niederrhein Grundlagen der Prof. Dr. Nitsche Fachbereich 03 Java Programmierung Bachelor Informatik SS 2015 Übung 1. Grundlagen von Java Grundlagen von Java Aufgabe 1: Typen und Zuweisungen in Java Welche der folgenden Java-Anweisungen sind fehlerhaft? Handelt es sich um einen Compiler- oder einen Laufzeitfehler? Anmerkung: Folgefehler

Mehr

KURZANLEITUNG DUPLICITY MIT CLOUD OBJECT STORAGE

KURZANLEITUNG DUPLICITY MIT CLOUD OBJECT STORAGE KURZANLEITUNG DUPLICITY MIT CLOUD OBJECT STORAGE Version 1.12 01.07.2014 SEITE _ 2 INHALTSVERZEICHNIS 1. Einleitung...Seite 03 2. Einrichtung des Systems...Seite 04 3. Erzeugen eines Backup-Skripts...Seite

Mehr

JDroidLib mit Eclipse (Mac/Linux/Windows)

JDroidLib mit Eclipse (Mac/Linux/Windows) JDroidLib mit Eclipse (Mac/Linux/Windows) Version 1.3, 25. März 2013 (Unter Windows besser die ADT-Bundle Version installieren, siehe entsprechende Anleitung) Vorbereitungen: 1. JDK SE neuste Version installieren,

Mehr

Apache Subversion (SVN)

Apache Subversion (SVN) Apache Subversion (SVN) Datamining und Sequenzanalyse Marvin Meusel, Sascha Winter 18.10.2013 Apache Subversion (SVN) Datamining und Sequenzanalyse Marvin Meusel, Sascha Winter 18.10.2013 git Datamining

Mehr

Das Build Tool Ant. Sebastian Mancke, mancke@mancke-software.de

Das Build Tool Ant. Sebastian Mancke, mancke@mancke-software.de Das Build Tool Ant Sebastian Mancke, mancke@mancke-software.de Grundlagen Motivation Bei der Übersetzung und Pflege von Software treten viele, gleich bleibende Arbeitsschritte auf. Übersetzen des Codes

Mehr

Apps-Entwicklung mit Netbeans

Apps-Entwicklung mit Netbeans JDroid mit Netbeans Seite 1 Apps-Entwicklung mit Netbeans Version 2.2, 30. April 2013 Vorbereitungen: 1. JDK SE neuste Version installieren, (http://www.oracle.com/technetwork/java/javase/downloads/index.html)

Mehr

Hello World in Java. Der Weg zum ersten Java-Programm

Hello World in Java. Der Weg zum ersten Java-Programm Vorwort Hello World in Java Der Weg zum ersten Java-Programm Diese Anleitung wurde unter Windows XP verfasst. Grundsätzlich sollte sie auch unter späteren Windows Versionen wie Windows Vista oder Windows

Mehr

ALM mit Visual Studio Online. Philip Gossweiler Noser Engineering AG

ALM mit Visual Studio Online. Philip Gossweiler Noser Engineering AG ALM mit Visual Studio Online Philip Gossweiler Noser Engineering AG Was ist Visual Studio Online? Visual Studio Online hiess bis November 2013 Team Foundation Service Kernstück von Visual Studio Online

Mehr

Parallele und funktionale Programmierung Wintersemester 2013/14. 8. Übung Abgabe bis 20.12.2013, 16:00 Uhr

Parallele und funktionale Programmierung Wintersemester 2013/14. 8. Übung Abgabe bis 20.12.2013, 16:00 Uhr 8. Übung Abgabe bis 20.12.2013, 16:00 Uhr Aufgabe 8.1: Zeigerverdopplung Ermitteln Sie an folgendem Beispiel den Rang für jedes Listenelement sequentiell und mit dem in der Vorlesung vorgestellten parallelen

Mehr

Software Bedienungsanleitung. ENiQ Access Management: Online-Inbetriebnahme

Software Bedienungsanleitung. ENiQ Access Management: Online-Inbetriebnahme Software Bedienungsanleitung ENiQ Access Management: Online-Inbetriebnahme V1.0 April 2015 Inhaltsverzeichnis 1 Voraussetzungen... 3 2 Allgemeine Hinweise... 3 3 Generelle Einstellungen... 3 4 Dienste

Mehr

Übersicht. Informatik 2 Teil 3 Anwendungsbeispiel für objektorientierte Programmierung

Übersicht. Informatik 2 Teil 3 Anwendungsbeispiel für objektorientierte Programmierung Übersicht 3.1 Modell Konto 3.2 Modell Konto - Erläuterungen 3.3 Benutzer Ein- und Ausgabe mit Dialogfenster I 3.4 Benutzer Ein- und Ausgabe mit Dialogfenster II 3.5 Klassen- und Objekteigenschaften des

Mehr

git & git-flow Jens Sandmann 14.12.2013 Warpzone Münster e.v. Jens Sandmann (WZ) git & git-flow 14.12.2013 1 / 31

git & git-flow Jens Sandmann 14.12.2013 Warpzone Münster e.v. Jens Sandmann (WZ) git & git-flow 14.12.2013 1 / 31 git & git-flow Jens Sandmann Warpzone Münster e.v. 14.12.2013 Jens Sandmann (WZ) git & git-flow 14.12.2013 1 / 31 Überblick 1 git Versionskontrolle Allgemein VCS mit git 2 git flow 3 git nutzen 4 Anhang

Mehr

Smartphone Entwicklung mit Android und Java

Smartphone Entwicklung mit Android und Java Smartphone Entwicklung mit Android und Java predic8 GmbH Moltkestr. 40 53173 Bonn Tel: (0228)5552576-0 www.predic8.de info@predic8.de Was ist Android Offene Plattform für mobile Geräte Software Kompletter

Mehr

Verteilte Versionskontrolle mit GIT. 17.04.2012 - Dortmund Ansgar Brauner - GreenPocket GmbH - Köln

Verteilte Versionskontrolle mit GIT. 17.04.2012 - Dortmund Ansgar Brauner - GreenPocket GmbH - Köln Verteilte Versionskontrolle mit GIT 17.04.2012 - Dortmund Ansgar Brauner - GreenPocket GmbH - Köln 1 über mich 32 Jahre alt Softwareentwickler bei der Firma GreenPocket in Köln Java EE Entwickler und Rails

Mehr

Variablen manipulieren per JDI

Variablen manipulieren per JDI Variablen manipulieren per JDI Zusammenfassung Jede moderne Java IDE verfügt über eine mächtige und dennoch meist einfach zu bedienende Benutzeroberfläche die das finden von Fehlern in lokalen oder entfernt

Mehr

Programmieren I. Die Programmiersprache Java. www.kit.edu. Institut für Angewandte Informatik

Programmieren I. Die Programmiersprache Java. www.kit.edu. Institut für Angewandte Informatik Programmieren I Die Programmiersprache Java KIT Universität des Landes Baden-Württemberg und nationales Großforschungszentrum in der Helmholtz-Gemeinschaft www.kit.edu Eigenschaften von Java Java ist eine

Mehr

Java Einführung Programmcode

Java Einführung Programmcode Java Einführung Programmcode Inhalt dieser Einheit Programmelemente Der erste Programmcode Die Entwicklungsumgebung: Sun's Java Software Development Kit (SDK) Vom Code zum Ausführen des Programms 2 Wiederholung:

Mehr

SVN-Einführung für das SEP DS und CM. Julian Timpner, Stefan Brenner, Stephan Rottmann

SVN-Einführung für das SEP DS und CM. Julian Timpner, Stefan Brenner, Stephan Rottmann SVN-Einführung für das SEP DS und CM Julian Timpner, Stefan Brenner, Stephan Rottmann 23. April 2014 Subversion (SVN) - Allgemeines Versionsverwaltung für Dokumente Primär für reine Textdateien (*.txt,

Mehr

Git in großen Projekten

Git in großen Projekten Git in großen Projekten Einsatz von Submodulen und Subtrees René Preißel (rp@etosquare.de) Buchhandlung Lehmanns, 16.10.2013 1 Über Mich René Preißel (rp@etosquare.de) Freiberuflicher Berater, Entwickler,

Mehr

Seminararbeit Ruby Uno Kartenspiel

Seminararbeit Ruby Uno Kartenspiel Seminararbeit Ruby Uno Kartenspiel Autor: Fabian Merki Fabian Merki 05.11.2006 1 von 10 Inhaltsverzeichnis Einleitung... 3 Die Idee... 4 Design und Implementierung in Ruby... 5 Testing... 7 Startbefehle...

Mehr

2. Sie sind der Administrator Ihres Netzwerks, das den SBS 2011 Standard ausführt.

2. Sie sind der Administrator Ihres Netzwerks, das den SBS 2011 Standard ausführt. Arbeitsblätter Der Windows Small Business Server 2011 MCTS Trainer Vorbereitung zur MCTS Prüfung 70 169 Aufgaben Kapitel 1 1. Sie sind der Administrator Ihres Netzwerks, das den SBS 2011 Standard ausführt.

Mehr

Ant in Eclipse Starthilfe

Ant in Eclipse Starthilfe IN DIESER KURSEINHEIT Einleitung o Um was geht's eigentlich? Hello World o Das Ant Skript Mehrere Targets und Properties o Hello World Ausgabe Ant Launch Configurations o Definition o Modifikation o Nutzung

Mehr

ANT. Kurzvortrag von Manuel Schulze. mschulze@inf.fu-berlin.de

ANT. Kurzvortrag von Manuel Schulze. mschulze@inf.fu-berlin.de ANT Kurzvortrag von Manuel Schulze mschulze@inf.fu-berlin.de ANT Überblick Teilprojekt der Apache Software Foundation [1] ANT ist Opensource Build-Tool ähnlich wie make (?) jedoch voll auf Java zugeschnitten

Mehr

RÖK Typo3 Dokumentation

RÖK Typo3 Dokumentation 2012 RÖK Typo3 Dokumentation Redakteur Sparten Eine Hilfe für den Einstieg in Typo3. Innpuls Werbeagentur GmbH 01.01.2012 2 RÖK Typo3 Dokumentation Inhalt 1) Was ist Typo3... 3 2) Typo3 aufrufen und Anmelden...

Mehr

Programmieren was ist das genau?

Programmieren was ist das genau? Programmieren was ist das genau? Programmieren heisst Computerprogramme herstellen (von griechisch programma für Vorschrift). Ein Computerprogramm ist Teil der Software eines Computers. Als Software bezeichnet

Mehr

Dezentrale Versionsverwaltung

Dezentrale Versionsverwaltung Dezentrale Versionsverwaltung mit GIT with that guy 14.08.2012 Lars Kumbier 1 Versionsverwaltung? 14.08.2012 Lars Kumbier 2 Versionsverwaltung? Speichern unterschiedlicher Entwicklungsschritte (oder Versionen)

Mehr

KURZANLEITUNG CLOUD BLOCK STORAGE

KURZANLEITUNG CLOUD BLOCK STORAGE KURZANLEITUNG CLOUD BLOCK STORAGE Version 1.12 01.07.2014 SEITE _ 2 INHALTSVERZEICHNIS 1. Einleitung......Seite 03 2. Anlegen eines dauerhaften Block Storage...Seite 04 3. Hinzufügen von Block Storage

Mehr

Einführung in das Microsoft.NET-Framework. Programmiersprache C# MEF Das Managed Extensibility Framework. André Kunz

Einführung in das Microsoft.NET-Framework. Programmiersprache C# MEF Das Managed Extensibility Framework. André Kunz Einführung in das Microsoft.NET-Framework Programmiersprache C# MEF Das Managed Extensibility Framework André Kunz 21.09.2010 1 In dieser Einführung bekommen Sie einen kurzen Einstieg in das.net-framework

Mehr

Java-IDE-Vergleich Seite 1 / 5

Java-IDE-Vergleich Seite 1 / 5 Java-IDE-Vergleich Seite 1 / 5 Java-IDEs im Vergleich 1. Getestete IDEs: Borland JBuilder 3 Professional Edition IBM Visual Age 3 Entry Edition Sun Forte 1.01 Community Edition Microsoft Visual J++ 6.0

Mehr

Software Engineering I

Software Engineering I Software I Übungsblatt 1 + 2 Claas Pinkernell Technische Universität Braunschweig http://www.sse.cs.tu-bs.de/ Seite 2 Welche Werkzeuge? Programmiersprache Java Integrierte Entwicklungsumgebung Eclipse

Mehr

Microsoft PowerPoint 2013 YouTube-Video einfügen

Microsoft PowerPoint 2013 YouTube-Video einfügen Hochschulrechenzentrum Justus-Liebig-Universität Gießen Microsoft PowerPoint 2013 YouTube-Video einfügen YouTube-Video einfügen in PowerPoint 2013 Seite 1 von 6 Inhaltsverzeichnis Einleitung... 2 Vorbereitungen...

Mehr

Web und Mobile Apps Programmieren mit Dart

Web und Mobile Apps Programmieren mit Dart Web und Mobile Apps Programmieren mit Dart Marco Jakob Kalaidos Fachhochschule Schweiz majakob@gmx.ch Abstract: Bisher war es kaum realistisch, im Anfängerunterricht mobile oder webbasierte Applikationen

Mehr

Byte-Taxi. Bedienungsanleitung. Seite 1 von 8

Byte-Taxi. Bedienungsanleitung. Seite 1 von 8 Byte-Taxi Bedienungsanleitung Seite 1 von 8 Inhaltsverzeichnis 1. Beschreibung 3 2. Systemvoraussetzungen 4 3. Installationsanleitung 5 4. Bedienung 6 5. Infos & Kontakt 8 Seite 2 von 8 1. Beschreibung

Mehr

Apache Subversion (SVN)

Apache Subversion (SVN) Apache Subversion (SVN) Datamining und Sequenzanalyse Marvin Meusel, Sascha Winter 19.10.2012 Apache Subversion (SVN) Datamining und Sequenzanalyse Marvin Meusel, Sascha Winter 19.10.2012 git Datamining

Mehr

VWA Rhein-Neckar Dipl.-Ing. Thomas Kloepfer. Kommunikation I (Internet) Übung 4 PHP

VWA Rhein-Neckar Dipl.-Ing. Thomas Kloepfer. Kommunikation I (Internet) Übung 4 PHP VWA Rhein-Neckar Dipl.-Ing. Thomas Kloepfer Kommunikation I (Internet) Übung 4 PHP SS 2004 Inhaltsverzeichnis 1. PHP die serverseitige Programmiersprache...1 1.1. PHP - Bereiche in HTML definieren...1

Mehr

Einführung in die Cross-Plattform Entwicklung Das Intel App Framework

Einführung in die Cross-Plattform Entwicklung Das Intel App Framework Einführung in die Cross-Plattform Entwicklung Das Intel App Framework Einführung Dieses Hands-on-Lab (HOL) macht den Leser mit dem Intel App Framework vom Intel XDK vertraut. Es wird Schritt für Schritt

Mehr

Erste Schritte mit HG 2

Erste Schritte mit HG 2 Erste Schritte mit HG 2 Malte Ried FH-Gießen Version: 1.0 21. November 2003 Inhaltsverzeichnis 1 Einführung 2 2 Allgemeines 2 2.1 Koordinaten...................................... 2 2.2 Farben.........................................

Mehr

BNG Bootloader Documentation

BNG Bootloader Documentation BNG Bootloader Documentation Release 0.2 Elias Medawar, Yves Peissard, Simon Honegger, Jonathan Stoppani 20. 04. 2010 Inhaltsverzeichnis 1 Abstract 1 2 Architektur 3 2.1 Überblick.................................................

Mehr

Um asynchrone Aufrufe zwischen Browser und Web Anwendung zu ermöglichen, die Ajax Hilfsmittel DWR ist gebraucht.

Um asynchrone Aufrufe zwischen Browser und Web Anwendung zu ermöglichen, die Ajax Hilfsmittel DWR ist gebraucht. Technisches Design Inhalt Design Übersicht Menü und DispatcherServlet DWR Servlet Viewer Servlets Controllers Managers Sicherheit Anwendung Architektur Component Diagram Deployment Diagram Komponente Sequence

Mehr

Perzentile mit Hadoop ermitteln

Perzentile mit Hadoop ermitteln Perzentile mit Hadoop ermitteln Ausgangspunkt Ziel dieses Projektes war, einen Hadoop Job zu entwickeln, der mit Hilfe gegebener Parameter Simulationen durchführt und aus den Ergebnissen die Perzentile

Mehr

http://www.cis.upenn.edu/~bcpierce/unison/download/stable/unison- 2.9.1/

http://www.cis.upenn.edu/~bcpierce/unison/download/stable/unison- 2.9.1/ Einführung Was ist Unison? Unison ist ein Dateisynchronisationsprogramm für Windows und Unix. Es teilt sich viele Funktionen mit anderen Programmen, wie z.b. CVS und rsync. Folgend einige Vorteile des

Mehr

Einführung zu den Übungen aus Softwareentwicklung 1

Einführung zu den Übungen aus Softwareentwicklung 1 Einführung zu den Übungen aus Softwareentwicklung 1 Dipl.-Ing. Andreas Riener Universität Linz, Institut für Pervasive Computing Altenberger Straße 69, A-4040 Linz riener@pervasive.jku.at SWE 1 // Organisatorisches

Mehr

VIII: Vererbung. Unterklassen einer Klasse. Vererbung von Methoden und Instanzvariablen. Überschreiben von Methoden

VIII: Vererbung. Unterklassen einer Klasse. Vererbung von Methoden und Instanzvariablen. Überschreiben von Methoden VIII: Vererbung Unterklassen einer Klasse Vererbung von Methoden und Instanzvariablen Überschreiben von Methoden Vererbung als Realisierung einer is-a Beziehung. Informatik I VIII: Vererbung 259 Beispiel:

Mehr

MGE Datenanbindung in GeoMedia

MGE Datenanbindung in GeoMedia TIPPS & TRICKS MGE Datenanbindung in GeoMedia 10. September 2002 / AHU INTERGRAPH (Schweiz) AG Neumattstrasse 24, CH 8953 Dietikon Tel: 043 322 46 46 Fax: 043 322 46 10 HOTLINE: Telefon: 043 322 46 00

Mehr

IT Engineering Continuous Delivery. Development Tool Chain Virtualisierung, Packer, Vagrant und Puppet. Alexander Pacnik Karlsruhe, 20.05.

IT Engineering Continuous Delivery. Development Tool Chain Virtualisierung, Packer, Vagrant und Puppet. Alexander Pacnik Karlsruhe, 20.05. IT Engineering Continuous Delivery Development Tool Chain Virtualisierung, Packer, Vagrant und Puppet Alexander Pacnik Karlsruhe, 20.05.2014 Einleitung... worum es in diesem Vortrag geht Ziele Continuous

Mehr

White Paper. Embedded Treiberframework. Einführung

White Paper. Embedded Treiberframework. Einführung Embedded Treiberframework Einführung White Paper Dieses White Paper beschreibt die Architektur einer Laufzeitumgebung für Gerätetreiber im embedded Umfeld. Dieses Treiberframework ist dabei auf jede embedded

Mehr

4 Vererbung, Polymorphie

4 Vererbung, Polymorphie 4 Vererbung, Polymorphie Jörn Loviscach Versionsstand: 21. März 2014, 22:57 Die nummerierten Felder sind absichtlich leer, zum Ausfüllen beim Ansehen der Videos: http://www.j3l7h.de/videos.html This work

Mehr

git Änderungen verwalten mit git

git Änderungen verwalten mit git Änderungen verwalten mit git Wie arbeitet man am besten an einem Protokoll zusammen? PeP et al. Toolbox, 2014 2 Idee: Austausch über Mails PeP et al. Toolbox, 2014 3 Mails: Probleme Risiko, dass Änderungen

Mehr

Einführung in die Cross-Plattform Entwicklung Das Intel XDK

Einführung in die Cross-Plattform Entwicklung Das Intel XDK Einführung in die Cross-Plattform Entwicklung Das Intel XDK Einführung Dieses Hands-on-Lab (HOL) macht den Leser mit dem Intel XDK vertraut. Es wird Schritt für Schritt die erste eigene Hybrid-App entwickelt

Mehr

Groovy und CouchDB. Ein traumhaftes Paar. Thomas Westphal

Groovy und CouchDB. Ein traumhaftes Paar. Thomas Westphal Groovy und CouchDB Ein traumhaftes Paar Thomas Westphal 18.04.2011 Herzlich Willkommen Thomas Westphal Software Engineer @ adesso AG Projekte, Beratung, Schulung www.adesso.de thomas.westphal@adesso.de

Mehr

7 Plugins einbinden. 7.1 Beispiel»Die Taschenlampe«

7 Plugins einbinden. 7.1 Beispiel»Die Taschenlampe« 201 PhoneGap bringt einen standardisierten Hardwarezugriff für Smartphones mit. Aber was passiert, wenn Sie mehr wollen: Wenn Sie eine Hardware per Bluetooth ansprechen wollen oder Features der jeweiligen

Mehr

Technische Beschreibung: EPOD Server

Technische Beschreibung: EPOD Server EPOD Encrypted Private Online Disc Technische Beschreibung: EPOD Server Fördergeber Förderprogramm Fördernehmer Projektleitung Projekt Metadaten Internet Foundation Austria netidee JKU Linz Institut für

Mehr

SEMINARVORTRAG ANDROID ENTWICKLUNG ETIENNE KÖRNER EMBEDDED SYSTEMS SS2013 - HSRM

SEMINARVORTRAG ANDROID ENTWICKLUNG ETIENNE KÖRNER EMBEDDED SYSTEMS SS2013 - HSRM SEMINARVORTRAG ANDROID ENTWICKLUNG ETIENNE KÖRNER EMBEDDED SYSTEMS SS2013 - HSRM ÜBERSICHT Android Android Dalvik Virtuelle Maschine Android und Desktop Applikationen Android Entwicklung Tools R Activity

Mehr

Objektorientiertes Programmieren für Ingenieure

Objektorientiertes Programmieren für Ingenieure Uwe Probst Objektorientiertes Programmieren für Ingenieure Anwendungen und Beispiele in C++ 18 2 Von C zu C++ 2.2.2 Referenzen und Funktionen Referenzen als Funktionsparameter Liefert eine Funktion einen

Mehr

Apps-Entwicklung mit Eclipse

Apps-Entwicklung mit Eclipse JDroid mit Eclipse Seite 1 Apps-Entwicklung mit Eclipse Version 1.1, 30. April 2013 Vorbereitungen: 1. JDK installieren JDK SE neuste Version (64 oder 32 Bit) herunterladen und installieren (http://www.oracle.com/technetwork/java/javase/downloads/index.html)

Mehr

Einführung in Verteilte Versionskontrollsysteme. am Beispiel von Git

Einführung in Verteilte Versionskontrollsysteme. am Beispiel von Git Einführung in Verteilte Versionskontrollsysteme am Beispiel von Git Diplominformatiker (BA), Git Benutzer seit 2009 Daniel Böhmer Leibniz Institut für Troposphärenforschung 8. März 2012 Verteilte Versionskontrollsysteme/Git

Mehr

Mobile Applications. Adrian Nägeli, CTO bitforge AG

Mobile Applications. Adrian Nägeli, CTO bitforge AG Mobile Applications Adrian Nägeli, CTO bitforge AG Inhalt Vorstellung Marktübersicht Entwicklung Adrian Nägeli Dipl. Inf.-Ing FH Seit 2005 bei bitforge bitforge AG Standort Rapperswil-Jona Gründung 2004

Mehr

3.9 Grundelemente einer Benutzeroberfläche

3.9 Grundelemente einer Benutzeroberfläche 92 3 Grundlagen einer ios-anwendung 3.8.4 Target-Actions Einer der häufigsten Anwendungsfälle bei einer Oberfläche ist das Betätigen einer Schaltfläche durch einen Anwender, woraufhin eine bestimmte Aktion

Mehr

Einführung in Android. 9. Dezember 2014

Einführung in Android. 9. Dezember 2014 Einführung in Android 9. Dezember 2014 Was ist Android? Software für mobile Geräte: Betriebssystem Middleware Kernanwendungen Android SDK: Tools und APIs zur Entwicklung von Anwendungen auf der Android-Plattform

Mehr

URT Eclipse All in one

URT Eclipse All in one URT Eclipse All in one Das Paket Eclipse All in one enthält Programme und Einstellungen, die zum Programmieren mit Eclipse in Zusammenarbeit mit Subversion und ANT benötigt werden. Dieses Paket dient als

Mehr

Objektorientierte Programmierung. Kapitel 12: Interfaces

Objektorientierte Programmierung. Kapitel 12: Interfaces 12. Interfaces 1/14 Objektorientierte Programmierung Kapitel 12: Interfaces Stefan Brass Martin-Luther-Universität Halle-Wittenberg Wintersemester 2012/13 http://www.informatik.uni-halle.de/ brass/oop12/

Mehr

Zeiterfassungsanlage Handbuch

Zeiterfassungsanlage Handbuch Zeiterfassungsanlage Handbuch Inhalt In diesem Handbuch werden Sie die Zeiterfassungsanlage kennen sowie verstehen lernen. Es wird beschrieben wie Sie die Anlage einstellen können und wie das Überwachungsprogramm

Mehr

FAQ - Script gaesteform

FAQ - Script gaesteform FAQ - Script gaesteform www.kundencenter.ws 9. April 2009 Salvatore Spadaro 1 2 Inhaltsverzeichnis 1 Script - gaesteform 3 1.1 Welchen Funktionumfang bietet das Script gaesteform und welche Technik steckt

Mehr

Installation Anleitung für JTheseus und MS SQL Server 2000

Installation Anleitung für JTheseus und MS SQL Server 2000 Installation Anleitung für JTheseus und MS SQL Server 2000 Inhaltsverzeichnis 1 Installation der Datenbank 3 1.1 Erstellen der Datenbank 3 1.2 Tabellen und Minimal Daten einlesen 4 1.3 Benutzer JTheseus

Mehr

Java: Vererbung. Teil 3: super() www.informatikzentrale.de

Java: Vererbung. Teil 3: super() www.informatikzentrale.de Java: Vererbung Teil 3: super() Konstruktor und Vererbung Kindklasse ruft SELBSTSTÄNDIG und IMMER zuerst den Konstruktor der Elternklasse auf! Konstruktor und Vererbung Kindklasse ruft SELBSTSTÄNDIG und

Mehr

Software Engineering II

Software Engineering II Software Engineering II Codegenerierung für den SmartIO Editor mit der Modeling Workflow Engine Wintersemester 10/111 Fachgebiet Software Engineering Albert Zündorf / Wiederholung Bisher im Laufe des Semesters

Mehr

Übung zur Vorlesung Einführung in Software Engineering

Übung zur Vorlesung Einführung in Software Engineering Übung zur Vorlesung Einführung in Software Engineering Wintersemester 2012/13, Richard Bubel und Martin Hentschel Übungsblatt 5: Testen Abgabeformat: Reichen Sie Ihre Lösung per SVN als eine PDF-Datei

Mehr

Dokumentation Schulprojekt: Samba als Serverdienst

Dokumentation Schulprojekt: Samba als Serverdienst Dokumentation Schulprojekt: Samba als Serverdienst Sandra Schreiner und Sascha Lenhart 20. September 2007 Inhaltsverzeichnis 1 Einleitung 3 1.1 Projektbeschreibung.............................. 3 1.2 Projektziele...................................

Mehr

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck Javadoc Programmiermethodik Eva Zangerle Universität Innsbruck Überblick Einführung Java Ein erster Überblick Objektorientierung Vererbung und Polymorphismus Ausnahmebehandlung Pakete und Javadoc Spezielle

Mehr

CloudMatic V1.0. Inhalt

CloudMatic V1.0. Inhalt CloudMatic V1.0 Inhalt Einleitung... 2 CCUs hinzufügen... 3 meine-homematic.de... 4 Eigenes VPN... 4 View Editor... 5 Übersicht... 5 Allgemeine Einstellungen... 6 Kanäle hinzufügen... 6 Spezielle Kanäle...

Mehr

Visualisierung auf Büro PC s mit dem ibricks Widget

Visualisierung auf Büro PC s mit dem ibricks Widget Automation Server Visualisierung auf Büro PC s mit dem Widget Solutions Industriestrasse 25A CH-3178 Bösingen mail@.ch www..ch Tel +41 31 5 110 110 Fax+41 31 5 110 112 Solutions Bausteine zum intelligenten

Mehr

RIWA NetUpdater Tool für automatische Daten- und Softwareupdates

RIWA NetUpdater Tool für automatische Daten- und Softwareupdates RIWA NetUpdater Tool für automatische Daten- und Softwareupdates Grundlegendes... 1 Ausführbare Dateien und Betriebsmodi... 2 netupdater.exe... 2 netstart.exe... 2 netconfig.exe... 2 nethash.exe... 2 Verzeichnisse...

Mehr

an Hand eines Beispiels Konsole

an Hand eines Beispiels Konsole Versionskontrolle an Hand eines Beispiels Konsole 1 / 14 PAUL SCHEREMET Inhaltsverzeichnis Einleitung 3 Das Repository anlegen (init) 4 Das erste Modul importieren (import) 5 Module auschecken (checkout

Mehr

Datensicherung. Beschreibung der Datensicherung

Datensicherung. Beschreibung der Datensicherung Datensicherung Mit dem Datensicherungsprogramm können Sie Ihre persönlichen Daten problemlos Sichern. Es ist möglich eine komplette Datensicherung durchzuführen, aber auch nur die neuen und geänderten

Mehr

Übungspaket 19 Programmieren eigener Funktionen

Übungspaket 19 Programmieren eigener Funktionen Übungspaket 19 Programmieren eigener Funktionen Übungsziele: Skript: 1. Implementierung und Kodierung eigener Funktionen 2. Rekapitulation des Stack-Frames 3. Parameterübergabe mittels Stack und Stack-Frame

Mehr

IMBA. Installationsanleitung. SQL Server-Datenbankadapter. Das Instrument für den fähigkeitsgerechten Personaleinsatz

IMBA. Installationsanleitung. SQL Server-Datenbankadapter. Das Instrument für den fähigkeitsgerechten Personaleinsatz Das Instrument für den fähigkeitsgerechten Personaleinsatz IMBA SQL Server-Datenbankadapter Installationsanleitung gefördert durch das Bundesministerium für Gesundheit und Soziale Sicherung Vorbereitung

Mehr

OpenGL. (Open Graphic Library)

OpenGL. (Open Graphic Library) OpenGL (Open Graphic Library) Agenda Was ist OpenGL eigentlich? Geschichte Vor- und Nachteile Arbeitsweise glscene OpenGL per Hand Debugging Trend Was ist OpenGL eigentlich? OpenGL ist eine Spezifikation

Mehr

Fertigprodukte. Bruno Blumenthal und Roger Meyer. 18. Juli 2003. Zusammenfassung

Fertigprodukte. Bruno Blumenthal und Roger Meyer. 18. Juli 2003. Zusammenfassung Fertigprodukte Bruno Blumenthal und Roger Meyer 18. Juli 2003 Zusammenfassung Dieses Dokument beschreibt die Fertigprodukte welche im Projekt NetWACS eingesetzt werden sollen. Es soll als Übersicht dienen

Mehr

ECLIPSE PDT* + MAMP-PRO mit XDebug

ECLIPSE PDT* + MAMP-PRO mit XDebug ECLIPSE PDT* + MAMP-PRO mit XDebug Wozu überhaupt? Was brauch ich? Was muss ich einstellen? Wo steht mehr darüber? 2012 Klemens Heinen http://zwergnilpferd.de Xampp/Lamp-User? macht nix - ist ähnlich.

Mehr

SiteAudit Knowledge Base. Einrichtung & Verwaltung der Reporting Web Site

SiteAudit Knowledge Base. Einrichtung & Verwaltung der Reporting Web Site SiteAudit Knowledge Base Einrichtung & Verwaltung der Reporting Web Site Mai 2010 In diesem Beitrag: Funktionsübersicht Einrichtung RWS Verwaltung der Report-Ordner Zugriff auf SiteAudit Datenbanken SiteAudit

Mehr