Meteor – Realtime HTML5 Canvas Game

Geplaatst door Bart Riepe op 23 juli 2012

Tag(s): Hobbyprojecten

Eens per jaar krijgen de medewerkers van Infi de mogelijkheid om een week lang aan een hobbyproject te werken. De enige limitatie is dat het enige relevantie heeft voor de beroepspraktijk. Ik had al een tijdje een idee in mijn hoofd voor het maken van een multiplayer spel. Iemand stuurde een tijdje geleden een berichtje rond waarin de real-time webtechnologie Meteor werd aangeprezen; dat leek me een zeer interessante combinatie om eens uit te proberen.

Mijn doel was om een game te maken waarbij je met ruimtescheepjes rond kunt vliegen en kunt schieten op meteoren en op je medespelers. Zo kun je punten verdienen om uiteindelijk de game te winnen. Hier zie je het uiteindelijke resultaat:

De technologie die ik in eerste instantie wilde gebruiken was Meteor. Meteor is een heel mooie library die het mogelijk maakt om updates die je op één pagina maakt, direct door te sturen naar andere browsers die ook die data aan het bekijken zijn. Bovendien is alle data op alle clients gesynchroniseerd beschikbaar en dus snel om op te zoeken. Het enige nadeel is dat het momenteel nog geen beveiliging heeft, waardoor iedereen databasebewerkingen op de database kan uitvoeren. Voor mij was dat echter nog niet zo relevant.

Ik ben begonnen met het maken van de interface waarmee je aan spellen zou kunnen meedoen, een chatroom en andere mooie interface-technische zaken. Dat ging fantastisch, Meteor werkte prachtig, en als ik op het ene scherm een berichtje intikte, dan verscheen het een paar milliseconden later ook op het andere scherm.

Nadat dat klaar was, ben ik begonnen met het ontwikkelen van het spel, maar dat bleek aanzienlijk moeilijker. Ik had gedacht dat ik het wel even in elkaar zou flansen, maar ik kwam vaak dingen tegen waar ik helemaal nooit aan gedacht had. Het belangrijkste probleem waar ik tegenaan liep, was mijn gebruik van Meteor. Het is een heel slimme library, dus als je veel dingen tegelijkertijd (of kort na elkaar) wijzigt, dan spaart hij die wijzigingen op, zodat ze allemaal tegelijk naar de server worden gestuurd. Het probleem was: mijn spel stuurde zo snel verschillende updates (elke 30 milliseconden werd de positie van een schip geüpdatet), dat de library eeuwig bleef wachten. Er werd een heleboel gewijzigd, maar de wijzigingen waren nooit te zien bij de andere spelers. Pas als ik de updatefrequentie verlaagde naar om de 400 milliseconden begon er weer iets te bewegen bij de andere spelers.

Iedereen die wel eens een multiplayer spel heeft gespeeld, weet echter dat 2.5 keer per seconde een update krijgen van de positie van je tegenstander niet erg praktisch is als je hem nog op een fatsoenlijke manier wilt kunnen raken. De scheepjes schokten over het scherm. Om dat probleem een beetje op te lossen, heb ik toen interpolatie geïmplementeerd. Het spel onthoudt dan in welke richting het schip aan het bewegen is en zet in de tijd dat het geen verdere informatie krijgt, de beweging in die richting voort. Hierdoor kon je ook de tussenposities redelijk weergeven.

Maar het was nog steeds lelijk. Spelers drukken binnen een halve seconde best veel knopjes in om hun schip in een andere richting te laten bewegen, dus je zag elke keer het scheepje naar de juiste positie schokken. Nadat ik een dag lang tevergeefs had geprobeerd om dit gedrag te verbeteren en erg gefrustreerd was geraakt over de documentatie van Meteor – of liever gezegd het gebrek daaraan - besloot ik dat mijn keuze voor Meteor onjuist was. De library bevat nog wat onvolkomenheden en is onaf, waardoor hij voor mijn doeleinde ontoereikend is.

