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 & Mai 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 86 I

3 Listings 1 Eclipse Optionen in gradle setzen Gradle in der Kommandozeile Eine Assert Methode für zwei 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 Die verschiedenen Layer eines absgdx Programmes 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) III

5 35 Beispiel der Debugansicht (In-Menu) 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äß 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 große Anzahl von Spielen, vor allem sogenannte mobile Games teilen sich eine Reihe von Merkmalen. So ist ein Großteil 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 zwei dimensionale Draufsicht oder eine Seitenansicht. Oft wird hier eine 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 (siehe 2.5). 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 damit einfache 2D Spiele mit einer Tilemap und einem Entity-System entwickeln zu können. Unser Framework übernimmt die Verwaltung von Maps, Entities und optional Elementen wie Menü und Netzwerk. Durch LibGDX kann man das Projekt direkt am PC testen. 1

8 2 Plattformunabhängigkeit Ein entscheidender Vorteil, dass 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 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öße 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. Außerdem 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. 2

9 Abbildung 1: Die verschiedenen Layer eines absgdx Programmes 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 3

10 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. 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 großer 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ößte 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 fließen 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

11 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. 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. Außerdem 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. Außerdem 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. Sprache Erweiterbar Kostenlos Performance Auf PC testbar Dynamik Ausführung Cocos2D-x C++ O D Compile MonoGame C# + - O + 3D JIT Unity3D C# - + O + 3D Compile LibGDX Java D JIT Tabelle 1: Vergleich verschiedener Spieleframeworks und Engines Zum Schluss blieb nur noch LibGDX übrig: Wir haben uns für LibGDX entschieden weil es all un- 5

12 seren 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. 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. 6

13 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. Außerdem 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 Abbildung 2: Git Network Graph mit smartgit 7

14 Außerdem 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.[1, 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. Abbildung 3: Screenshot SmartGit 8

15 3.1.2 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 groß 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ßerdem Dateien, wie die IDE-Projektdateien, automatisch. 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, ausgehend vom Anfangsprojekt. Gradle lädt dann diese Bibliotheken, falls sie noch nicht auf dem Rechner vorhanden sind. Dies hat auch den Vorteil, falls eine Bibliothek öfters im Abhängigkeitsbaum auftaucht sie trotzdem nur einmal geladen werden muss.[2, S. 55] Gradle unterstützt viele verschiedene Repositories in welcher nach fehlenden Bibliotheken gesucht werden kann, standardmäßig wird jedoch die Maven Central Repository 2 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

16 Konfiguration Die Konfiguration geschieht über build.gradle Dateien welche in der Sprache Groovy geschrieben sind.[3][s. 73] absgdx ist ein Multiprojekt, dies bedeutet, dass es aus mehreren Gradle Projekten besteht mit jeweils eigenen Konfigurationen die voneinander abhängen. [2, 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. Abbildung 4: 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: 10

17 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 ) 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 zu- 11

18 sammenhä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. 12

19 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 5: Beispiel der junit Test Anzeige Das Ziel der Unittests ist es einen Großteil 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. [4, S 62] 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

20 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ößen ausgeführt. Einmal mit normal großer Map, einmal mit einer Map der Größe 1x1 und auch noch mit verschiedenen anderen Größen. 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

21 Android Build Probleme Ein Problem, dass wir mit junit jedoch hatten war der Android Build Vorgang. Anfangs waren alle unsere Unittests in dem absgdx-framework Projekt. Deshalb war dieses Projekt von junit abhängig und 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 ausschließen. 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

22 3.1.4 Continuous Integration Zusammen mit den Unittests und Git wenden wir auch noch eine dritte Praktik an: Continuous Integration. Immer wenn jemand auf den main-branch unseres Repositories pusht wird automatisch ein Skript auf einem Buildserver ausgeführt. Dieses Skript clont das 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 1 welcher mit einer Textdatei ".travis.yml" im Repository root konfiguriert wird. language: java before_install: - chmod +x gradlew install:./gradlew desktop:assemble script: -./gradlew absgdx framework:check -./gradlew absgdx test:check -./gradlew core:check -./gradlew desktop:check notifications: recipients: - m...@m...de - b...@g...com 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 gepusht wurde, ohne den Code vorher getestet zu haben, dann schlägt das ganze Skript fehl und es wird eine an alle recipients geschickt

23 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: Abbildung 6: Beispiel der Online Ansicht von TravisCI 17

24 3.1.5 Metrics Code Metrics Um eine Übersicht über den aktuellen Stand unseres Codes zu erhalten setzten wir das Metrics Tool Metrics ein. Abbildung 7: absgdx Metrics Es zeigt eine Reihe an Statistiken über den Quellcode an und warnt wenn Teile des Codes komplex 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 18

25 Abbildung 8: 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. 19

26 3.1.6 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 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üßig 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 20

27 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: - 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ßerdem 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. "travis@travis-ci.org" git config --global user.name "travis-ci" git clone --branch=gh-pages Mikescher/absGDX gh-pages cd gh-pages git rm -rf./javadoc 21

28 cp -Rf $HOME/tmp_jd./javadoc fi git add -f. git status git commit -m "Lastest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages" git push -f origin gh-pages 22

29 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 große Anzahl an Texturen in einer einzigen Datei zusammengefasst sind. Abbildung 9: 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 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 23

30 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äßig 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öße 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. Außerdem 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äßig sind in absgdx sechs verschiedene MapScaleResolver enthalten: FixedMapScaleResolver Dies ist der einfachste MapScaleResolver, er gibt immer eine konstante, vorher bestimmte Größe zurück. (zum Beispiel 60px) 24

31 Abbildung 10: 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. 25

32 Abbildung 11: 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. 26

33 Abbildung 12: 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. 27

34 Abbildung 13: 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. 28

35 Abbildung 14: 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öße 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 außer Kraft setzen. 29

36 Abbildung 15: 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 groß 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:[5, S 232f.] public Rectangle getvisiblemapbox() { float tilesize = mapscaleresolver.gettilesize(owner. getscreenwidth(), owner.getscreenheight(), map.height, map. width); 30

37 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ößen, 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 groß 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

38 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öße 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 großen 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. 32

39 3.2.2 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 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 16: 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 so- 33

40 mit ein einfaches Rechteck. Außerdem 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. 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. Außerdem stehen Optionen zur Verfügung wie Drehung oder Verzerrung der Textur. Auch muss die gezeichnete Textur nicht mit der Position oder den Ausmaßen 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ößeren 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 Ausmaßen wie das Entity addfullcollisioncircle(): Fügt ein Kollisions Kreis hinzu, welcher das Entity komplett ausfüllt 34

41 addfullcollisiontriangle(aligncorner4 align): Fügt ein Kollisions Dreieck hinzu, welches drei Ecken des Entities benutzt (Abhängig von dem übergebenen Alignment). 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 onpassivemovementcollide aufgerufen. Wurde vorher festgelegt, dass die beiden Entities sich nicht überschneiden dann entspricht dies einem Zusammenstoß, 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 35

42 bewegen. Andernfalls wäre das Spiel nur auf einem Rechner mit gleichen oder ähnlichen UPS Updates per second wie denen des Entwicklerrechners spielbar. Außerdem erschwert dies das Programmieren der allgemeinen Spiellogik. In den meisten Fällen denkt man über Objekte nicht in der Form von "An 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 große 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; 36

43 } } 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[6]. 37

