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).

Typical-client-server-architecture

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 ja Player2 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 teete PacketConnectToLobby.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:

packets

Näide ühest PacketConnectToLobby.java klassist:

packetlobby

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

Flow-diagram

Mängija tegevused → Klient → Server → Teine klient

  1. Mängija vajutab nuppe (nt liikumine, tulistamine). See info saadetakse edasi kliendi PlayerInputManager kaudu.

  2. Klient saadab vajutused edasi serverisse, kasutades selleks sõnumeid nagu PlayerMovementMessage ja PlayerShootingMessage.

  3. 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).

  4. Serveris kontrollitakse kuulide kokkupõrkeid ja vajadusel vähendatakse elusid. Kõik see info hoitakse serveri sees, et mäng oleks aus ja turvaline.

  5. Kui mänguseis on muutunud, saadab server uue seisundi tagasi kõikidele klientidele, kasutades GameStateMessage sõnumit.

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