Ik bleef echter wel zitten met een project dat ik graag wilde afmaken. Eerder had ik al een keertje summier met node.js, in combinatie met socket.io gewerkt, en uit ervaring daarmee wist ik dat dat die libraries op een veel lager niveau zitten dan Meteor (je moet dus veel meer dingen zelf doen), maar ook dat ze vrijwel instantaan alle data oversturen. Op het moment dat ik de client had omgeschreven om daarmee om te gaan, had ik plotseling een vrij mooi multiplayer spel. De scheepjes vlogen vloeiend heen en weer, en het enige wat nog miste was een mechanisme om op elkaar te schieten, en wat code om de score bij te houden.

Eerst wilde ik gaan schieten, maar liep daarbij tegen nog een interessant probleem aan. Kogels vliegen snel, en scheepjes ook, als je wil kijken of elkaar raken, dan moet je dat een aantal keer per seconde doen. Als ze echter snel genoeg gaan, dan zijn ze langs elkaar heen voordat er zo’n check gedaan wordt. Er zijn vrij veel verschillende manieren om dit op te lossen, maar ze kosten allemaal vrij veel tijd om te maken - vooral als je zoals ik, niet extreem goed bent in hogere wiskunde.

Omdat dit soort problemen op meerdere plekken voorkomt, zijn er gelukkig al mensen die er oplossingen voor hebben gemaakt en deze vrij beschikbaar stellen op het internet. Mijn keuze viel op een physics engine/library met de naam Box2D, die ook goed botsingen tussen objecten kon detecteren. 

Sowieso is natuurwetten toepassen op een ruimtespel natuurlijk leuk, want er is niets dat meer ‘ruimte!’ schreeuwt dan een vacuum waarin je scheepjes blijven rondvliegen in de exacte richting die ze hadden wanneer je geen motoren aan hebt staan en waarin ze oneindig kunnen versnellen. Uiteraard was die hele engine inbouwen weer bijna even veel werk als het me zou hebben gekost om zelf het botsen tussen twee objecten te maken, maar nu kreeg ik daar veel meer voor terug. Opeens functioneerden mijn ruimtescheepjes als echte ruimteschepen, en moesten ze boosters aan meerdere kanten van het schip hebben om een beetje fatsoenlijk te kunnen draaien en bewegen. Interessant was ook dat elke botsing of kogelinslag een schip nu een nare draaiing meegaf, wat er bijzonder leuk uitzag.

Toen was eindelijk het moment aangebroken om met twee spelers tegen elkaar te spelen. Het was een groot succes, maar er was iets waar ik tot dan toe nooit over had nagedacht. Vliegen in de ruimte is namelijk helemaal niet leuk, en geraakt worden door een inslag die je scheepje als een malle doet tollen al helemaal niet. Het eerste probleem: achtervolgingen. Als je tot in het oneindige mag versnellen, dan kost het evenzoveel tijd om weer af te remmen naar 0. Wanneer je dus achter iemand aanzit, en jullie zijn allebei flink op snelheid, dan kan hij een klein beetje remmen, waarop je direct langs hem heen schiet, en het een eeuwigheid duurt voor je weer bij elkaar bent. Dit probleem is nog veel erger wanneer je op elkaar af vliegt, aangezien je de neiging hebt om vooral te blijven versnellen, waarop je langs elkaar heenschiet (zonder elkaar te raken) en dan weer een hele tijd bezig bent voordat je überhaupt omgekeerd bent. Dan was er nog het tollen: als je elkaar raakte, schoot je in zó’n spin, dat het je een paar seconden kostte om weer enige controle te krijgen. Dat was frustrerend en niet leuk, want in die tijd kon de ander al lang een volgend schot plaatsen.

In ieder geval waren er dus nog genoeg dingen om aan te passen, maar de tijdslimiet kwam in zicht. Het leek me beter om dit even te laten rusten en ervan uit te gaan dat mensen zulk realisme zouden appreciëren. Het laatste wat ik nog snel moest inbouwen, was het bijhouden van de score, en het verliezen/winnen van de game. Aangezien de tijd nogal beperkt was, is dat in minimale vorm geïmplementeerd, waardoor het nog niet mogelijk is om daadwerkelijk de game te winnen. Je kunt wel zien hoeveel van je tegenstanders je al kapotgeschoten hebt.

Mijn plan is om het spel steeds wat verder door te ontwikkelen.

Schrijf een reactie:

Naam:
E-mail*:
Bericht:
*optioneel, wordt niet getoond.