44 Abbildung 17: 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öße 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. 38

45 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ößer 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 39

46 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 18: 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äßig existiert jedoch kein Zwang diese zu 40

47 implementieren. Gerade deshalb sollte man dies jedoch nur machen wenn man schon Erfahrung mit dem Framework hat und mit Sicherheit weiß 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. 41

48 3.2.3 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äßig 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. Abbildung 19: 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 42

49 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. 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. 43

50 3.2.4 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:[7, S 73] Der Algorithmus sollte auch bei vielen Entities auf der Karte noch schnell sein und die Update-Time nicht unnötig erhöhen [7, S 14f] 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. 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. Außerdem 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. 44

51 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. [5, S 500] 45

52 Abbildung 20: 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 Übermaß 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 46

53 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 [5, S 499]. Dies liegt daran, dass eine Multiplikation um mehrere Größenordnungen 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 umschließende Kreise abschätzt und diese zuerst kollidieren lässt. Nur wenn die umschließenden Kreise sich überschneiden muss man dann den komplizierteren Schritt machen und die genauen Geometrien kollidieren lassen. Außer 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 21: 3 Möglichkeiten einer Kreis-Dreieck Kollision 47

54 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. 48

55 Abbildung 22: 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 23: 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); 49

56 } 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. [7, S 32] 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) 50

57 } 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 groß wie die Karte sind ausgeschlossen). Unsere Lösung liegt darin die Datenstruktur zu ändern. Bisher wurden die CollisionGeometrien in einer einzigen großen 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 groß wie die normalen Map Tiles zu haben. Dies ist 51

58 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öße 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 groß sind wie die MapTiles (2 1 = 2) und ein Wert von -1 halb so große (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 außerhalb 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 52

59 dieses Radius werden dann mit der entsprechenden Geometrie gefüllt. Dieser Collision-Radius berechnet sich aus dem umschließenden 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. Außerdem muss die Kugel in jedem Schritt selbst ihre Kollisionen überprüfen, da es sonst keiner für sie tut. 53

60 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. Außerdem 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äßig hat. Außerdem 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äßig 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 groß 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 54

61 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. Außerdem 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 24: Performance Graph der CollisionMap 55

62 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 außer 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 ) : 56

63 Abbildung 25: 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 ) 57

64 Abbildung 26: 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 27: 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) 58

65 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 28: 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 59

66 Abbildung 29: 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 30: 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. 60

67 Abbildung 31: 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 61

68 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ößte "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.[7, S 18] 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 [5, 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.[7, S 11ff] Einfacher ist es eine konstante Update-Rate aufrecht zu erhalten und keine extrem dünne Entities zu verwenden, wo Kollisionen wichtig sind. 62

69 Abbildung 32: 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 63

70 ihr lässt sich dies auf die Objekte einschränken mit der das Entity auch wirklich zusammenstoßen 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öße). 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. 64

71 3.2.5 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. 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 33: 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 außer null als wahr gewertet und Zahlen werden immer als wahr gewertet. 65

72 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. RootProperty: Dies ist ähnlich einer MetaProperty kann jedoch keine Abhängigkeiten haben und bildet somit die Wurzel des Baumes. 66

73 3.2.6 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 34: Beispiel der Debugansicht (In-Game) Außerdem 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. 67

74 Abbildung 35: 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). 68

75 3.2.7 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. Außerdem 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. Abbildung 36: 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. 69

76 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, außerdem 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. Außerdem kann man diesen Hintergrund benutzen um einfach eine einfarbige Fläche als Hintergrund zu erhalten ohne eine extrem große Textur in den SingleBackground zu laden. 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. 70

77 Abbildung 37: 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. 71

78 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 große 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öße 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 38: 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 72

79 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 73

