te cre¨ eren met events voor een bestaand spel
door
Dennis Laurence van den Berg
Scriptiebegeleider: dr. Rein Smedinga Tweede begeleider: dr. Henk Bekker
Rijksuniversiteit Groningen 3 augustus 2013
Scriptie is geschreven ter vervulling van de eisen voor een Bachelor of Science diploma (BSc.) van Informatica.
De scriptie beschrijft het proces van het ontwikkelen van een eigen bedachte Editor, waarmee de gebruiker levels kan cre¨eren voor een spel op het Android
platform. Het is van belang dat de Editor overzichtelijk en
gebruiksvriendelijk is, zodanig dat een nieuwe gebruiker gemakkelijk bekend raakt met de functionaliteit en geen uitgebreide uitleg nodig heeft. De Editor bestaat uit twee onderdelen, enerzijds de Level Editor om simpele objecten te cre¨eren en daarvoor eigenschappen in te stellen. Anderzijds een Event Editor,
waarmee bepaald kan worden welke gebeurtenissen plaatsvinden, op welke plek en op welk tijdstip.
Met behulp van een agile software-ontwikkelingsmethode is de Editor ontwikkeld. Deze scriptie beschrijft welke beslissingen gedurende het proces genomen zijn, welke problemen ontstaan zijn en hoe deze opgelost zijn. Om te bepalen of de doelstelling van het project behaald is, is er een usability test gedaan waarin een aantal personen gebruik hebben gemaakt van de Editor en
deze beoordeeld hebben.
I. Introductie 10
1. Editors in het algemeen 10
2. Het spel 10
2.1. Genre . . . 10
2.2. Besturing . . . 10
II. Doelstelling 11 3. Editor, het originele idee 11 3.1. Te weinig tijd . . . 11
4. Object Editor 11 4.1. Stopgezet . . . 11
5. Editor, uitbreidingen 12 6. Uiteindelijke doelstelling 12 III. Concept 13 7. Levels en Events 13 8. User Interface 13 9. Software design keuze 13 9.1. Programmeertaal . . . 13
9.2. Alternatieven . . . 14
10. Ontwikkelmethode 14 10.1. Agile Modeling-Driven Development . . . 14
IV. Ontwikkeling 15 11. Veel voorkomend ontwerp-patroon 15 11.1. Bridge patroon . . . 15
12. IT0: Editor Basis 15 12.1. Model . . . 15
12.2. Ontwerp . . . 16
12.3. Implementatie . . . 16
13. IT1: Level Editor, toevoegen objecten 17 13.1. Model . . . 17
13.2. Ontwerp . . . 18
13.3. Implementatie . . . 18
13.3.1. Objecten toevoegen . . . 19
14. IT2: Level Editor, objecten manipuleren 19
14.1. Model . . . 20
14.2. Ontwerp . . . 20
14.3. Implementatie . . . 20
14.3.1. Objecten selecteren en verslepen . . . 20
14.3.2. Object kopi¨eren, knippen en plakken . . . 20
15. IT3: Event Editor, Nodes 21 15.1. Model . . . 21
15.2. Ontwerp . . . 21
15.3. Implementatie . . . 22
15.3.1. Nodes toevoegen . . . 22
15.3.2. Edges toevoegen . . . 22
16. IT4: Level Editor : Eigenschappen 22 16.1. Model . . . 23
16.2. Ontwerp . . . 23
16.3. Implementatie . . . 24
17. IT5: Event Editor : Eigenschappen 24 17.1. Model . . . 24
17.2. Ontwerp . . . 25
17.3. Implementatie . . . 25
18. IT6: Event Editor : Particles 26 18.1. Model . . . 26
18.2. Ontwerp . . . 27
18.3. Implementatie . . . 27
18.3.1. ParticleObject toevoegen . . . 27
19. IT7: Level Editor : Integratie Procedural Level Builder 28 19.1. Model . . . 28
19.2. Ontwerp . . . 28
19.3. Implementatie . . . 29
19.3.1. Level Builder . . . 29
19.3.2. Geometry Builder . . . 29
19.4. Meer uitleg . . . 29
20. IT8: Level Editor : Manipulatie uitbreidingen 30 20.1. Model . . . 30
20.2. Ontwerp . . . 30
20.3. Implementatie . . . 31
20.3.1. Objecten roteren . . . 31
20.3.2. Objecten schalen . . . 31
20.3.3. Objecten vervormen . . . 31
20.4. Problemen . . . 31
21. IT9: Level opslaan en inladen 32 21.1. Ontwerp . . . 32
21.2.2. Xstream . . . 32
22. IT10: Koppelen met het spel 33 22.1. Model/ontwerp . . . 33
22.2. Implementatie . . . 34
22.2.1. Problemen . . . 34
22.3. Voorbeeld . . . 35
23. Spel ontwikkeling 36 V. Usability study 37 24. Personen 37 25. Eerste usability tests : Experts 37 26. Resultaten 37 26.1. Level Editor onderdeel . . . 38
26.2. Event Editor onderdeel . . . 38
26.3. Algemeen onderdeel . . . 40
26.4. Eindresultaat . . . 40
VI. Conclusie 41 27. Toekomstplannen 41 A. Usability study 43 B. Nodes 45 B.1. Event . . . 45
B.2. Trigger . . . 45
B.3. Port . . . 45
1. Het ontwerp van de Editor . . . 16
2. Het klassediagram van de Editor . . . 16
3. De GUI van de Editor . . . 17
4. Het model van de controllers. . . 17
5. Het klasse diagram van de controllers. . . 18
6. Het MVC patroon en Convexe/Concave vorm. . . 18
(a). Illustratie van het MVC-patroon. . . 18
(b). Convexe-(l) en concave vorm. . . 18
7. Het model van een GameObject. . . 20
8. Het complete model van EdNode. . . 21
(a). Het model van de EdNode. . . 21
(b). De subklasses van EdNode. . . 21
9. Het model van de controller in de Event Editor. . . 22
10. Model van de popup om eigenschappen in te stellen. . . 23
11. Klassediagram van de Popup klasse. . . 24
12. Het model van de eigenschappenbalk. . . 25
13. Klassediagrammen van de balk en node eigenschappen. . . 25
(a). Het klassediagram van de eigenschappenbalk. . . 25
(b). Het klassediagram van de eigenschappen voor een node. . . 25
14. Het uiteindelijke controller model van de Event Editor. . . 26
15. Het klassediagram van de ParticleObject klasse. . . 27
16. Het model van de structuur om basislevel te genereren. . . 28
17. Het klassediagram van de structuur om basislevel te genereren. . . 29
18. Het uiteindelijke model van de controller van de Level Editor. . . 30
19. Het uiteindelijke klassediagram van de controller van de Level Editor. . . 30
20. Het model en klassediagram van het externe formaat. . . 33
(a). Het model van het externe formaat. . . 33
(b). Het klassediagram van het externe formaat. . . 33
21. De koppeling tussen de Editor en het spel. . . 35
(a). Een screenshot van een level in de Editor. . . 35
(b). Een screenshot van een level in het spel. . . 35
22. Staafgrafiek van de gemiddelde tijden voor het Level Editor onderdeel. . . 38
23. Staafgrafiek van de gemiddelde tijden voor het Event Editor onderdeel. . . 39
24. Staafgrafiek van de gemiddelde tijden voor het Algemene onderdeel. . . 40
Lijst van tabellen
1. Gemiddelde tijd per Level Editor opdracht voor (on)ervaren gebruikers in min.sec. . . . 372. Gemiddelde tijd per Event Editor opdracht voor (on)ervaren gebruikers in min.sec. . . . 38
3. Gemiddelde tijd per Algemene opdracht voor (on)ervaren gebruikers in min.sec. . . 39
4. Gemiddelde cijfers voor de Editor. . . 40
5. Lijst van Event types. . . 45
6. Lijst van Trigger types. . . 45
7. Lijst van Port types. . . 45
Afkorting/term Betekenis
Editor Een hulpmiddel om een spel te ontwerpen Compatible Verenigbaar met
Modulair Makkelijk om functionaliteit toe te voegen of te verwijderen Android Een besturingssysteem voor smartphones en tablets
UPS United Parcel Service (koeriersdienst)
Swipen Het vegen met de vinger over het scherm van de tablet/smartphones Tikken Het aanraken van het scherm met de vinger
Level Editor De basis van de Editor om objecten te cre¨eren en te manipuleren Event Editor Een sectie binnen de Editor om Events te cre¨eren
Event Gebeurtenis in een spel
Trigger Een object dat een Event activeert
Object Editor Een Editor om objecten, of samengestelde objecten te cre¨eren (G)UI (Graphical) User Interace
Toolbar Een deel van de interface met hulpmiddelen om bepaalde acties uit te voeren Platform Besturingssysteem
Bytecode Machinetaal
API Application programming interface, verzameling definities Mouse-over Als een muisgestuurde aanwijzer over een bepaald deel beweegt Physics Engine Een systeem om krachten te berekenen op objecten
Graphics Engine Een systeem om berekeningen te doen op beelden Scope Geeft aan hoe ver de invloed van iets zich uitstrekt
Edge Een lijnsegment
Texture Een plaatje dat door de Graphics Engine wordt weergegeven
Deel I.
Introductie
I
n het ontwikkelen van spellen, zowel voor de pc, de console of zelfs voor de smartphone, gaat veel tijd en werk zitten. Het kost een ontwikkelaar dan ook een aantal jaren om een spel succesvol te ontwikkelen. Een succesvol spel wordt gekenmerkt door een goede verhaallijn en een leuke, spannende, of avontuurlijke spelervaring. ´E´en van de factoren die bijdragen aan de spelervaring is de spelomgeving, dan wel levels. Doordat het vaak gaat om erg grote omgevingen, zoals werelden, in combinatie met kleinere omgevingen in veelvoud, zoals grotten en andere kleinere levels, is het haast onmogelijk om alles handmatig te programmeren. Daarom gebruiken veel grote ontwikkelaarsbedrijven een hulpmiddel om dit ontwikkelproces te versnellen; een Editor.1. Editors in het algemeen
Een Editor is dus een hulpmiddel om omgevingen en/of levels te cre¨eren. De basis is het toevoegen van verschillende soorten objecten en het manipuleren daarvan. Denk daarbij aan het verplaatsen, roteren, schalen en verdraaien van die objecten. Een aantal editors zijn erg geavanceerd. Een voorbeeld hiervan is de Unreal Engine[7]. Met behulp hiervan is het mogelijk om een complete 3-dimensionale wereld te cre¨eren. Doordat deze editor zo geavanceerd en krachtig is, maken meerdere bedrijven er gebruik van om zo hun spel te ontwikkelen. Het programma moet dus ’compatible’ zijn met verschillende spellen.
Om dit voor elkaar te krijgen is het van belang dat het programma een goede structuur heeft en dat het modulair en gebruiksvriendelijk is. Het ontwerpen is dus al een grote uitdaging. Doordat een editor niet elke wens van een ontwikkelaar kan vervullen, kiezen bedrijven er soms voor om zelf te investeren in een nieuwe editor, dan toepasbaar is op hun spel.
2. Het spel
Het spel waarvoor de Editor ontwikkeld is, is een 2-dimensionaal actie spel voor de Android[8]
smartphones. De speler heeft de rol als Delivery Dan, een vriendelijke pakketbezorger in dienst van SUP (parodie op UPS ). Dan krijgt de opdracht om een aantal pakketjes te bezorgen in een ander melkwegstelsel. Onderweg komt hij verschillende hindernissen en vijanden tegen, waardoor hij zijn weg moet vinden. Dit spel is ontwikkeld door een team van informaticastudenten, waaronder ik, die in het laatste jaar van hun bachelor zitten.
2.1. Genre
Het spel, Delivery Dan, is een 2-dimensionaal avonturenspel, waarbij de speler zo ver mogelijk moet komen. Dat houdt in dat het spel in twee dimensies weergegeven wordt, er is dus geen diepte zichtbaar.
Bij dit spel is alles vanaf de zijkant te zien. Het was ook mogelijk geweest om het vanaf de bovenkant te laten zien, maar voor dit spel was dat geen oplossing.
2.2. Besturing
Het personage, Dan, loopt automatisch naar rechts, maar de speler moet op het juiste moment bukken en/of springen (met behulp van ’swipen’) en op de vijanden schieten (door te ’tikken’ op het scherm), zodat de pakketjes niet in gevaar komen. Mocht de speler toch geraakt worden, dan verliest hij een pakketje. Wanneer alle pakketjes kwijtgeraakt zijn, dan is het spel afgelopen en wordt Dan ontslagen.
Deel II.
Doelstelling
A
an het begin van het project, was duidelijk hoe de Editor ontwikkeld zou worden.Echter, zoals in grote software projecten, heeft vaak herstructurering plaatsgevon- den. Dit komt doordat er meer mensen betrokken waren bij het ontwikkelen van het spel, waarvoor de Editor initieel ontwikkeld werd. In deze sectie zal kort samengevat worden welke beslissingen genomen zijn en de verschillende idee¨en die ontstaan zijn. Daarna wordt de uiteindelijke doelstelling belicht.
3. Editor, het originele idee
Het originele idee voor de Editor was een simpel programma, bestaande uit twee onderdelen. Het eerste onderdeel was een Level Editor, waarmee objecten zoals cirkels, rechthoeken en andere convexe vormen gecre¨eerd konden worden. Daarnaast was het mogelijk om een ruimte te defini¨eren, wat de grenzen van het level aangaf. Het tweede onderdeel was de Event Editor, wat de gebruiker in staat stelde zelf te bepalen waar en wat voor een bepaalde gebeurtenis plaats zou vinden. Het laatste onderdeel zou binnen de scope van dit bachelorproject vallen. Het eerste onderdeel zou ook door mijzelf ontwikkeld worden, maar behoorde niet tot dit project.
3.1. Te weinig tijd
Aangezien de Graphics- en de Game-engine al in de afrondingsfase zaten, was het wachten op de Editor om de levels en gebeurtenissen te cre¨eren. Het ontwikkelen van de Event Editor kostte veel tijd, waardoor ik weinig tijd in de Level Editor kon steken. Aangezien de Event Editor tot de scope van mijn bachelorprojcet behoorde, en ik als enige verstand had van de Level Editor, was het niet mogelijk dat een ander persoon een aantal taken overnam. Later kwam dus het idee om de levels willekeurig te genereren. Een algoritme genereerde kleine stukken levels, die aan elkaar geplakt werden, en het bepaalde op welke plekken objecten geplaatst zouden worden. Deze objecten konden met een Object Editor gemaakt en opgeslagen worden. De Event Editor kon blijven bestaan als uitbreiding van de Object Editor, zodat mijn bachelorproject niet in gevaar kwam.
4. Object Editor
De levels zouden zoals gezegd willekeurig gegenereerd worden. Om deze levels compleet te maken, moest het opgevuld worden door objecten. Met behulp van een Object Editor, werd het maken en opslaan van kleine of grote objecten makkelijk. De Object Editor was een programma waarmee aparte objecten gemaakt konden worden, zoals een open schuur waar doorheen gelopen kan worden, maar ook overheen gelopen kan worden. Deze schuur zou dan bestaan uit verschillende vormen, samengevoegd tot ´e´en geheel. Dit object werd vervolgens opgeslagen als een bestand. Het spel zou dan zelf deze objecten inladen en, volgens bepaalde regels van positionering, op een bepaalde plek plaatsen in het level. Op deze manier zou elk level willekeurig opgevuld worden met objecten en landschap decoraties, dat telkens een uniek level opleverde.
4.1. Stopgezet
Het ontwikkelen van de Object Editor werd stopgezet, doordat een ander persoon bezig was met het ontwikkelen ervan, maar uiteindelijk te druk was met zijn eigen bachelorproject. Ik besloot om, in
plaats van het Object Editor project voort te zetten, terug te gaan naar mijn eigen Level Editor, aangezien ik daaraan gewerkt heb en dus precies weet hoe alles in elkaar zit.
5. Editor, uitbreidingen
Het ontwikkelen van de Editor (zie sectie 3) werd dus weer opgepakt. Er zijn een aantal uitbreidingen hiervoor ontwikkeld. In de Level Editor wordt er geen ruimte meer gedefinieerd voor de grenzen van het level, maar er wordt gebruik gemaakt van een techniek om een landschap te genereren. Dit houdt in dat een algoritme voor een gegeven breedte een set van edges zal genereren, dat de grond van het level representeert. Nadien kan de gebruiker objecten cre¨eren en plaatsen en de Event Editor gebruiken.
De levels worden opgeslagen en later ingeladen in het spel.
6. Uiteindelijke doelstelling
De uiteindelijke doelstelling is het cre¨eren van een programma, waarmee de gebruiker op een simpele manier een level kan construeren voor een spel. In dit programma moet het mogelijk zijn om de basis van het level, de grond, te laten genereren met een aantal instelbare parameters. Daarnaast moeten basisvormen, zoals cirkels en rechthoeken, gemaakt kunnen worden, maar moet de gebruiker ook de mogelijkheid hebben om zelf een vorm te cre¨eren door lijnen met elkaar te verbinden.
Voor deze vormen moeten een aantal eigenschappen in te stellen zijn. Denk hierbij aan eigenschappen die nodig zijn voor de PhysicsEngine, zoals massa en wrijving, maar ook eigenschappen voor de GraphicsEngine, zoals de ’texture’ die gemapt moet worden over de vorm en wat voor soort object het
is.
Naast het cre¨eren van vormen, is er een tweede onderdeel in de Editor, een zogenaamde Event Editor, waarin het mogelijk moet zijn om te bepalen wat er in een level gebeurt en wanneer dit gebeurt.
Een voorbeeld hiervan is het plotseling naar beneden vallen van een object, wanneer de speler ergens langsloopt. Met behulp van grafen kunnen de objecten gelinkt worden aan de gebeurtenissen, ook wel Events genoemd, dan wel aan de objecten die een Event activeren, ook wel Triggers genoemd.
Het feitelijke doel van dit project is om een Editor te ontwikkelen, dat gebruiksvriendelijk en overzichtelijk is, zodanig dat een nieuwe gebruiker gemakkelijk gewend raakt aan de beschikbare functionaliteit.
Deel III.
Concept
H
et concept van dit project is het ontwikkelen van een Editor, als hulpmiddel om voor een Android-game levels te cre¨eren. De Editor bestaat uit twee delen: enerzijds een Level Editor, om vormen te cre¨eren en eigenschappen ervoor te defini¨eren, anderzijds een Event Editor, om Events en bijbehorende Triggers te cre¨eren en indien gewenst te koppelen aan de objecten die in de Level Editor gecre¨eerd zijn.7. Levels en Events
Met het eerste onderdeel, de Level Editor, kan de gebruiker levels maken. Dit zijn tweedimensionale omgevingen met een breedte en hoogte, die opgevuld zijn met gemaakte vormen, zoals cirkels, recht- hoeken of andere convexe vormen.
Met het tweede onderdeel, de Event Editor, kan de gebruiker bepalen wat er in een level gebeurt en waar. Deze gebeurtenissen die plaats moeten gaan vinden worden Events genoemd. Voordat een Event plaatsvindt, moet deze als het ware ’geactiveerd’ worden, doordat een of andere conditie waar wordt.
Het activeren van de Events wordt bepaald door zogenaamde Triggers. Deze representeren een conditie waaraan voldaan moet worden, om een gekoppelde Event hieraan te activeren. Het kan gewenst zijn dat voor een bepaald Event meerdere condities moeten gelden, voordat deze geactiveerd kan worden, of dat het activeren ervan later moet plaatsvinden. Hiervoor zijn er zogenaamde Ports. Ports zijn als het ware tussenstations tussen een conditie dat geldt (Trigger) en een gebeurtenis (Event). Met deze Ports kunnen er complexere Events gecre¨eerd worden. Bijvoorbeeld een AND-Port [16], dat twee Triggers combineert tot ´e´en uitgangs-signaal. Dit uitgangs-signaal wordt gekoppeld aan een Event. Op deze manier moeten de condities voor beide Triggers gelden, om het Event te activeren. Als er maar ´e´en conditie geldt, wordt het Event niet geactiveerd.
8. User Interface
Het is van belang dat de User Interface (UI)[15] gebruiksvriendelijk is. Dit houdt in dat het overzichtelijk moet zijn voor de gebruiker en dat er een minimaal aantal klikken nodig is om een bepaalde actie uit te voeren. Om dit voor elkaar te krijgen moeten knoppen die bij elkaar horen gegroepeerd zijn, zodat het duidelijk is voor de gebruiker dat deze knoppen een soortgelijke functionaliteit hebben. Verder moet het duidelijk zijn welke knop wat doet. Er moet dus informatie beschikbaar zijn over een element in de vorm van een label, tekst die verschijnt wanneer de gebruiker met de muis op een element staat, of een uitleggende icoon voor een knop.
Binnen een apart onderdeel van het scherm, de werkomgeving, moeten alle gemaakte objecten te zien en te manipuleren zijn. De gebruiker moet intu¨ıtief om kunnen gaan met het verslepen, aanpassen, verwijderen en koppelen van objecten met anderen.
9. Software design keuze
9.1. Programmeertaal
Ik heb ervoor gekozen om de Editor in Java[5] te schrijven, omdat ik al enige ervaring had met deze programmeertaal. Java biedt object-geori¨enteerd programmeren met behulp van klasses en interfaces.
Bovendien heeft Java klasses als ArrayLists[11], die het gebruiksgemak vergroten.
Naast de functionaliteit die Java biedt, is de taal platfrom-onafhankelijk, doordat het gecompileerd wordt naar bytecode voor een virtuele machine, de Java Virtual Machine (JVM)[6]. Deze JVM is beschikbaar voor verschillende besturingssystemen.
Om een Editor te maken is het van belang dat er een GUI gemaakt wordt. Ook hiervoor is Java de favoriet. Java biedt een handige API om een GUI te bouwen, genaamd Swing[14]. Swing bouwt voort op AWT[12] (Abstract Windowing Toolkit) van Java. In tegenstelling tot AWT, waar grafische elementen van het besturingssysteem worden gebruikt, is Swing een eigen library en biedt het een groter aantal componenten.
9.2. Alternatieven
Naast Java biedt C++[1] ook de mogelijkheid om een GUI te bouwen. C++ is een programmeertaal die ook object-geori¨enteerd is. Het is een verbetering van de taal C. Echter worden bestanden in C++
direct gecompileerd naar machinetaal, waardoor de uitvoerbare bestanden alleen op ´e´en doelplatform draaien. Het is dus niet platform-onafhankelijk.
C++ biedt meerdere libraries voor het bouwen van een GUI. WinApi [9] en Qt [3] zijn daar voorbeelden van. Echter heb ik daar geen ervaring mee, dus zal het veel meer tijd kosten om te gebruiken dan Java Swing.
10. Ontwikkelmethode
De Editor heb ik ontwikkeld volgens het Agile softwareontwikkelingsframework. Dit houdt in dat de Editor ontwikkeld is in korte periodes, genaamd iteraties. Per iteratie zal uitgelegd worden wat er ontwikkeld en gemodelleerd is. De Agile methode die ik gebruikt heb is de Agile Modeling-Driven Development [2] (AMDD) ontwikkelmethode.
10.1. Agile Modeling-Driven Development
AMDD is de Agile versie van Model-Driven Development (MDD). Dit houdt in dat ik per iteratie een model maak, als het nodig is, van wat ik die iteratie ga implementeren, in plaats van tevoren een groot model te maken. In feite maak ik dus een klein model met net genoeg informatie voor de huidige iteratie en ga ik daarna implementeren. AMDD verschilt met Feature Driven Development (FDD) en Use-case Driven Development (UCDD), in het feit dat het niet specificeert wat voor soort modellen gemaakt moeten worden. Bij FDD zijn de primaire requirements de ’modellen’ en bij UCDD zijn het de Use-cases. Doordat van tevoren niet bekend was welke features ontwikkeld werden, heb ik niet gekozen voor FDD of UCDD, maar voor AMDD.
Deel IV.
Ontwikkeling
D
oordat de Editor ontwikkeld is volgens een Agile methode, is er per iteratie een stuk software ontwikkeld. Per iteratie wordt beschreven of er een model gemaakt is, welke ontwerp- en architectuur-keuzes ik gemaakt heb en wat er ge¨ımplementeerd is.De iteraties zijn afgekort als IT.
11. Veel voorkomend ontwerp-patroon
Tijdens het ontwikkelen van de Editor, heb ik het Bridge-patroon vaak gebruikt. Om te voorkomen dat het dubbel wordt uitgelegd, zal ik het in deze sectie alvast beschrijven.
11.1. Bridge patroon
In de Level- en Event Editor wordt veelvoudig gebruik gemaakt van het Bridge-patroon. Dit houdt simpelweg in dat de abstractie en de implementatie van een klasse los staan van elkaar, zodanig dat de twee onafhankelijk van elkaar kunnen functioneren. Het patroon maakt gebruik van overerving om de afzonderlijke taken in verschillende klassen onder te brengen.
Een voorbeeld: GameObject, deze heeft een aantal attributen, bijvoorbeeld een object EdShape. Dit is een klasse waarin de implementatie staat van bepaalde functies om manipulaties op het object uit te voeren. Echter worden deze functies vanuit GameObject aangeroepen en niet in EdShape zelf.
Dit patroon wordt onder andere gebruikt in: Listeners (secties 13, 14 en 15), GameObject (sectie 13), EdNode (sectie 15), Eigenschappen (secties 16 en 17).
12. IT0: Editor Basis
In de eerste iteratie van het project ben ik begonnen met het ontwerpen van een globaal model van de Editor. Voor de GUI van de Editor moest een API gekozen worden. Omdat ik al enigszins ervaring had met Java Swing, ging mijn voorkeur daar naar uit. Zoals uitgelegd in sectie 9.2, had ik ook gebruik kunnen maken van de Qt library in C++, maar omdat ik daar geen kennis van had was dat geen kandidaat. Java AWT was wel een kandidaat, maar Swing biedt meerdere mogelijkheden in componenten.
12.1. Model
De Editor bestaat uit een hoofdvenster, waarin een menu gekoppeld zit die functionaliteit biedt voor zowel de Level Editor als Event Editor. Als de Level Editor geactiveerd is, bevindt zich in het venster een toolbar, waarin de knoppen om objecten toe te voegen zichtbaar zijn. Daarnaast zit een panel, dat functioneert als werkomgeving van het level. Daarin moeten de reeds gemaakte objecten weergegeven worden. Doordat een level hoogstwaarschijnlijk groter zal zijn dan de schermgrootte, moet de panel voor de werkomgeving verschuifbaar zijn.
In het geval dat de Event Editor geactiveerd is, bevindt zich in het venster een soortgelijke tool- bar, maar met knoppen om specifieke objecten voor de Event Editor, dus Nodes, toe te voegen.
Daarnaast zit net als in de Level Editor een verschuifbaar panel voor de werkomgeving, maar die de
Figuur 1: Het ontwerp van de Editor
gemaakte nodes laat zien. Naast deze twee componenten bevat het venster nog een balk waarin per node eigenschappen in te stellen zullen zijn.
12.2. Ontwerp
Figuur 2: Het klassediagram van de Editor
Het klassediagram is te zien in figuur 2. De hoofdklasse is EditorFrame. Dit is het hoofdvenster waar alle andere componenten in zitten. Dit venster heeft een menu bar, EditorMenu, waarin manipuleerfuncties en functies als opslaan en inladen ge¨ımplementeerd zijn. EditorFrame bevat het EditorPane die de specifieke componenten van de Level- en Event Editor opgeslagen heeft, zodat gemakkelijk gewisseld kan worden tussen beide onderdelen.
12.3. Implementatie
Het hoofdvenster, EditorFrame is een klasse die de Java Swing klasse JFrame overerft. Dit maakt het mogelijk om de functionaliteit te gebruiken die JFrame biedt. Voor een JFrame kan gemakkelijk een menubalk (JMenuBar) ingesteld worden. De klasse EditorMenu overerft deze klasse. De verdere
componenten, de EditorPane, de toolbars en de werkomgevingen (workareas) overerven JPanel. Al deze beschreven klassen zorgen voor een GUI, zoals weergegeven in Figuur 3.
Figuur 3: De GUI van de Editor
13. IT1: Level Editor, toevoegen objecten
Nadat de GUI voor de Editor ontwikkeld was, ben ik begonnen met het implementeren van het toevoegen van een aantal objecten in de Level Editor. Hiervoor moest een structuur bedacht worden, waarop later voortgebouwd kon worden. Alle objecten die gemaakt worden, worden toegevoegd aan een model. De workarea kijkt vervolgens naar dit model om de objecten zichtbaar te maken.
Om objecten te maken zijn er controllers nodig. Deze controllers kunnen, door naar interacties met de muis te kijken, objecten maken en het model bijwerken met het gemaakte object.
13.1. Model
Figuur 4: Het model van de controllers.
Zoals gezegd wordt in het model alle gemaakte objecten opgeslagen. De workarea heeft dit model opgeslagen. Hiervoor in geen schets gemaakt, aangezien het een simpele oplossing is.
Echter zijn de controllers niet zo triviaal. Het is namelijk zo dat het cre¨eren van verschillende objecten niet op altijd op dezelfde manier verloopt. Daardoor moeten er verschillende controllers ge¨ımplementeerd worden, die ieder op eigen manier naar de interacties met de muis kijkt. Het model hiervoor is te zien in figuur 4.
13.2. Ontwerp
Figuur 5: Het klasse diagram van de controllers.
Er is ´e´en hoofdklasse bedacht, EditorListener, die de interfaces MouseListener (om te luisteren naar het klikken met de muis) en MouseMotionListener (om te luisteren naar muisbewegingen) implementeert. Het maken of manipuleren van verschillende vormen in de Level Editor vereist verschillende implementaties voor de events die de MouseListeners opleveren, zoals een onMouseClick event (dat geactiveerd wordt als er met de muisknop geklikt wordt). Hiervoor is een interface ontwikkeld genaamd EditorMode, die ge¨ımplementeerd wordt door de verschillende methodes voor het maken van vormen of het manipuleren ervan. Per klasse staat een unieke implementatie voor de genoemde events. Om bij te houden welke methode actief is, staat dit opgeslagen in de EditorListener als
’huidige modus’ (currentMode). Doordat de EditorListener bij een MouseEvent functies aanroept van deze currentMode, kan gemakkelijk gewisseld worden tussen de verschillende methodes. Dit is dus het rollenpatroon.
13.3. Implementatie
Het toevoegen van objecten is ge¨ımplementeerd volgens het MVC-patroon[10] (Model-View-Controller).
Op het moment dat het model aangepast is, wordt dit gemeld aan de view, zodat deze geupdate kan worden. Dit is een push-implementatie van MVC. De view is hier de workarea, deze heeft een model met objecten. Verder is de controller de listener die het model telkens aanpast. Een illustratie hiervan is te zien in figuur 6a.
(a) Illustratie van het MVC-patroon. (b) Convexe-(l) en concave vorm.
Figuur 6: Het MVC patroon en Convexe/Concave vorm.
Ook heb ik gebruik gemaakt van het Observer patroon. Dit gaat meestal gepaard met het MVC - patroon. Het is namelijk wenselijk om te weten wanneer de inhoud van het model veranderd, aangezien
de view de inhoud van het model weergeeft. Om deze weergave up-to-date te houden implementeert het model de Observable interface. Dit betekent dat dit object in de gaten gehouden kan worden door Observers. In dit geval is de view een Observer (deze implementeert dus ook de Observer interface).
Op deze manier kan, bij een wijziging aan het model, de Observer genotificeerd worden. Doordat de gebruiker een bepaalde actie wil initi¨eren, wordt de betreffende methode in de controller aangeroepen en het resultaat ’gepushed’ naar de view. Dit is dus een push implementatie van MVC.
Bij het implementeren van de Listener klasse heb ik gebruik gemaakt van het Bridge-patroon. Omdat ik dit patroon vaker heb gebruikt, wordt dit uitgelegd in sectie 11.1.
13.3.1. Objecten toevoegen
Het toevoegen van objecten wordt onderverdeeld per object. Er zijn bij deze iteratie een aantal objecten ge¨ımplementeerd, waaronder: Convexe vormen, cirkels en rechthoeken. De basis voor elk object is hetzelfde; de gebruiker klikt op de betreffende knop om het gewenste object te cre¨eren, daarna klikt hij in de werkomgeving om punten te cre¨eren. Per object is de afronding van het maken van het object anders:
• Convexe vorm: De gebruiker klikt om een hoekpunt van de convexe vorm te cre¨eren. Er wordt een lijn getekend tussen de reeds toegevoegde hoekpunten. Wanneer de verzameling hoekpunten gesloten wordt (de gebruiker klikt op het eerst gemaakte punt) wordt er een convexe vorm toegevoegd aan het model. Het kan zijn dat de vorm niet meer convex is, oftewel er geldt niet dat voor iedere combinatie van twee punten binnen dit object, elk punt dat op het rechte lijnstuk ligt dat deze twee punten verbindt op zijn beurt ook binnen dit object ligt (zie figuur 6b). Dit object wordt dan opgedeeld in driehoeken, doordat de PhysicsEngine alleen met convexe vormen kan rekenen.
• Cirkel: De gebruiker klikt om het middelpunt van de cirkel te cre¨eren. Vervolgens wordt er een cirkel getekend vanaf dat punt naar het punt waar de muis zich bevindt. Als de gebruiker tevreden is met de geconstrueerde cirkel, dan klikt hij nogmaals om het object definitief te maken en toe te voegen aan het model.tex
• Rechthoek: Het cre¨eren van een rechthoek gebeurt op eenzelfde wijze als het cre¨eren van cirkels.
De gebruiker klikt om een hoekpunt van de rechthoek toe te voegen. Vervolgens wordt de positie van de muis gebruikt om de overstaande hoek te bepalen. Deze twee hoekpunten worden gebruikt om een rechthoek te tekenen.
13.3.2. Objecten structuur
De globale structuur van de objecten die toegevoegd worden aan het model is te zien in figuur 7.
Een GameObject bestaat uit een EdShape, waarin attributen staan, zoals een transformatiematrix en een vorm (lijst met punten), dat gebruikt wordt om berekeningen op te doen voor manipulaties, een Drawable, dat gebruikt wordt om het object op een correcte wijze te tekenen en een Properties klasse voor de eigenschappen, dat in sectie 16 wordt uitgelegd. Een EdShape is een abstracte klasse die functioneert als hoofdklasse voor de verschillende vormen. Een EdShape is dus in feite een EdConvex (convexe vorm), een EdCircle (een cirkel) of een EdRectangle (een rechthoek).
14. IT2: Level Editor, objecten manipuleren
Zoals bij meerdere bewerkingsprogramma’s, biedt de Level Editor de mogelijkheid om de gemaakte objecten te manipuleren. De eerste manipulatiefuncties die bij deze iteratie ge¨ımplementeerd zijn, zijn de volgende: selecteren, verslepen, kopi¨eren, knippen en plakken. Hiervoor wordt er ook gekeken naar de interacties met de muis. Het is immers gewenst dat het object bij bijvoorbeeld het verslepen de positie van de muis volgt.
Figuur 7: Het model van een GameObject.
14.1. Model
Het model van de Listener dat te zien is in figuur 4, wordt uitgebreid met een extra modus genaamd EditingMode. Deze modus controleert of een object aangeklikt en versleept wordt. Doordat het model in figuur 4 enkel uitgebreid wordt met ´e´en modus, laat ik het nieuwe model van de Listener, met de nieuwe modus, achterwege.
14.2. Ontwerp
Voor het klasse diagram in figuur 5 geldt hetzelfde als het model van de nieuwe Listener, het wordt uitgebreid met ´e´en extra modus, EditingMode. Daarom laat ik het nieuwe klasse diagram van de Listener achterwege.
14.3. Implementatie
14.3.1. Objecten selecteren en verslepen
Door op een object te klikken kan deze geselecteerd worden. De listener kijkt na het klikken of er binnen een object geklikt is. Het is ook mogelijk om meerdere objecten te selecteren. Dit wordt gedaan door een selectie-rechthoek te maken, door op een lege plek in het venster de muis in te drukken en te verslepen. Dit cre¨eert een rechthoek. Alle objecten die in dit rechthoek zitten, worden geselecteerd.
De objecten die geselecteerd zijn, kunnen versleept worden door de muis op ´e´en van deze objecten in te drukken en te bewegen naar een nieuwe positie. De posities van alle geselecteerde objecten worden dan aan de hand van de muispositie bijgewerkt.
14.3.2. Object kopi¨eren, knippen en plakken
Naast het verslepen kunnen geselecteerde objecten ook gekopieerd of geknipt worden. Hiervoor zijn extra menu-items toegevoegd aan de menubalk. De implementatie hiervan wordt geregeld in dezelfde modus als bij het selecteren, de EditingMode. Als objecten gekopieerd worden, wordt er een kloon van elk object gemaakt en in een lijst gestopt. De originelen blijven bestaan. Bij het knippen wordt er ook een kloon van elk object gemaakt, maar worden de originele uit het model verwijderd. Vervolgens kunnen de gekloonde objecten geplakt worden. De objecten worden dan toegevoegd aan het model.
15. IT3: Event Editor, Nodes
In de derde iteratie ben ik begonnen met de Event Editor. De GUI hiervoor was al ontwikkeld. Bij deze iteratie heb ik gekeken naar een structuur voor de gemaakte objecten. Van belang was dat de objecten onderling referenties konden hebben. Het idee was om de objecten als een graaf te representeren.
(a) Het model van de EdNode. (b) De subklasses van EdNode.
Figuur 8: Het complete model van EdNode.
15.1. Model
De objecten die gemaakt kunnen worden, worden door ´e´en klasse gerepresenteerd. Het model van die klasse is te zien in figuur 8a. De hoofdklasse, genaamd EdNode, heeft een EdShape om de manipulaties op uit te voeren (de volledige structuur van de EdShape is te zien in figuur 7), een Drawable om de node te tekenen, en een Properties klasse, dat uitgelegd zal worden in sectie 16. Verder heeft een node inkomende en uitgaande referenties naar andere nodes. Een EdNode is namelijk de hoofdklasse van alle objecten die in de Event Editor gemaakt kunnen worden. Een EdNode is een abstracte klasse waar geen instanties van bestaan, maar instanties als type van ´e´en van zijn kinderen: EdEvent, EdPort en EdTrigger. Een model daarvan is te zien in figuur 8b.
Een Event representeert een bepaalde gebeurtenis die plaats kan vinden, bijvoorbeeld het ontploffen van een object. Een Trigger is een activator die een Event kan laten plaatsvinden door deze te activeren, bijvoorbeeld als de speler in een bepaald gebied komt. Een Port is als het ware een tussenstation tussen een Trigger en een Event. Met deze Port kan er een complexere Event gecre¨eerd worden. Bijvoorbeeld een AND-Port [16], dat twee Triggers combineert tot ´e´en uitgangs-signaal. Dit uitgangs-signaal wordt gekoppeld aan een Event. Op deze manier moeten de condities voor beide Triggers gelden, om het Event te activeren. Als er maar ´e´en conditie geldt, wordt het Event niet geactiveerd.
Net zoals bij het toevoegen van objecten in de Level Editor, zijn hier ook controllers nodig die kijken naar de interacties met de muis. Deze controllers zijn op eenzelfde wijze ge¨ımplementeerd (zie sectie 13), alleen met andere methodes. Het model is te zien in figuur 9.
15.2. Ontwerp
Doordat de controller van de Event Editor gebaseerd is op die van de Level Editor, wordt deze niet verder uitgelegd. Het enige wat verschilt is namelijk de modus. Er wordt onderscheid gemaakt tussen het tekenen van nodes, de Draw Mode, het toevoegen van verbindingen tussen deze nodes (Edges), de Edge Mode en een Editing Mode voor het selecteren en verslepen van de nodes.
Figuur 9: Het model van de controller in de Event Editor.
15.3. Implementatie 15.3.1. Nodes toevoegen
Het toevoegen van Nodes wordt gedaan met behulp van de Draw Mode. Op het moment dat de gebruiker op een knop klikt van een betreffende node, wordt deze modus geactiveerd en wordt er gekeken waar in het workarea panel de gebruiker klikt. Op die positie wordt vervolgens de betreffende node gecre¨eerd.
Deze nodes kunnen geselecteerd en versleept worden, op dezelfde manier als de objecten in de Level Editor. Voor een compleet overzicht van de mogelijke node types, zie appendix B.
15.3.2. Edges toevoegen
Doordat de nodes in de Event Editor aan elkaar gekoppeld kunnen worden, kunnen er edges, oftewel verbindingen, tussen de nodes gemaakt worden. Dit wordt gehanteerd door de Edge Mode in de controller. Als de gebruiker een verbinding wil maken tussen twee nodes, klikt hij op de edge knop.
Vervolgens klikt hij op een node om aan te geven dat de verbinding begint bij de aangeklikte node.
Daarna wordt er een lijn getekend vanaf dat punt naar de muisaanwijzer, totdat de gebruiker op een tweede node klikt. Dit cre¨eert een verbinding tussen de twee aangeklikte nodes. In de lijst met outputnodes van de eerste node, wordt nu het tweede node toegevoegd. Hetzelfde, maar dan andersom, geldt voor de lijst met inputnodes van de tweede node. Merk op dat de edges alleen voor de representatie van de verbindingen gelden. De werkelijke verbinding tussen nodes wordt dus opgeslagen in de nodes zelf. Op deze manier wordt een graaf van nodes ontwikkeld.
Er zijn wel een aantal restricties op het aantal uitgaande en inkomende verbindingen van een node. Zo hebben alle events geen uitgaande verbindingen, het zijn immers ’eindnodes’. Triggers hebben geen inkomende verbindingen, ze staan namelijk aan het begin van een graaf. Voor ports is het aantal inkomende en/of uitgaande verbindingen afhankelijk van het type port.
16. IT4: Level Editor : Eigenschappen
Voor de Physics- en GraphicsEngine is het van belang om een aantal eigenschappen te weten van objecten in de Level Editor. De in te stellen eigenschappen zijn afhankelijk van een aantal situaties.
Zo zijn er voor een animatie-type object andere grafische eigenschappen in te stellen dan voor een shape-type object. Met behulp van een popup zijn de eigenschappen in te stellen. Deze eigenschappen worden bijgehouden in het betreffende object.
16.1. Model
Voor het instellen van eigenschappen wordt een popup gebruikt. Het model daarvoor is te zien in figuur 10.
Figuur 10: Model van de popup om eigenschappen in te stellen.
Een popup bestaat uit drie onderdelen: een deel voor de algemene (general) eigenschappen, een deel voor de grafische eigenschappen (drawable) en een deel voor de fysische eigenschappen (material).
• General: Tot de algemene eigenschappen hoort bijvoorbeeld de collectie waarin het object moet zitten. Dit is relevant voor de PhysicsEngine. Een object kan bijvoorbeeld tot de collectie Scenery behoren. Dat houdt in dat het niet kan bewegen en andere objecten (zoals de speler) botsen met dit object. Zo kan het ook tot de Movable collectie behoren.
• Material: De speler kan aangeven tot welk materiaalsoort een object behoort. Aan de hand hiervan kunnen fysische eigenschappen ingesteld worden, zoals massa, wrijving etc. Voor elk materiaalsoort zijn tot nu toe nog dezelfde eigenschappen in te stellen.
• Drawable: Op een zelfde manier als de materiaalsoort, kan de gebruiker aangeven tot wat voor een grafische soort het object behoort. Dit kan een normale vorm zijn, of een een plaatje, of een animatie. Aan de hand van deze soort kunnen aanvullende eigenschappen ingesteld worden.
De ingestelde eigenschappen moeten ergens opgeslagen worden. Hiervoor is een klasse Properties, met subklasses per onderdeel als attribuut en heeft het dezelfde hi¨erarchie als het model voor de popup (figuur 10). Hierin worden de eigenschappen opgeslagen. Zoals in sectie 13.3.2 beschreven staat, is de Properties klasse een attribuut van GameObject. Hierdoor zijn de eigenschappen ten alle tijde op te vragen en aan te passen.
16.2. Ontwerp
Het klassediagram van de popup is te zien in figuur 11. De hoofdklasse, Popup, overerft de JDialog klasse van Java. Hierdoor kan er gemakkelijk een popup gecre¨eerd worden, maar met eigen invulling.
Deze invulling wordt verzorgd door de drie klassen PopupMaterial, PopupGeneral en PopupDrawable.
De klassen overerven JPanel. Aan de hand van de aangegeven collecties wordt bepaald wat er in het popup weergegeven wordt. Bijvoorbeeld, als de gebruiker niet heeft gespecificeerd tot welke materi- aalsoort een object behoort, is het JPanel van PopupMaterial niet zichtbaar en kunnen er dus ook
geen fysische eigenschappen worden ingesteld. Op eenzelfde manier wordt er bepaald welk JPanel van de PopupDrawable weergegeven wordt, zodat de juiste grafische eigenschappen ingesteld kunnen worden.
Het klassediagram voor de Properties klasse heeft eenzelfde structuur als die voor de Popup klasse.
Echter overerven ze geen JPanel of JDialog. Wel heeft de Properties klasse de drie onderdelen als attributen. De Drawable klasse is dan weer onderverdeeld in de verschillende drawable types.
16.3. Implementatie
Figuur 11: Klassediagram van de Popup klasse.
Bij het implementeren van de Properties klasse heb ik gebruik gemaakt van het Bridge-patroon.
Omdat ik dit patroon vaker heb gebruikt, wordt dit uitgelegd in sectie 11.1.
17. IT5: Event Editor : Eigenschappen
Voor een aantal types nodes is het wenselijk om aanvullende eigenschappen in te stellen. Stel je wilt een timer tussen een trigger en event, maar voor een timer is het van belang om in te stellen hoe lang een timer duurt. Dit moet in te stellen zijn. Ook moet er een referentie gemaakt kunnen worden naar een object uit de Level Editor. Ik beschouw dit ook als een eigenschap van een node. Het is immers van belang voor bijvoorbeeld een event om een object te laten ontploffen om te weten welk object ontploft moet worden.
17.1. Model
Om eigenschappen voor nodes in te stellen heb ik een extra balk ontwikkeld, waarin voor een geselecteerde node de in te stellen eigenschappen te zien zijn en te bewerken zijn. Op deze manier kan de gebruiker makkelijk en snel eigenschappen instellen. Het model hiervoor is te zien in figuur 12. Het model voor het opslaan van de eigenschappen heeft dezelfde structuur. Echter implementeert geen enkele klasse een Panel interface. Het idee is dat, op het moment dat een bepaalde type node geselecteerd wordt, het betreffende eigenschappenpanel geactiveerd en zichtbaar wordt met de huidige ingestelde eigenschappen.
Mocht het om een node gaan waaraan objecten uit de Level Editor gekoppeld zijn, dan krijgen deze objecten een onderscheidende kleur.
Figuur 12: Het model van de eigenschappenbalk.
17.2. Ontwerp
(a) Het klassediagram van de eigenschappenbalk. (b) Het klassediagram van de eigen- schappen voor een node.
Figuur 13: Klassediagrammen van de balk en node eigenschappen.
De klasse EventPropertiesBar maakt onderdeel uit van de GUI van de Event Editor, zoals eerder weergegeven en beschreven in respectievelijk figuur 2 en sectie 12. Deze klasse overerft de JPanel klasse van Java. Op eenzelfde structuur als beschreven in het model, bestaat de balk uit verschillende klassen die ook JPanel overerven. Op deze manier kan ik gemakkelijk de benodigde inputvelden en/of knoppen maken om eigenschappen in te stellen. Zoals eerder vermeld wordt het juiste panel zichtbaar wanneer een node geselecteerd wordt. Dit kan doordat alle panels al bestaan in de EventPropertiesBar klasse.
Het klassediagram van de Properties klasse voor de eigenschappen van een node is te zien in fi- guur 13b. De subklasses van de type nodes zijn hier achterwege gelaten, aangezien dat het diagram onleesbaar groot maakt. Belangrijk om te weten is dat elke node, waarvoor eigenschappen instelbaar zijn, daarvoor velden heeft in de klasse om deze eigenschappen bij te houden.
17.3. Implementatie
Ook hier wordt gebruik gemaakt van het Bridge-patroon (uitgelegd in sectie 11.1), om de EventPropertiesBar klasse te implementeren.
Verder kan er voor een aantal Events en Ports, een koppeling gemaakt worden met objecten uit de Level Editor. Voor Destroy-Event is het van belang om een object uit de Level Editor aan te geven als het object dat moet ontploffen. Hiervoor is een nieuwe methode aan de Listener toegevoegd (de Listener is beschreven in sectie 15). Deze methode, ObjectChooser, bepaalt of ´e´en of meerdere objecten (hangt af van het type Node) geselecteerd wordt. De oorspronkelijke methodes van de EventListener, te zien in
figuur 9, wordt uitgebreid met de nieuwe methode. Omdat het model uit figuur 9 maar met slechts ´e´en nieuwe methode uitgebreid wordt, laat ik het nieuwe Listener-model achterwege.
18. IT6: Event Editor : Particles
Vanwege het feit dat voor particles in het spel een aparte onderdeel van de GraphicsEngine geschreven is, is het wenselijk om ook in de Event Editor hiervoor een onderdeel te ontwikkelen. Particles zijn kleine grafische objecten die gebruikt worden in een systeem om een bepaald fenomeen, zoals vuur, te simuleren. In de Event Editor is een ParticleGenerator een Event. Dit is een speciaal Event dat kleine Particles genereert in het level. Om aan te sluiten op de ParticleEngine in het spel, heb ik de eigenschappen voor dat Event uitgebreid met extra eigenschappen en functionaliteit.
18.1. Model
Het oorspronkelijke model voor de controller van de Event Editor (te zien in figuur 9), wordt uitgebreid met twee extra modi, een modus om een spawn toe te voegen waarin de particles ontstaan en een modus om een aantrekkingskracht toe te voegen. Het uiteindelijke model van de controller is te zien in figuur 14.
Figuur 14: Het uiteindelijke controller model van de Event Editor.
De zogeheten spawn kan verschillende soorten objecten zijn. De particles kunnen in een bepaalde straal (cirkel) of een rechthoek ontstaan, maar het is ook mogelijk om aan te geven dat de particles langs een lijn of set van lijnen ontstaan. Dit is bijvoorbeeld wanneer een tak in brand staat, dan kan er een lijn over de tak getekend worden om het te laten lijken alsof de tak in brand staat.
Naast een spawn kan ook een aantrekkingskracht (attractor ) gedefinieerd worden. Dit is een onzichtbaar object dat een bepaalde kracht uitoefent op de particles. Hierdoor komen de particles in beweging.
Deze objecten zijn in te stellen in de eigenschappen van de ParticleGenerator. Naast deze ob- jecten zijn er ook aanvullende eigenschappen in te stellen, die relevant zijn voor de ParticleEngine. Dit zijn fysische eigenschappen, zoals het aantal particles en de levensduur, maar ook grafische eigenschap- pen zoals textuur en/of kleuren. Deze aanvullende eigenschappen kunnen met behulp van een popup ingesteld worden. Het model hiervoor is triviaal. Het is namelijk een popup dat een aantal velden en knoppen bevat om eigenschappen in te stellen en een klasse waarin de eigenschappen opgeslagen worden. In die klasse staat ook de objecten voor de spawn en attractor opgeslagen.
18.2. Ontwerp
Figuur 15: Het klassediagram van de ParticleObject klasse.
Het klassediagram van de ParticleObject klasse is te zien in figuur 15. Het ParticleObject heeft een EdShape om een spawn of attractor te maken. Op deze manier kunnen deze objecten gemanipuleerd worden in de Event Editor. Ook heeft het een DrawableParticle om het object op een correcte wijze weer te geven in de view.
In het popup voor de Particles kunnen veel eigenschappen ingesteld worden. Dit zijn verschillende eigenschappen die nodig zijn voor de engines.
• PhysicsEngine: voor de PhysicsEngine is het van belang om te weten wat het aantal particles is dat gegenereerd zal worden, wat daarvan de levensduur is (dus na hoeveel seconden ze weer verdwijnen), wat de massa is en tot slot wat de zwaartekracht is die er kracht op uitoefent.
• GraphicsEngine: voor de GraphicsEngine is het echter van belang om te weten wat het aantal frames is voor een animatie, wat de resourcebestanden zijn (plaatjes) en bijvoorbeeld of er kleurveranderingen of veranderingen in het alpha kanaal (dat zorgt voor transparantie van een plaatje) zijn.
• ParticleEngine: tot slot zijn er voor het particle systeem zelf wat eigenschappen nodig. Dit zijn eigenschappen die te maken hebben met de spawn en attractor. Wat voor een ParticleObject gebruikt wordt voor de spawn en wat de kracht is waarmee de attractor de particles aantrekt.
18.3. Implementatie
18.3.1. ParticleObject toevoegen
• Spawn: Een Spawn kan gemaakt worden met behulp van de SpawnMode in de controller. Deze modus wordt geactiveerd zodra de gebruiker op de knop drukt om een spawn toe te voegen. Bij het activeren van de SpawnMode wordt gekeken wat voor soort spawn gemaakt moet worden, door te kijken wat voor soort is aangegeven in het dropdown-menu in de instellingen. Als dit een rechthoek of cirkel is, wordt het maken en tekenen van het spawnobject gedaan zoals dit beschreven is in sectie 13. Bij het maken van een lijn of set van lijnen als spawnobject, moet de gebruiker blijven klikken om steeds nieuwe punten toe te voegen. Om te stoppen kan op het done-knopje geklikt worden. Er worden tijdens het tekenen lijnen tussen deze punten gecre¨eerd.
Dit spawnobject wordt tenslotte opgeslagen in de ParticleProp klasse, waarin de eigenschappen staan van de EdParticleGenerator.
• Attractor: Een attractor kan gemaakt worden met behulp van de AttractorMode in de controller.
Deze wordt op eenzelfde wijze geactiveerd als de SpawnMode. Echter is het verschil dat er alleen een kleine cirkel gemaakt kan worden door eenmaal ergens te klikken. Dit doordat het niet van belang is hoe dit object eruit ziet, aangezien het niet zichtbaar zal zijn en enkel een kracht uitoefent op de particles. De hoeveelheid kracht die uitgeoefend wordt, kan ingesteld worden via de popup. Uiteindelijk wordt ook dit object opgeslagen in de eigenschappen-klasse ParticleProp.
19. IT7: Level Editor : Integratie Procedural Level Builder
Voor een minorscriptie heb ik samen met een medestudent een Procedural Level Builder (PLB)[4]
ontwikkeld. Dit houdt in dat de PLB steeds kleine stukjes level genereert en deze aan elkaar plakt. Op deze manier was het mogelijk om een oneindig lang level te genereren. Onder het genereren van een level wordt verstaan: een basislevel, dat bestaat uit een heuvelachtige grondgebied, met op willekeurige plaatsen een ravijn. Doordat de PLB direct in het spel ge¨ımplementeerd was, kwam ik op het idee om het te integreren in de Editor.
19.1. Model
Het idee is om met enkele simpele interacties een basislevel te genereren. Wanneer de gebruiker op de knop klikt om een basislevel toe te voegen, verschijnt een popup om een aantal instellingen in te snellen. Vervolgens verschijnt het basislevel op het scherm. Het model is te zien in figuur 16.
Figuur 16: Het model van de structuur om basislevel te genereren.
19.2. Ontwerp
Het klassediagram te zien in figuur 17. De hoofdklasse, LevelBuider, heeft een GeometryBuilder.
Deze heeft op zijn beurt een SignalGenerator, PointBuilder en PointsPostProcessor. Dit zijn klassen die een onderdeel van het level genereren voor hun rekening nemen. Dit zijn de volgende onderdelen:
• Genereer een signaal
• Verfijn punten
• Post-processing
Een klasse die de SignalGenerator interface implementeert, genereert een signaal en zet dit om naar punten. Vervolgens verfijnt een PointBuilder klasse de gemaakte punten. Tot slot kan er nog wat
Figuur 17: Het klassediagram van de structuur om basislevel te genereren.
post-processing gedaan worden met een PointsPostProcessor klasse. Doordat dit interfaces zijn, kan er gemakkelijk een nieuwe techniek ge¨ımplementeerd worden voor bijvoorbeeld het genereren van een signaal.
19.3. Implementatie 19.3.1. Level Builder
Simpel gezegd maakt de LevelBuilder steeds een stuk basislevel, wat uiteindelijk aan elkaar geplakt wordt, zodat het lijkt alsof het uit ´e´en geheel bestaat. Zoals eerder genoemd, gebruikt het de GeometryBuilder om de punten en edges te genereren voor de wereld. Uiteindelijk levert dit een set op van segmenten die, als er een vorige set bestaat, samengevoegd wordt met de vorige set en uiteindelijk omgezet wordt naar een geheel object voor in de Level Editor.
19.3.2. Geometry Builder
De GeometryBuilder hanteert het uitvoeren van de juiste functies van de juiste klasse. Het zal allereerst functies aanroepen van een klasse die de interface SignalGenerator implementeert. Deze functies genereren een 1-dimensionaal en een 2-dimensionaal signaal, dat gebruikt wordt om later een wereldsegment te cre¨eren.
Na het genereren van een signaal, wordt een klasse gebruikt die de interface PointBuilder implementeert.
Deze klasse bevat een bepaalde techniek om punten te maken vanuit een 2-dimensionaal signaal. Een pointbuilder kan bijvoorbeeld ervoor zorgen dat de hoeken tussen punten afgestompt worden, zoals de huidige techniek doet.
Hierna worden functies van een PointsPostProcessor aangeroepen, om na het genereren van keypoints wellicht nog wat andere manipulaties van de punten uit te voeren.
19.4. Meer uitleg
Voor een meer gedetailleerde uitleg over de Procedural Level Builder, zie [4].
20. IT8: Level Editor : Manipulatie uitbreidingen
In sectie 14 heb ik beschreven hoe ik het eerste aantal manipulatie mogelijkheden ge¨ımplementeerd heb.
Om het aantal mogelijkheden te vergroten heb ik ook het roteren, vervormen en schalen van objecten ontwikkeld. Het roteren draait het object links- of rechtsom. Het schalen vergroot of verkleint een object. Het vervormen veranderd de vorm van het object door een hoekpunt te verplaatsen.
20.1. Model
Het model van de controller in de Level Editor (weergegeven in figuur 4), wordt uitgebreid met drie nieuwe modi, voor het roteren, schalen en vervormen. Dit model is te zien in figuur 18.
Figuur 18: Het uiteindelijke model van de controller van de Level Editor.
De structuur is verder hetzelfde als beschreven in sectie 14, dus daar wordt verder niet op in gegaan.
20.2. Ontwerp
Hetzelfde geldt voor het ontwerp. De controller, beschreven in sectie 14 (weergegeven in figuur 5) wordt enkel uitgebreid met de drie bekende modi. Het uiteindelijke ontwerp is te zien in figuur 19.
Figuur 19: Het uiteindelijke klassediagram van de controller van de Level Editor.
20.3. Implementatie 20.3.1. Objecten roteren
Het roteren van objecten geldt niet voor alle objecten. Het is immers onzinnig om een cirkel te roteren.
De modus om te roteren wordt geactiveerd door een object te selecteren in de Level Editor en op de roteer-knop te klikken. Vervolgens kan het object geroteerd worden door ´e´en van de hoekpunten van het object te pakken en te slepen naar een andere plek. De rotatiehoek wordt bepaald door een vector te berekenen van het startpunt van de muisaanwijzer naar het middelpunt van het object en een vector van het nieuwe punt van de muisaanwijzer naar dat middelpunt. De hoek tussen deze twee vectoren wordt vervolgens bepaald en gebruikt in de transformatiematrix van het betreffende object. Op deze manier wordt het object geroteerd.
20.3.2. Objecten schalen
Zoals het roteren van objecten, wordt het schalen van objecten ook geactiveerd door op de schaal-knop te klikken. De schaalmodus in de listener wordt dan geactiveerd. Het object kan nu geschaald worden door een hoekpunt te pakken en te verslepen naar een nieuwe positie. Door de verhouding te berekenen tussen het startpunt van de hoek en het nieuwe punt van de hoek, is de schalingsfactor van het object bekend. Deze wordt gebruikt in de transformatiematrix om zo het object te schalen.
20.3.3. Objecten vervormen
Ook het vervormen van objecten wordt gedaan door eerst op een knop te klikken en vervolgens een hoekpunt te verslepen. De index van het hoekpunt in de lijst wordt opgeslagen, alsmede de nieuwe co¨ordinaten. In de shape van het object wordt vervolgens het juiste punt geupdate met de nieuwe positie. Daarna worden de edges geupdate zodat de lijnen weer goed getekend worden.
20.4. Problemen
Ik ondervond wat problemen bij het implementeren van deze nieuwe functionaliteit. Met name het schalen en roteren verliep niet zoals gepland. Het roteren liep bijvoorbeeld niet intu¨ıtief. Tijdens het roteren, als je voorbij een bepaald punt was met de muis, draaide het object ineens de verkeerde richting op. Het objecten moest naar de locatie van de muis draaien, maar dat gebeurde niet. Dit kwam in eerste instantie doordat de hoek voor het schalen verkeerd berekend werd. Ik bereken de hoek tussen een vector vanaf het middelpunt naar het beginpunt van de muisaanwijzer en een vector vanaf het middelpunt naar het eindpunt van de muisaanwijzer (dus het punt na verslepen met de muis). Nadat de hoek goed berekend werd, was het nog niet opgelost. Dit kwam doordat het instellen van de orientatie (hoe het object gedraaid staat) niet kan door een simpele toekenning (zoals x = y), vanwege het feit dat bij objecten dan alleen een referentie naar dat object wordt opgeslagen. Door een functie te maken in dat object, x.setTo(y), kon de orientatie wel ingesteld worden. Dit lostte het rotatieprobleem op.
Eenzelfde soort probleem ondervond ik bij het schalen van objecten. Een object schaalde bijvoorbeeld exponentieel. De oorzaak hiervan was dat de schalingsfactor verkeerd berekend werd.
Een ander, vreemd, probleem was dat, wanneer een object eerst geroteerd was, dan het object geschaald werd, het object nog steeds een beetje roteerde. Andersom was ook het geval. Na eerst te schalen en vervolgens te roteren, schaalde het object ook nog een beetje. Hier heb ik lang mee gezeten. Uiteindelijk bleek de fout in het schalen te zitten. Bij het schalen wordt er een matrix-vermenigvuldiging gedaan met de transformatiematrix en een schalingsmatrix. De fout zat in de schalingsmatrix. Deze was eerst de matrix links weergegeven. De goede staat rechts weergegeven.
α 1 1 α
α α α α
met α als schalingsfactor
21. IT9: Level opslaan en inladen
Het is van belang dat de gemaakte levels, inclusief events e.d. opgeslagen kunnen worden en ingeladen kunnen worden. Zo kunnen er gemakkelijk wijzigingen worden aangebracht aan bestaande levels. De belangrijkste eis hiervoor is misschien wel dat de referenties tussen de objecten onderling (in de event editor) en tussen de objecten uit de editor onderdelen behoud blijven.
21.1. Ontwerp
Het opslaan en inladen van een level wordt gedaan door respectievelijk het schrijven naar en lezen uit een bestand. Dit wordt door ´e´en klasse geregeld, de ObjectParser. Doordat er verder geen extra klassen betrokken zijn bij dit proces, is het onnodig om een model of klassediagram te maken. Deze klasse leest de modellen van de level- en event editor en schrijft deze naar een bestand, of leest deze modellen in. Op die manier kunnen levels opgeslagen in ingelezen worden.
21.2. Implementatie 21.2.1. Serializable
In eerste instantie gebruikte ik Java Serializable[13] voor het schrijven naar- en inlezen van een bestand.
Hiervoor moesten alle objecten die weggeschreven werden de interface Serializable implementeren.
Ook klassen binnen een andere klasse (als veld) moesten deze interface implementeren. Mocht er een veld zijn waarvan het niet nodig was om weg te schrijven, dan moest de identifier transient ervoor staan.
Echter werkte dit niet optimaal. Naast het feit dat veel klassen Serializable moesten implementeren, werkte het na het inladen niet meer. Objecten konden niet meer versleept worden en de referenties ontbraken. Waarom het na het inladen niet meer werkte is mij onduidelijk. Wellicht laadde Serializable wel alle objecten weer in, maar de referenties niet, doordat het alleen de eigenschappen en methodes opslaat.
21.2.2. Xstream
Ik ging op zoek naar een andere, betere oplossing. Na wat zoeken kwam ik uiteindelijk bij XStream[17]
terecht. XStream is een API, dat gebaseerd is op Java Serializable, maar verschilt in het feit dat het objecten niet omzet naar bytecode, maar naar XML. Hierdoor is het bestand te openen en makkelijk te lezen. Naast het importeren van een speciale JAR bestand, waar de libraries instonden, hoefde ik niet veel te veranderen. Het is bij Xstream niet noodzakelijk om objecten de Serializable interface te implementeren. Dit wordt door de API zelf geregeld.
Na het implementeren met behulp van Xstream was het probleem dat ik ondervond bij Serializable opgelost. Objecten konden na het inladen gewoon versleept worden. Later bleek dat de referenties onderling wel goed ging, maar niet tussen de verschillende modellen. Na enig onderzoek kwam ik erachter dat het voor XStream onbekend is wat de referenties tussen objecten zijn, als deze afzonderlijk naar het bestand geschreven werden. Dit was ook zo in mijn geval. Ik schreef beide modellen apart naar het bestand. Na een kleine aanpassing, door de modellen op te slaan in ´e´en klasse en deze vervolgens naar het bestand te schrijven, waren de referenties wel bekend voor Xstream. Hierdoor bleven de referenties bewaard.
Verder was de overhead nogal groot. In het begin werden alle klassen betrokken bij de modellen meegeschreven, dus ook de vormen die opgeslagen stonden in de objecten. Deze kunnen gemakkelijk opnieuw berekend worden aan de hand van de lijst met punten en de transformatiematrix. Ik heb er daarom voor gekozen om de vorm zelf niet mee te nemen (en dus transient te maken), maar de lijst met punten en de matrix wel, zodat de vorm opnieuw berekend kon worden.
Ook het meeschrijven van plaatjes (texturen) was een overhead. XStream kon hier namelijk niet goed mee overweg. Het schreef elke pixelwaarde naar XML, wat resulteerde in een enorme lijst van integers.
Het opslaan ging goed, maar bij het inladen leverde deze lijst een foutmelding op in mijn JVM. De oplossing hiervoor was simpel. Het bestand heb ik transient gemaakt, en het pad naar dit bestand heb ik opgeslagen. Het pad wordt wel meegeschreven en gebruikt om bij het inladen het bestand weer opnieuw in te laden.
22. IT10: Koppelen met het spel
Naast het opslaan en inladen van een gemaakt level is het natuurlijk van belang dat de levels ook daadwerkelijk speelbaar zijn in het spel. Hiervoor moet een vertaalslag gemaakt worden van objecten uit de editor naar objecten uit het spel. Deze vertaalslag is nodig doordat de editor veel objecten gebruikt die onder andere gebruik maken van een aantal Java klassen. De objecten in het spel zelf doen dat niet. Echter maken deze gebruik van veel klassen afkomstig uit de Physics Engine. Het is zinloos om deze hele engine te importeren in de Editor, dat zou namelijk veel overhead cre¨eren.
(a) Het model van het externe formaat. (b) Het klassediagram van het externe formaat.
Figuur 20: Het model en klassediagram van het externe formaat.
22.1. Model/ontwerp
Voor het maken van een vertaalslag heb ik een formaat bedacht dat zowel in het spel als in de editor gebruikt wordt. Dit formaat bevat een aantal onderdelen die in beide (spel en editor) belangrijk zijn.
Het model hiervoor is te zien in figuur 20a. Het klassediagram is te zien in figuur 20b.
De hoofdklasse, ExternalFormat bevat een aantal sub-klassen waarin de benodigde informatie opgesla- gen staat:
• ShapeFormat: Hierin staat opgeslagen wat voor soort vorm het is en wat de positie van de punten van deze vorm is. Een object kan in de toekomst uit meerdere vormen bestaan, dus is het een array van vormen.
• FillFormat: Hierin staat simpelweg hoe het object weergegeven wordt. Dit is tot nog toe de kleur van het object.
• GraphicsFormat: Hierin staat informatie die relevant is voor de Graphics Engine. Tot nu toe staat hierin alleen de texture opgeslagen.
• Collections: Een String array waarin staat tot welke collecties een object behoort, zoals beschreven was in sectie 16.1.
• PhyPropFormat: De informatie dat voor de Physics Engine relevant is, wordt in deze klasse opgeslagen. Dit is de informatie zoals beschreven in sectie 16.1.
• CameraPath: Tot slot is er nog een camera pad opgeslagen, als een lijst van Edges. Dit is het pad waar de camera overheen loopt. Dit wordt tezamen met een ’basislevel’ gegenereerd.
Tot slot bestaat er een FormatConverter klasse. Deze klasse zorgt voor het opslaan en ophalen van informatie in het externe formaat.
22.2. Implementatie
De implementatie van de FormatConverter klasse verschilt aan de Editor- en Spel-kant. De implemen- tatie aan de Editor-zijde is geheel gericht aan het opslaan van informatie. Het gaat de objecten in de modellen af om de informatie om te zetten naar het externe formaat. Dit externe formaat wordt vervolgens in een lijst bewaard. Deze lijst wordt tot slot naar een bestand geschreven, dat later door het spel ingelezen kan worden.
De implementatie aan het spel-zijde is echter geheel gericht aan het ophalen van deze informatie. De lijst met externe formaten wordt uit een bestand gelezen. Vervolgens wordt elk formaat uit de lijst langsgegaan om daaruit de benodigde informatie te halen. Er wordt eerst gekeken wat voor soort vorm het is en wat de bijbehorende fysische eigenschappen zijn en tot wat voor collectie het object behoort.
Dit wordt opgeslagen in een object van de Physics Engine. Daarna wordt de grafische informatie verkregen en opgeslagen in een object van de Graphics Engine. De twee reeds gemaakte objecten worden tot slot gebruikt om een GameObject te maken dat toegevoegd wordt aan de Game Engine.
Het object uit de Level Editor is nu succesvol geimporteerd in het spel.
22.2.1. Problemen
Het koppelen van de Editor en het spel was niet zo makkelijk. Allereerst moest er een vertaalslag gemaakt worden tussen de beide soorten objecten. Dit koste wat tijd, maar was uiteindelijk te realiseren door te vergelijken welke relevante informatie aan beide kanten beschikbaar was en waar deze informatie vandaan gehaald of opgeslagen kon worden. De Editor was immers ontwikkeld om de gebruiker in staat te stellen deze informatie zelf op te slaan.
Naast het bedenken en ontwerpen van die vertaalslag moest de lijst met externe formaten nog van de Editor naar het spel komen. Hiervoor was in eerste instantie een eigen methode bedacht, die de objecten ´e´en voor ´e´en naar een tekstbestand schreef. Eerst werden alle sub-klassen van het level editor object naar het bestand geschreven, daarna het object zelf. Hierdoor kon, door een zelfgeschreven parser, eerst de sub-klassen van het object ingelezen worden en vervolgens het object zelf gemaakt worden aan de hand van deze sub-klassen. Dit was erg ineffici¨ent en tijdrovend. Ik besloot om het te proberen met Java Serializable.
Het gebruik van Serializable verliep niet geheel zoals verwacht. Aan de Editor kant werden ob- jecten wel naar het bestand geschreven, maar aan het spel kant ging het inlezen niet goed. Met Serializable moeten de formaten identiek zijn aan elkaar, dus ook de packagenamen van het formaat en de sub-klassen. Een voorbeeld: De Editor gebruikt een klasse Vec2 voor het gebruik van punten met een x- en y-co¨ordinaat, die de punten van de vorm van het object representeren. De packagenaam van deze klasse aan de Editor zijde is com.bernoulligames.leveleditor.util. Aan de zijde van het spel wordt deze klasse ook gebruikt voor dezelfde punten. Echter is de packagenaam hier: mage.util.math.
Doordat deze packagenamen verschillen, ziet Serializable ze als compleet verschillende objecten. Dit leverde foutmeldingen op. Naast de packagenaam moet ook de inhoud exact hetzelfde zijn. Na het oplossen van deze problemen werkte het echter nog niet, om onbekende reden.
Ik besloot om het opslaan en inlezen met behulp van XStream te doen, aangezien dit gemakkelijk werkte bij het opslaan en inladen van levels in de Editor (zie sectie 21). Hiervoor moest echter de library van XStream ge¨ımporteerd worden in het spel. Aan de Editor kant was dit al gebeurd, dus dat was geen probleem. Doordat het spel in Android geschreven is, werkt het importeren van externe libraries anders dan in normale Java projecten. Na wat zoeken vond ik uitleg hoe het importeren in Android
moest. Echter, na het importeren kreeg ik toch steeds een foutmelding dat XStream niet gevonden kon worden. Deze foutmelding kreeg ik maar niet opgelost. Uiteindelijk ben ik weer teruggegaan naar Java Serializable.
Na het opnieuw implementeren van Serializable ging het ineens goed, zonder een foutmelding. Waar- schijnlijk had ik tijdens de vorige implementatie een foutje gemaakt, dat ik dit keer niet maakte.
Mogelijk werkt dan ook het opslaan en inladen van levels. Echter bestaat de koppeling van de Editor en het spel alleen nog uit objecten uit de Level Editor. De Event Editor is nog niet gekoppeld, dus alle referenties in dat onderdeel hoeven (nog) niet te bestaan in het spel. Hierdoor is het simpeler om de koppeling te maken. Om deze reden kan het zo zijn dat het opslaan/inladen van levels nog steeds niet met Serializable werkt.
De koppeling tussen de Editor en het spel zou verder uitgebreid worden, zodat de gemaakte Events in de Event Editor ook ge¨ımporteerd werden in het spel, maar doordat de ontwikkeling van het spel is stilgezet is dit niet mogelijk (hierover is meer te lezen in sectie 23).
22.3. Voorbeeld
Om te laten zien dat de koppeling tussen de Editor en het spel bestaat, laat ik screenshots zien van een level dat gemaakt is in de Editor en ge¨ımporteerd is in het spel. De screenshot van de Editor is te zien in figuur 21a. Hier is te zien dat het android-logo gemaakt is. Dit object is als een convexe vorm gecre¨eerd, maar doordat dit object uiteindelijk niet convex was is het opgedeeld in driehoeken.
Hetzelfde geldt voor het woord ’YAY’. Een screenshot van het level in het spel is te zien in figuur 21b.
Hierin is het android-logo alsmede het woord ’YAY’ weer te zien, maar nu is het ´e´en geheel. Het gele object dat in deze screenshot te zien is, is een representatie van de speler. Dit wordt uiteindelijk veranderd in een echt speler-object, inclusief grafische elementen.
(a) Een screenshot van een level in de Editor. (b) Een screenshot van een level in het spel.
Figuur 21: De koppeling tussen de Editor en het spel.