Multiplayer mängu loomiseks LibGDX-iga kliendi poolel ja KryoNet-iga serveri poolel hõlmab sellist projektistruktuuri, mis eraldab kliendi ja serveri koodi, kuid võimaldab nende vahel lihtsat ja kiiret suhtlust.
Projekti struktuur¶
Mänguprojekt on jaotatud sisuliselt kaheks alamprojektiks:
Klient: Kliendi poolel hakkab teil toimuma mäng lokaaltasandil, mängija tegevuste kontrollimine ning nende edastamine serverisse.
Server: Server tegeleb mängu seisu hoidmisega, mängijate tegevuste ja info laiali saatmisega ning tagabki selle, et mäng on mängitav võrgus.
Iga kord kui mängija midagi teeb, siis koheselt peab klient edastama selle informatsiooni serverisse ning server omakorda edastab selle teistele mängijatele.
Selleks, et see kõik toimuks võimalikult kiiresti ja sujuvalt tuleb teada, kuidas mängu struktureerida ning mis failidega infot saata.
(Mõlema põhimõttega lähemalt tutvumiseks lugege läbi Klient-server suhtlus materjal).
Mängu struktuur¶
Mängu maailma puhul on kaks võimalust:
Maailm on kliendis
Maailma laadimine toimub kiiremini.
AI implementeerimisel võivad tekkida probleemid. Seda seepärast, et tehisintellekti tegevus toimub serveri poolel ning selleks, et temal oleks ka ülevaade mängust, on temal ka vaja maailmat.
Maailm on serveris
Maailma saatmine klientidele on sisukam.
Mängu maailma jaoks on soovitatav teha universaalne World.java
klass.
Mängijate tegemisel on samuti rangelt soovitatav hoida lihtsat joont ning teha üks universaalne Player
klass.
Kui teil on mängijate jaoks mitu erinevat versiooni, siis seda on võimalk implementeerida läbi selle,
et laiendate ühte Player
klassi.
Kui alguses juhtub, et teete mängu lokaaltasandil ainult ja teil on
Player1
jaPlayer2
klassid, siis selline lahendus hea ei ole ning teeb teie tööd kordades keerulisemaks.
Kui teil mängus on mitu erinevat vaadet (näiteks Menu, Lobby, End Screen), siis iga
vaate jaoks tuleb teil teha eraldi klass mis kõik laiendavad kliendi universaalset Screen.java
klassi.
See tuleb kasuks potentsiaalsete vigade parandamisel, sest nii on kood kihistunud erinevate olukordade vahel ning lihtsam on analüüsida.
Info saatmine¶
Info saatmine hakkab teil toimuma Packet
-iga.
Selleks on teil vaja ühte universaalset Packet.java
klassi, mida hakkate laiendama.
Iga informatsioon, mida hakkate saatma, peab olema eraldi klassis.
Olgu selleks siis näiteks klientide liitumine
lobby
-iga, siis selleks teetePacketConnectToLobby.java
klassi.
Iga Packet
-i sees hakkab olema vastav informatsioon.
Üldjuhul võiks olla nii, et ühes
Packet
-is liiga palju informatsiooni korraga ei oleks, sest nii on lihtsam infot struktureerida.
NB! Kõik Packet
-id, mis on kliendis, peavad ka serveris olema ning nende sisud mõlemal pool identsed.
Näide potentsiaalsetest Packet
klassidest:
Näide ühest PacketConnectToLobby.java
klassist:
Mängu "Flow diagram"¶
Selleks, et mitmikmäng töötaks sujuvalt, peab klient ja server omavahel infot vahetama väga täpselt ja kiirelt.
Alloleval skeemil on näha, kuidas toimub andmevahetus mängija, kliendi ja serveri vahel. See näitab, kuidas mängija vajutab nuppe, info liigub serverisse ja lõpuks uuendatakse mängupilti kõigis klientides. Skeem on võetud sellest projektist
Mängija tegevused → Klient → Server → Teine klient
Mängija vajutab nuppe (nt liikumine, tulistamine). See info saadetakse edasi kliendi
PlayerInputManager
kaudu.Klient saadab vajutused edasi serverisse, kasutades selleks sõnumeid nagu
PlayerMovementMessage
jaPlayerShootingMessage
.Server võtab need sõnumid vastu ja töötleb need läbi. Iga mängija kohta luuakse sama kuulaja klassi eraldi eksemplar (diagrammil on see näidatud näiteks kui Player1MovementListener jms). Server uuendab mängu olekut (nt mängija asukohta, uusi kuule jms).
Serveris kontrollitakse kuulide kokkupõrkeid ja vajadusel vähendatakse elusid. Kõik see info hoitakse serveri sees, et mäng oleks aus ja turvaline.
Kui mänguseis on muutunud, saadab server uue seisundi tagasi kõikidele klientidele, kasutades
GameStateMessage
sõnumit.Klient saab sõnumi ja uuendab ekraanil kuvatavat mängupilti: mängijad, kuule, kaart jne. Kõik see toimub
GameStateManager
abil, mis juhib mängupilti.
Selline lähenemine tagab selle, et kõik mängijad näevad sama mängu ning keegi ei saa ebaõiglast eelist.