80 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 Außer dem MenuContainer werden alle Komponenten angezeigt. Standardmäßig 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 39: 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. Außerdem 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 74

81 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. 75

82 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ößen oder dynamische Größenä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 Maßen beruhen oder die Komponenten dynamisch und relativ zur verfügbaren Fläche definieren. 76

83 Das AGDXML Format Abbildung 40: 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 (außer 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 Maß in der Einheit Pixel angeben oder einen Prozentwert, welcher relativ zum übergeordneten Element interpretiert wird. Diese Prozentwerte sind die 77

84 erste Möglichkeit um dynamische Menüs zu erzeugen. Außerdem 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 große 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-/Zellenmaße gibt es drei verschiedene Definitionsmöglichkeiten: 78

85 Name Schreibweise Funktion PIXEL Zahlenwert alleine angeben Die Spalte/Reihe bekommt exakte die festgelegten Maße PERCENTAGE Zahlenwert mit angefügtem Prozentzeichen Die Größe 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äß 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 groß 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" > <grid container="true"> <grid.columndefinitions width="20, 2*, 10, 1*, 20" /> <grid.rowdefinitions height="8\%, 40, 4\%, 1*, 4\%" /> 79

86 <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 41: 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 wird. Außerdem kann man Sehen wie sich das Menü unter verschiedenen Auflösungen verhält. 80

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

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

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

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress.

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress. Anmeldung http://www.ihredomain.de/wp-admin Dashboard Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress. Das Dashboard gibt Ihnen eine kurze Übersicht, z.b. Anzahl der Beiträge,

Mehr

Eine eigene Seite auf Facebook-Fanseiten einbinden und mit einem Tab verbinden.

Eine eigene Seite auf Facebook-Fanseiten einbinden und mit einem Tab verbinden. Eine eigene Seite auf Facebook-Fanseiten einbinden und mit einem Tab verbinden. Nach den Änderungen die Facebook vorgenommen hat ist es einfacher und auch schwerer geworden eigene Seiten einzubinden und

Mehr

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt Inhaltsverzeichnis Aufgabe... 1 Allgemein... 1 Active Directory... 1 Konfiguration... 2 Benutzer erstellen... 3 Eigenes Verzeichnis erstellen... 3 Benutzerkonto erstellen... 3 Profil einrichten... 5 Berechtigungen

Mehr

OP-LOG www.op-log.de

OP-LOG www.op-log.de Verwendung von Microsoft SQL Server, Seite 1/18 OP-LOG www.op-log.de Anleitung: Verwendung von Microsoft SQL Server 2005 Stand Mai 2010 1 Ich-lese-keine-Anleitungen 'Verwendung von Microsoft SQL Server

Mehr

Qt-Projekte mit Visual Studio 2005

Qt-Projekte mit Visual Studio 2005 Qt-Projekte mit Visual Studio 2005 Benötigte Programme: Visual Studio 2005 Vollversion, Microsoft Qt 4 Open Source s. Qt 4-Installationsanleitung Tabelle 1: Benötigte Programme für die Qt-Programmierung

Mehr

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite.

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. ewon - Technical Note Nr. 003 Version 1.2 Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. Übersicht 1. Thema 2. Benötigte Komponenten 3. Downloaden der Seiten und aufspielen auf

Mehr

Die Dateiablage Der Weg zur Dateiablage

Die Dateiablage Der Weg zur Dateiablage Die Dateiablage In Ihrem Privatbereich haben Sie die Möglichkeit, Dateien verschiedener Formate abzulegen, zu sortieren, zu archivieren und in andere Dateiablagen der Plattform zu kopieren. In den Gruppen

Mehr

DOKUMENTATION VOGELZUCHT 2015 PLUS

DOKUMENTATION VOGELZUCHT 2015 PLUS DOKUMENTATION VOGELZUCHT 2015 PLUS Vogelzucht2015 App für Geräte mit Android Betriebssystemen Läuft nur in Zusammenhang mit einer Vollversion vogelzucht2015 auf einem PC. Zusammenfassung: a. Mit der APP

Mehr

WOT Skinsetter. Nun, erstens, was brauchen Sie für dieses Tool zu arbeiten:

WOT Skinsetter. Nun, erstens, was brauchen Sie für dieses Tool zu arbeiten: WOT Skinsetter WOT Skinsetter steht für World of Tanks skinsetter (WOTS von nun an). Mit diesen Tool können Sie Skins importieren und ändern, wann immer Sie möchten auf einfache Weise. Als World of Tanks

Mehr

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein. Schritt 1: Installation des Javacompilers JDK. Der erste Start mit Eclipse Bevor Sie den Java-Compiler installieren sollten Sie sich vergewissern, ob er eventuell schon installiert ist. Gehen sie wie folgt

Mehr

Hex Datei mit Atmel Studio 6 erstellen

Hex Datei mit Atmel Studio 6 erstellen Hex Datei mit Atmel Studio 6 erstellen Es werden generell keine Atmel Studio Dateien ins Repository geladen, da jeder seine Dateien an anderen Orten liegen hat und weil nicht jeder das Atmel Studio 6 benutzt.

Mehr

Task: Nmap Skripte ausführen

Task: Nmap Skripte ausführen Task: Nmap Skripte ausführen Inhalt Einfache Netzwerkscans mit NSE Ausführen des Scans Anpassung der Parameter Einleitung Copyright 2009-2015 Greenbone Networks GmbH Herkunft und aktuellste Version dieses

Mehr

! " # $ " % & Nicki Wruck worldwidewruck 08.02.2006

!  # $  % & Nicki Wruck worldwidewruck 08.02.2006 !"# $ " %& Nicki Wruck worldwidewruck 08.02.2006 Wer kennt die Problematik nicht? Die.pst Datei von Outlook wird unübersichtlich groß, das Starten und Beenden dauert immer länger. Hat man dann noch die.pst

Mehr

Im Folgenden wird Ihnen an einem Beispiel erklärt, wie Sie Excel-Anlagen und Excel-Vorlagen erstellen können.

Im Folgenden wird Ihnen an einem Beispiel erklärt, wie Sie Excel-Anlagen und Excel-Vorlagen erstellen können. Excel-Schnittstelle Im Folgenden wird Ihnen an einem Beispiel erklärt, wie Sie Excel-Anlagen und Excel-Vorlagen erstellen können. Voraussetzung: Microsoft Office Excel ab Version 2000 Zum verwendeten Beispiel:

Mehr

Kurzanleitung. MEYTON Aufbau einer Internetverbindung. 1 Von 11

Kurzanleitung. MEYTON Aufbau einer Internetverbindung. 1 Von 11 Kurzanleitung MEYTON Aufbau einer Internetverbindung 1 Von 11 Inhaltsverzeichnis Installation eines Internetzugangs...3 Ist mein Router bereits im MEYTON Netzwerk?...3 Start des YAST Programms...4 Auswahl

Mehr

Kleines Handbuch zur Fotogalerie der Pixel AG

Kleines Handbuch zur Fotogalerie der Pixel AG 1 1. Anmelden an der Galerie Um mit der Galerie arbeiten zu können muss man sich zuerst anmelden. Aufrufen der Galerie entweder über die Homepage (www.pixel-ag-bottwartal.de) oder über den direkten Link

Mehr

Switching. Übung 7 Spanning Tree. 7.1 Szenario

Switching. Übung 7 Spanning Tree. 7.1 Szenario Übung 7 Spanning Tree 7.1 Szenario In der folgenden Übung konfigurieren Sie Spanning Tree. An jeweils einem Switch schließen Sie Ihre Rechner über Port 24 an. Beide Switche sind direkt über 2 Patchkabel

Mehr

1. Zuerst muss der Artikel angelegt werden, damit später die Produktvarianten hinzugefügt werden können.

1. Zuerst muss der Artikel angelegt werden, damit später die Produktvarianten hinzugefügt werden können. Produktvarianten und Downloads erstellen Produktvarianten eignen sich um Artikel mit verschiedenen Optionen wie bspw. ein Herrenhemd in den Farben blau, grün und rot sowie in den Größen S, M und L zu verkaufen.

Mehr

Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten

Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten Der Konfigurations-Assistent wurde entwickelt, um die unterschiedlichen ANTLOG-Anwendungen auf den verschiedensten Umgebungen automatisiert

Mehr

Abschluss Version 1.0

Abschluss Version 1.0 Beschreibung Der Abschluss wird normalerweise nur einmal jährlich durchgeführt. Dieses Tech-Note soll helfen, diesen doch seltenen aber periodisch notwendigen Vorgang problemlos durchzuführen. Abschlussvarianten

Mehr

Anleitung über den Umgang mit Schildern

Anleitung über den Umgang mit Schildern Anleitung über den Umgang mit Schildern -Vorwort -Wo bekommt man Schilder? -Wo und wie speichert man die Schilder? -Wie füge ich die Schilder in meinen Track ein? -Welche Bauteile kann man noch für Schilder

Mehr

SFTP SCP - Synology Wiki

SFTP SCP - Synology Wiki 1 of 6 25.07.2009 07:43 SFTP SCP Aus Synology Wiki Inhaltsverzeichnis 1 Einleitung 1.1 Grundsätzliches 2 Voraussetzungen 2.1 Allgemein 2.2 für SFTP und SCP 3 Installation 3.1 Welche openssl Version 3.2

Mehr

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software Wie erzeugt man ein Fotobuch im Internet bei Schlecker Seite Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software Punkt 12 bis 24: -Wir arbeiten mit der Software 8-16 -Erstellung

Mehr

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 von Markus Mack Stand: Samstag, 17. April 2004 Inhaltsverzeichnis 1. Systemvorraussetzungen...3 2. Installation und Start...3 3. Anpassen der Tabelle...3

Mehr

GITS Steckbriefe 1.9 - Tutorial

GITS Steckbriefe 1.9 - Tutorial Allgemeines Die Steckbriefkomponente basiert auf der CONTACTS XTD Komponente von Kurt Banfi, welche erheblich modifiziert bzw. angepasst wurde. Zuerst war nur eine kleine Änderung der Komponente für ein

Mehr

Gruppenrichtlinien und Softwareverteilung

Gruppenrichtlinien und Softwareverteilung Gruppenrichtlinien und Softwareverteilung Ergänzungen zur Musterlösung Bitte lesen Sie zuerst die gesamte Anleitung durch! Vorbemerkung: Die Begriffe OU (Organizational Unit) und Raum werden in der folgenden

Mehr

4D Server v12 64-bit Version BETA VERSION

4D Server v12 64-bit Version BETA VERSION 4D Server v12 64-bit Version BETA VERSION 4D Server v12 unterstützt jetzt das Windows 64-bit Betriebssystem. Hauptvorteil der 64-bit Technologie ist die rundum verbesserte Performance der Anwendungen und

Mehr

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Version 1.0 Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten In unserer Anleitung zeigen wir Dir, wie Du Blogbeiträge

Mehr

Java Script für die Nutzung unseres Online-Bestellsystems

Java Script für die Nutzung unseres Online-Bestellsystems Es erreichen uns immer wieder Anfragen bzgl. Java Script in Bezug auf unser Online-Bestell-System und unser Homepage. Mit dieser Anleitung möchten wir Ihnen einige Informationen, und Erklärungen geben,

Mehr

Installationsanleitungen

Installationsanleitungen Installationsanleitungen INPA SGBD-Entwicklungsumgebung (EDIABAS) INPA für Entwickler Bevor Sie EDIABAS / INPA installieren können, müssen Sie sich für den Ordner sgref auf smuc0900 freischalten lassen.

Mehr

INSTALLATION VON INSTANTRAILS 1.7

INSTALLATION VON INSTANTRAILS 1.7 INSTALLATION VON INSTANTRAILS 1.7 InstantRails 1.7 ist ein Paket, das Ruby, Rails, Apache, MySQL und andere Tools, z.b. phpmyadmin in vorkonfigurierter Form enthält. Das Paket muss in einem Verzeichnis

Mehr

Übung: Verwendung von Java-Threads

Übung: Verwendung von Java-Threads Übung: Verwendung von Java-Threads Ziel der Übung: Diese Übung dient dazu, den Umgang mit Threads in der Programmiersprache Java kennenzulernen. Ein einfaches Java-Programm, das Threads nutzt, soll zum

Mehr

Tutorial - www.root13.de

Tutorial - www.root13.de Tutorial - www.root13.de Netzwerk unter Linux einrichten (SuSE 7.0 oder höher) Inhaltsverzeichnis: - Netzwerk einrichten - Apache einrichten - einfaches FTP einrichten - GRUB einrichten Seite 1 Netzwerk

Mehr

Wo möchten Sie die MIZ-Dokumente (aufbereitete Medikamentenlisten) einsehen?

Wo möchten Sie die MIZ-Dokumente (aufbereitete Medikamentenlisten) einsehen? Anleitung für Evident Seite 1 Anleitung für Evident-Anwender: Einbinden der MIZ-Dokumente in Evident. Wo möchten Sie die MIZ-Dokumente (aufbereitete Medikamentenlisten) einsehen? Zunächst müssen Sie entscheiden,

Mehr

Daten Sichern mit dem QNAP NetBak Replicator 4.0

Daten Sichern mit dem QNAP NetBak Replicator 4.0 Daten Sichern mit dem QNAP NetBak Replicator 4.0 Was ist NetBak Replicator: Der NetBak Replicator ist ein Backup-Programm von QNAP für Windows, mit dem sich eine Sicherung von Daten in die Giri-Cloud vornehmen

Mehr

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC

In 12 Schritten zum mobilen PC mit Paragon Drive Copy 11 und Microsoft Windows Virtual PC PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER

Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER Abamsoft Finos in Verbindung mit der Webshopanbindung wurde speziell auf die Shop-Software shop to date von DATA BECKER abgestimmt. Mit

Mehr

Informationen zur Verwendung von Visual Studio und cmake

Informationen zur Verwendung von Visual Studio und cmake Inhaltsverzeichnis Informationen zur Verwendung von Visual Studio und cmake... 2 Erste Schritte mit Visual Studio... 2 Einstellungen für Visual Studio 2013... 2 Nutzung von cmake... 6 Installation von

Mehr

Artikel Schnittstelle über CSV

Artikel Schnittstelle über CSV Artikel Schnittstelle über CSV Sie können Artikeldaten aus Ihrem EDV System in das NCFOX importieren, dies geschieht durch eine CSV Schnittstelle. Dies hat mehrere Vorteile: Zeitersparnis, die Karteikarte

Mehr

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank In den ersten beiden Abschnitten (rbanken1.pdf und rbanken2.pdf) haben wir uns mit am Ende mysql beschäftigt und kennengelernt, wie man

Mehr

Erstellen einer digitalen Signatur für Adobe-Formulare

Erstellen einer digitalen Signatur für Adobe-Formulare Erstellen einer digitalen Signatur für Adobe-Formulare (Hubert Straub 24.07.13) Die beiden Probleme beim Versenden digitaler Dokumente sind einmal die Prüfung der Authentizität des Absenders (was meist

Mehr

FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox

FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox Bitte beachten: Der im folgenden beschriebene Provider "www.cwcity.de" dient lediglich als Beispiel. Cwcity.de blendet recht häufig

Mehr

Benutzerhandbuch MedHQ-App

Benutzerhandbuch MedHQ-App Benutzerhandbuch MedHQ-App T h o r D y n a m i c s G m b H A m B ü c h e n b e r g s k a m p 2 2 2 1 0 3 9 B ö r n s e n V e r s i o n 1. 0 S t a n d : 0 4 / 2 0 1 5 z u r M e d H Q - A p p - V e r s i

Mehr

GeoPilot (Android) die App

GeoPilot (Android) die App GeoPilot (Android) die App Mit der neuen Rademacher GeoPilot App machen Sie Ihr Android Smartphone zum Sensor und steuern beliebige Szenen über den HomePilot. Die App beinhaltet zwei Funktionen, zum einen

Mehr

Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10. Technische Informationen (White Paper)

Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10. Technische Informationen (White Paper) Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10 Technische Informationen (White Paper) Inhaltsverzeichnis 1. Über dieses Dokument... 3 2. Überblick... 3 3. Upgrade Verfahren... 4

Mehr

Bilder zum Upload verkleinern

Bilder zum Upload verkleinern Seite 1 von 9 Bilder zum Upload verkleinern Teil 1: Maße der Bilder verändern Um Bilder in ihren Abmessungen zu verkleinern benutze ich die Freeware Irfan View. Die Software biete zwar noch einiges mehr

Mehr

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht:

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Beiträge erstellen in Joomla Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Abbildung 1 - Kontrollzentrum Von hier aus kann man zu verschiedene Einstellungen

Mehr

Dokumentation IBIS Monitor

Dokumentation IBIS Monitor Dokumentation IBIS Monitor Seite 1 von 16 11.01.06 Inhaltsverzeichnis 1. Allgemein 2. Installation und Programm starten 3. Programmkonfiguration 4. Aufzeichnung 4.1 Aufzeichnung mitschneiden 4.1.1 Inhalt

Mehr

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang sysplus.ch outlook - mail-grundlagen Seite 1/8 Outlook Mail-Grundlagen Posteingang Es gibt verschiedene Möglichkeiten, um zum Posteingang zu gelangen. Man kann links im Outlook-Fenster auf die Schaltfläche

Mehr

1 topologisches Sortieren

1 topologisches Sortieren Wolfgang Hönig / Andreas Ecke WS 09/0 topologisches Sortieren. Überblick. Solange noch Knoten vorhanden: a) Suche Knoten v, zu dem keine Kante führt (Falls nicht vorhanden keine topologische Sortierung

Mehr

Arbeiten mit UMLed und Delphi

Arbeiten mit UMLed und Delphi Arbeiten mit UMLed und Delphi Diese Anleitung soll zeigen, wie man Klassen mit dem UML ( Unified Modeling Language ) Editor UMLed erstellt, in Delphi exportiert und dort so einbindet, dass diese (bis auf

Mehr

Informationen zum neuen Studmail häufige Fragen

Informationen zum neuen Studmail häufige Fragen 1 Stand: 15.01.2013 Informationen zum neuen Studmail häufige Fragen (Dokument wird bei Bedarf laufend erweitert) Problem: Einloggen funktioniert, aber der Browser lädt dann ewig und zeigt nichts an Lösung:

Mehr

Der Kalender im ipad

Der Kalender im ipad Der Kalender im ipad Wir haben im ipad, dem ipod Touch und dem iphone, sowie auf dem PC in der Cloud einen Kalender. Die App ist voreingestellt, man braucht sie nicht laden. So macht es das ipad leicht,

Mehr

Primzahlen und RSA-Verschlüsselung

Primzahlen und RSA-Verschlüsselung Primzahlen und RSA-Verschlüsselung Michael Fütterer und Jonathan Zachhuber 1 Einiges zu Primzahlen Ein paar Definitionen: Wir bezeichnen mit Z die Menge der positiven und negativen ganzen Zahlen, also

Mehr

Dokumentation von Ük Modul 302

Dokumentation von Ük Modul 302 Dokumentation von Ük Modul 302 Von Nicolas Kull Seite 1/ Inhaltsverzeichnis Dokumentation von Ük Modul 302... 1 Inhaltsverzeichnis... 2 Abbildungsverzeichnis... 3 Typographie (Layout)... 4 Schrift... 4

Mehr

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge Ab der Version forma 5.5 handelt es sich bei den Orientierungshilfen der Architekten-/Objektplanerverträge nicht

Mehr

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC PARAGON Technologie GmbH, Systemprogrammierung Heinrich-von-Stephan-Str. 5c 79100 Freiburg, Germany Tel. +49 (0) 761 59018201 Fax +49 (0) 761 59018130 Internet www.paragon-software.com Email sales@paragon-software.com

Mehr

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1 CMS.R. Bedienungsanleitung Modul Cron Revision 1 Copyright 10.09.2009 www.sruttloff.de CMS.R. - 1 - WOZU CRON...3 VERWENDUNG...3 EINSTELLUNGEN...5 TASK ERSTELLEN / BEARBEITEN...6 RECHTE...7 EREIGNISSE...7

Mehr

SANDBOXIE konfigurieren

SANDBOXIE konfigurieren SANDBOXIE konfigurieren für Webbrowser und E-Mail-Programme Dies ist eine kurze Anleitung für die grundlegenden folgender Programme: Webbrowser: Internet Explorer, Mozilla Firefox und Opera E-Mail-Programme:

Mehr

Patch Management mit

Patch Management mit Patch Management mit Installation von Hotfixes & Patches Inhaltsverzeichnis dieses Dokuments Einleitung...3 Wie man einen Patch installiert...4 Patch Installation unter UliCMS 7.x.x bis 8.x.x...4 Patch

Mehr

Installationsanleitung Maschinenkonfiguration und PP s. Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18.

Installationsanleitung Maschinenkonfiguration und PP s. Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18. Installationsanleitung Maschinenkonfiguration und PP s Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18.Februar 2015 Inhaltsverzeichnis 1 Einbinden der Postprozessoren... 3 1.1

Mehr

sm@rt-tan plus Flickerfeld bewegt sich nicht

sm@rt-tan plus Flickerfeld bewegt sich nicht Technischer Hintergrund Um die Verwendung des Verfahrens Sm@rt-TAN plus des neuen sicheren TAN- Verfahrens so komfortabel wie möglich zu gestalten, wurde eine Möglichkeit geschaffen, die Angaben einer

Mehr

Programme im Griff Was bringt Ihnen dieses Kapitel?

Programme im Griff Was bringt Ihnen dieses Kapitel? 3-8272-5838-3 Windows Me 2 Programme im Griff Was bringt Ihnen dieses Kapitel? Wenn Sie unter Windows arbeiten (z.b. einen Brief schreiben, etwas ausdrucken oder ein Fenster öffnen), steckt letztendlich

Mehr

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER Inhalt 1 Einleitung... 1 2 Einrichtung der Aufgabe für die automatische Sicherung... 2 2.1 Die Aufgabenplanung... 2 2.2 Der erste Testlauf... 9 3 Problembehebung...

Mehr

Speichern. Speichern unter

Speichern. Speichern unter Speichern Speichern unter Speichern Auf einem PC wird ständig gespeichert. Von der Festplatte in den Arbeitspeicher und zurück Beim Download Beim Kopieren Beim Aufruf eines Programms Beim Löschen Beim

Mehr

Die Beschreibung bezieht sich auf die Version Dreamweaver 4.0. In der Version MX ist die Sitedefinition leicht geändert worden.

Die Beschreibung bezieht sich auf die Version Dreamweaver 4.0. In der Version MX ist die Sitedefinition leicht geändert worden. In einer Website haben Seiten oft das gleiche Layout. Speziell beim Einsatz von Tabellen, in denen die Navigation auf der linken oder rechten Seite, oben oder unten eingesetzt wird. Diese Anteile der Website

Mehr

Workshop: Eigenes Image ohne VMware-Programme erstellen

Workshop: Eigenes Image ohne VMware-Programme erstellen Workshop: Eigenes Image ohne VMware-Programme erstellen Normalerweise sind zum Erstellen neuer, kompatibler Images VMware-Programme wie die Workstation, der ESX-Server oder VMware ACE notwendig. Die Community

Mehr

Step by Step Webserver unter Windows Server 2003. von Christian Bartl

Step by Step Webserver unter Windows Server 2003. von Christian Bartl Step by Step Webserver unter Windows Server 2003 von Webserver unter Windows Server 2003 Um den WWW-Server-Dienst IIS (Internet Information Service) zu nutzen muss dieser zunächst installiert werden (wird

Mehr

Anleitung zum Extranet-Portal des BBZ Solothurn-Grenchen

Anleitung zum Extranet-Portal des BBZ Solothurn-Grenchen Anleitung zum Extranet-Portal des BBZ Solothurn-Grenchen Inhalt Anleitung zum Extranet-Portal des BBZ Solothurn-Grenchen 2.2 Installation von Office 2013 auf Ihrem privaten PC 2.3 Arbeiten mit den Microsoft

Mehr

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren Lineargleichungssysteme: Additions-/ Subtraktionsverfahren W. Kippels 22. Februar 2014 Inhaltsverzeichnis 1 Einleitung 2 2 Lineargleichungssysteme zweiten Grades 2 3 Lineargleichungssysteme höheren als

Mehr

Installation und Inbetriebnahme von Microsoft Visual C++ 2010 Express

Installation und Inbetriebnahme von Microsoft Visual C++ 2010 Express Howto Installation und Inbetriebnahme von Microsoft Visual C++ 2010 Express Peter Bitterlich Markus Langer 12. Oktober 2012 Zusammenfassung Dieses Dokument erklärt Schritt für Schritt die Installation

Mehr

Powermanager Server- Client- Installation

Powermanager Server- Client- Installation Client A Server Client B Die Server- Client- Funktion ermöglicht es ein zentrales Powermanager Projekt von verschiedenen Client Rechnern aus zu bedienen. 1.0 Benötigte Voraussetzungen 1.1 Sowohl am Server

Mehr

Ihre Interessentendatensätze bei inobroker. 1. Interessentendatensätze

Ihre Interessentendatensätze bei inobroker. 1. Interessentendatensätze Ihre Interessentendatensätze bei inobroker Wenn Sie oder Ihre Kunden die Prozesse von inobroker nutzen, werden Interessentendatensätze erzeugt. Diese können Sie direkt über inobroker bearbeiten oder mit

Mehr

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen.

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen. Datenbank-Verschlüsselung mit DbDefence und Webanwendungen. In diesem Artikel werden wir Ihnen zeigen, wie Sie eine Datenbank verschlüsseln können, um den Zugriff einzuschränken, aber trotzdem noch eine

Mehr

Sichern der persönlichen Daten auf einem Windows Computer

Sichern der persönlichen Daten auf einem Windows Computer Sichern der persönlichen Daten auf einem Windows Computer DIRECTION DES SERVICES IT SERVICE DIT-MI DIREKTION DER IT-DIENSTE DIENSTSTELLE DIT-MI 1/9 1 Inhaltsverzeichnis 2 Einleitung... 3 3 Outlook Daten...

Mehr

Wie halte ich Ordnung auf meiner Festplatte?

Wie halte ich Ordnung auf meiner Festplatte? Wie halte ich Ordnung auf meiner Festplatte? Was hältst du von folgender Ordnung? Du hast zu Hause einen Schrank. Alles was dir im Wege ist, Zeitungen, Briefe, schmutzige Wäsche, Essensreste, Küchenabfälle,

Mehr

Nutzung der VDI Umgebung

Nutzung der VDI Umgebung Nutzung der VDI Umgebung Inhalt 1 Inhalt des Dokuments... 2 2 Verbinden mit der VDI Umgebung... 2 3 Windows 7... 2 3.1 Info für erfahrene Benutzer... 2 3.2 Erklärungen... 2 3.2.1 Browser... 2 3.2.2 Vertrauenswürdige

Mehr

OpenVPN unter Linux mit KVpnc Stand: 16. Mai 2013

OpenVPN unter Linux mit KVpnc Stand: 16. Mai 2013 1 Vorwort OpenVPN unter Linux mit KVpnc Stand: 16. Mai 2013 Folgende Beschreibung wurde mit einem Ubuntu 7.10 mit Kernel 2.6.22-14, OpenVPN 2.0.9 und KVpnc 0.9.1-rc1 getestet. Ein weiterer erfolgreicher

Mehr

Kurzanleitung zu. von Daniel Jettka 18.11.2008

Kurzanleitung zu. von Daniel Jettka 18.11.2008 Kurzanleitung zu Tigris.org Open Source Software Engineering Tools von Daniel Jettka 18.11.2008 Inhaltsverzeichnis 1.Einführung...1 2.Das Projektarchivs...3 2.1.Anlegen des Projektarchivs...3 2.2.Organisation

Mehr

Mit jedem Client, der das Exchange Protokoll beherrscht (z.b. Mozilla Thunderbird mit Plug- In ExQulla, Apple Mail, Evolution,...)

Mit jedem Client, der das Exchange Protokoll beherrscht (z.b. Mozilla Thunderbird mit Plug- In ExQulla, Apple Mail, Evolution,...) Das tgm steigt von Novell Group Wise auf Microsoft Exchange um. Sie können auf ihre neue Exchange Mailbox wie folgt zugreifen: Mit Microsoft Outlook Web Access (https://owa.tgm.ac.at) Mit Microsoft Outlook

Mehr

Datensicherung. Mögliche Vorgehensweisen:

Datensicherung. Mögliche Vorgehensweisen: Datensicherung Car&GO! Daten können schnell und mit hoher Sicherheit mit dem mitgelieferten Programm Backup.exe gesichert werden. Das Programm ist in jedem Verzeichnis enthalten aus dem das Cargo-Hauptprogramm

Mehr

Eigenen Farbverlauf erstellen

Eigenen Farbverlauf erstellen Diese Serie ist an totale Neulinge gerichtet. Neu bei PhotoLine, evtl. sogar komplett neu, was Bildbearbeitung betrifft. So versuche ich, hier alles einfach zu halten. Ich habe sogar PhotoLine ein zweites

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

Datensicherung und Wiederherstellung

Datensicherung und Wiederherstellung Dokumentation Datensicherung und Wiederherstellung Versionsverzeichnis Version: Datum: Revisionsgrund: Version 1.0 Januar 2011 Erste Ausgabe www.babe-informatik.ch 1/7 Datensicherung von Voraussetzung

Mehr

Zwischenablage (Bilder, Texte,...)

Zwischenablage (Bilder, Texte,...) Zwischenablage was ist das? Informationen über. die Bedeutung der Windows-Zwischenablage Kopieren und Einfügen mit der Zwischenablage Vermeiden von Fehlern beim Arbeiten mit der Zwischenablage Bei diesen

Mehr

FTP-Leitfaden RZ. Benutzerleitfaden

FTP-Leitfaden RZ. Benutzerleitfaden FTP-Leitfaden RZ Benutzerleitfaden Version 1.4 Stand 08.03.2012 Inhaltsverzeichnis 1 Einleitung... 3 1.1 Zeitaufwand... 3 2 Beschaffung der Software... 3 3 Installation... 3 4 Auswahl des Verbindungstyps...

Mehr

Netzwerk einrichten unter Windows

Netzwerk einrichten unter Windows Netzwerk einrichten unter Windows Schnell und einfach ein Netzwerk einrichten unter Windows. Kaum ein Rechner kommt heute mehr ohne Netzwerkverbindungen aus. In jedem Rechner den man heute kauft ist eine

Mehr

Informatik I Tutorial

Informatik I Tutorial ETH Zürich, D-INFK/D-BAUG Herbstsemester 2015 Dr. Martin Hirt Daniel Jost Informatik I Tutorial Dieses Tutorial hat zum Ziel, die notwendigen Tools auf dem eigenen Computer zu installieren, so dass ihr

Mehr

TeamSpeak3 Einrichten

TeamSpeak3 Einrichten TeamSpeak3 Einrichten Version 1.0.3 24. April 2012 StreamPlus UG Es ist untersagt dieses Dokument ohne eine schriftliche Genehmigung der StreamPlus UG vollständig oder auszugsweise zu reproduzieren, vervielfältigen

Mehr

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Amt für Informatik Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Anleitung vom 12. September 2009 Version: 1.0 Ersteller: Ressort Sicherheit Zielgruppe: Benutzer von SSLVPN.TG.CH Kurzbeschreib:

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

Der einfache Weg zum CFX-Demokonto

Der einfache Weg zum CFX-Demokonto Der einfache Weg zum CFX-Demokonto Diese Anleitung hilft Ihnen bei der Eröffnung eines Demokontos beim CFX Broker. Jeder Schritt bis zur vollständigen Eröffnung wird Ihnen im Folgenden erklärt. Zur besseren

Mehr

.htaccess HOWTO. zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage

.htaccess HOWTO. zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage .htaccess HOWTO zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage Stand: 21.06.2015 Inhaltsverzeichnis 1. Vorwort...3 2. Verwendung...4 2.1 Allgemeines...4 2.1 Das Aussehen der.htaccess

Mehr

Um dies zu tun, öffnen Sie in den Systemeinstellungen das Kontrollfeld "Sharing". Auf dem Bildschirm sollte folgendes Fenster erscheinen:

Um dies zu tun, öffnen Sie in den Systemeinstellungen das Kontrollfeld Sharing. Auf dem Bildschirm sollte folgendes Fenster erscheinen: Einleitung Unter MacOS X hat Apple die Freigabe standardmäßig auf den "Public" Ordner eines Benutzers beschränkt. Mit SharePoints wird diese Beschränkung beseitigt. SharePoints erlaubt auch die Kontrolle

Mehr