A Multiplayer Játék Beállítása a Socket.io segítségével | hyperPad Documentation

Loading...

Logo

z-f2VkDQ.jpg

1. Rész: Bevezetés

Ajánlott Előfeltételek

Ebben a bemutatóban a játékunk kiszolgáló beállítására és a csatlakozásra fogunk összpontosítani, hogy lehetővé tegyük a többjátékos funkciókat a Socket.io viselkedéseken keresztül. Fejlett funkciókat és viselkedéseket fogunk tárgyalni a hyperPad-ben, és határozottan ajánlott, hogy először nézze át a többi bemutatót, és szerezzen egy alaposabb érzést a szoftver működéséről, mielőtt folytatná.

Ez a bemutató feltételezi, hogy Ön jól érti a hyperPad alapvető funkcióit, valamint hogy van egy minimális megértése az írott programozásnak, mivel a játék kiszolgáló építéséhez Javascript szkriptekre fogunk összpontosítani. A bemutató azt is feltételezi, hogy van némi alapvető hálózati tudása és hogy megérti a szerverek és az ügyfeleik közötti különbségeket.

A bemutató elsődleges célja, hogy megtanítsa Önnek, mit kell tennie a többjátékos funkciók hozzáadásához a játékához; nem a játék megépítésére. Felfedezzük a Socket.io ügyfelek és a szerver közötti kapcsolatot, valamint azt, hogyan kommunikálnak egymással a Socket.io viselkedéseken keresztül.

Követelmények

A szerver létrehozásához és üzemeltetéséhez szüksége lesz egy számítógépre, amely képes futtatni a Node.JS -t (Mac, Windows, stb). A Node.JS telepítése és beállítása a céljainkhoz a bemutatóban tárgyalva lesz. Ha a szerverét az otthoni hálózatában üzemelteti, valószínűleg meg kell változtatnia a router port-továbbítási beállításait, ha kívülről érkező kapcsolatokat szeretne elfogadni a helyi hálózatán kívülről.

Ehhez a bemutatóhoz már létrehoztunk egy egyszerű bemutató játékot. Ebben két játékos játszik a fogócskát egy kis labirintusban. Felfedezzük, hogyan használják a Socket.io viselkedéseket a példa projektben, ezért ajánlott letölteni és megnyitni a projektet a hyperPad-ben.

A befejezett hyperPad példa projekthez itt tölthető le: Multiplayer tag tutorial.tap

Áttekintés

Ebben a bemutatóban áttekintjük a szerver létrehozásának alapjait a játékához. A szerver kezeli a játék legtöbb részletét, mint például a pontszámokat, játéktereket stb. Ezután viselkedéseket hozunk létre, amelyek információkat küldenek a játékunkból a szerverhez és fordítva.

Itt van a játékunk általános folyása:

1. A főmenüből csatlakozunk a szerverünkhöz, és lehetőséget adunk a felhasználónak arra, hogy játékszobát hozzon létre vagy csatlakozzon ahhoz.

a. Ha játékot hoznak létre, betöltjük a várótermet.

b. Ha játékot csatlakoznak, betöltjük a rendelkezésre álló játékterek listáját.

c. Amikor két játékos van a váróteremben, a játék elindul.

2. A játék során a szerver véletlenszerűen elhelyezi a játékosokat négy területen, és az egyiküket „E” státuszt kapja.

a. A másik játékos megjelölése véletlenszerűvé teszi a helyszíneiket, átadja az E státuszt és hozzáad egy pontot ahhoz a játékoshoz, aki megjelölte a másikat.

b. Ha egy bizonyos időtartamon belül nincs megjelölés, a szerver 1 pontot von le az éppen É-n álló játékostól, és megcseréli az E státuszt, mielőtt véletlenszerűen újra elhelyezné a játékosokat a spawn zónákban.

3. Miután egy játékos elérte a szükséges pontszámot, egy overlayt tölt be, amely győztest hirdet. Ezután a játékosok leválnak a szobáról és visszatérnek a főmenübe.

2. Rész: A Szerver Beállítása

Socket.io szerver létrehozásához Javascript alkalmazást kell futtatnunk a Socket.io könyvtárral, amely figyel az játékosok csatlakozására. A Socket.io egy Javascript hálózati könyvtár, amely leegyszerűsíti számunkra az internetes alkalmazás építésének nagyrészét. További részletek a későbbiekben.

Node.JS Letöltése és Telepítése

A kezdéshez látogassa meg a Node.JS webhelyet, és töltse le a számítógépére (Mac, Windows, stb.), amin a szervert üzemeltetni szeretné. A letöltés befejezése után futtassa a telepítőt, és kövesse az utasításokat. A telepítés során az összes lehetőséget hagyhatja alapértelmezettként. A Node.JS lehetővé teszi számunkra, hogy Javascript alkalmazásokat futtassunk önállóan, anélkül, hogy web böngészőre lenne szükségünk.

A Példa Szerver Letöltése és Futtatása

Következő lépésként töltse le a bemutató Multiplayer Server Example alkalmazását a GitHub-on:

Kattintson a "Clone or download" gombra, és válassza "Download ZIP" lehetőséget. Ez letölti a szerver példa kódját.

chrome_2019-08-05_14-22-14.png

Az letöltött ZIP fájlt ki kell csomagolni. Az állományban talál néhány kis fájlt, de a legfontosabb fájl itt az "index.js" fájl, amely a szerverünk kódja. Ezután nyissa meg a parancssort/terminált a szerver példa mappájában.

Írja be az "npm install" parancsot, és nyomja meg az Enter billentyűt, majd hagyja futni. Az npm egy csomagkezelő, amely beolvassa a package.json fájlt és letölti a szükséges csomagokat a szerverünkhöz. (A Socket.io-t is beleértve!)

cmd_2019-08-05_14-55-19.png

Amikor a parancs befejeződik, mindenünk megvan ahhoz, hogy elindítsuk a szervert. A terminálba írja be a "node ." parancsot, és a szerver elindul.

cmd_2019-08-05_15-02-38.png

Ennyi! A szerverünk most figyel a 3000-es porton bejövő Socket.io kapcsolatokra.

A "node ." parancs a Node.JS-t a jelenlegi könyvtárban indítja el, ahol meg fogja keresni a könyvtár index fájlját, és futtatja azt. Alapértelmezés szerint ez az "index.js" Javascript fájl, amelynek a szerverünk kódjának nagy része található, és amelyet a bemutató során át fogunk nézni.

Hagyja nyitva a terminált, mivel a bezárás is bezárja a szervert. Látni fogja a céges üzeneteket, amikor a játékosok csatlakoznak vagy lekapcsolódnak, amikor szobák létrejönnek vagy megszűnnek, és egyéb eseményeket fog tapasztalni.

Megjegyzés: Az otthoni hálózaton kívüli bejövő kapcsolatok engedélyezéséhez valószínűleg meg kell nyitnia a 3000-es portot az otthoni routerén. Ez a folyamat hálózatonként eltérő, de általában található egy útmutató az interneten a porttovábbítás módosításához a modem/jelző hálózatokhoz. Lehet, hogy újra be kell zárnia és indítania a Node.JS szervert, amikor megváltoztatja a porttovábbítás beállításait.

3. Rész: Csatlakozás a Szerverhez

Miután elindította a szerver alapjait, most csatlakozhatunk egy hyperPad játékhoz. Ezt érdemes az első lépésként megcsinálni a projektben, függetlenül attól, hogy melyik jelenetben vagyunk (mivel mindennek kommunikálnia kell a szerverrel). A legjobb, ha ezt a viselkedést egy objektumhoz kapcsoljuk a Globális Rétegen, így az minden jelenetben hatással lesz.

Untitled.jpg

A példa projektben a Globális Réteg „Szerver” címkéje tartalmazza a fenti kódot. (A projekt letöltése a bekapcsolási 1. részében, a Követelmények szakaszban található.)

Ezek a két viselkedés tényleg az egyetlen szükséges ahhoz, hogy csatlakozzunk a szerverhez. Először is, a testreszabott fül alatt helyezze el a Socket.io Ügyfél viselkedést, és húzza le. Itt az URL fül alatt meg kell adnia a szervere URL-jét a tulajdonságok ablakában. A fenti képen a szerverünk URL-je "http://192.168.0.191:3000" volt, beleértve a protokollt és a portot. Ezt meg kell változtatnia, hogy illeszkedjen a szervere URL-jére, különben valószínűleg nem fog működni, amikor elindítja a játékot.

Most van információnk a szerverünkről, de még mindig csatlakoznunk kell hozzá. Tehát, amire szükségünk van, az a Csatlakozni a Sockethez viselkedés. Húzzon le egyet, nyissa meg a tulajdonságait, és válassza ki az ügyfelet az üres dobozban, majd állítsa a Funkció tulajdonságot „Csatlakozás”-ra.

Most, amikor a projektünk betöltődik, automatikusan csatlakozni fogunk a szerverünkhöz.

mceclip1.png

4. Rész: Szobák Létrehozása és Csatlakozás

A következő lépés a játékterek létrehozása, ahol a játékosok beléphetnek és együtt játszhatnak.

mceclip2.png

Itt van a mi egyszerű Főmenü képernyőnk. Csak érintse meg az egyik gombot, hogy szobát indítson, vagy keressen elérhető szobákat.

Szobák Létrehozása

Nézzük meg, hogyan kommunikálunk a szerverrel a szoba létrehozása érdekében.

mceclip3.png

Egész egyszerű, nem? Tehát gyorsan áttekintve, amikor megérintjük a gombunkat, felkérnek minket, hogy írjunk be egy szoba nevet. Miután ezzel végeztünk, ezt a nevet a szervernek továbbítjuk, ahol a szoba létrejön, és betöltjük a váróterem jelenetet.

Ezután gyakran az Emit to Socket viselkedést fogjuk használni. Ez azért van, mert ez a fő módja annak, hogy adatokat küldjünk a szervernek. Gondoljon rá, hogy ez egyszerűen az „online verziója” a Broadcast Message és Receive Message -nek (Az Emit to Socket két műveletet egyszerre hajt végre).

Most hozzá kell adnunk néhány információt a szerverünkhöz, hogy létrehozhassa a szobát, miután megkapja a jelzést az Emit viselkedésből.

mceclip4.png

socket.on('createRoom', (roomName, callback) => {

Ez a sor egy socket eseményt hoz létre (lambdáként) a szerveren, amely figyelni fog a 'createRoom' eseményekre érkező Emits-re.

Az első paraméter az, amit az Emit to Socket viselkedéshez továbbítunk, jelen esetben a felhasználó által megadott szoba neve. Itt ezt a paramétert „roomName”-nak neveztük.

A második paraméter egy olyan funkció, amelyet később felhívunk a socket esemény során, hogy jelezzük az ügyfélnek. Az Emit to Socket viselkedés csak akkor folytatja a végrehajtást, ha a callback funkciót a szerveren meghívják. Itt ezt a paramétert „callback”-nak neveztük.

const room = {
id: uuid(),
name: roomName,
sockets: []
};

Ez létrehoz egy struktúra példányt, amely tartalmazza a szoba alapvető információit.

'id' egyedi azonosítót tartalmaz, amelyet az 'uuid()' segédfunkció generál. Ez segít abban, hogy ezt a szobát azonosítsuk a sok más létrehozott szoba listájában.

'name' beállítása a felhasználó által korábban megadott névre történik.

'sockets' üres tömbként lesz inicializálva. Később ez nyomon követi a szobához csatlakozó játékos csatlakozásokat.

rooms[room.id] = room;

'rooms' egy globális lista az aktív szobákról. Mivel új szobát hozunk létre, a listába az ID szerint fogjuk tárolni.

joinRoom(socket, room);

Ez felhívja a globális 'joinRoom' funkciót (29. sor), amely hozzáadja a játékos socketet a szoba 'sockets' tömbjéhez. Mivel a játékos létrehozta a szobát, ez őt is belépíti a szobába.

callback();
});

Végül meghívjuk a callback funkciót, hogy értesítsük az ügyfelet, hogy a szoba létrejött. Ez lehetővé teszi az Emit a Sockethez viselkedés számára, hogy folytassa a végrehajtást, amely betölti a Váróterem jelenetet. Ez egyben a 'createRoom' socket esemény végének jele is.

Szobák Csatlakozása

A szobák csatlakozása némileg eltérő, mivel hozzá kell férnünk az információkhoz a gomb különböző jelenetéből.

mceclip5.png

A csatlakozáshoz a következő működést a globális rétegen helyeztük el, ahogyan a szerverhez csatlakozunk. Így bármely jelenetben elérhetjük az információkat, jelen esetben a szobalistát. A gomba megérintése egyszerűen betölti a játékost a szobalista jelenetbe.

Itt van a második viselkedésünk a szerverrel való kommunikációra. A Socket eseményt úgy lehet értelmezni, mint a Receive Message-t, mivel csak akkor aktiválódik, ha a beállított üzenetet a szerver kibővíti.

A legjobb úgy gondolni, hogy a Socket esemény csak a szerverről érkező információkra reagál, míg az Emit a Sockethez viselkedés helyben végzett tettek reakciójában hívódik meg.

A logikánk szerint, amint csatlakozunk a szerverhez, Emiteljük a 'getRoomNames' kérdést a rendelkezésre álló szobanevekre.

mceclip19.png

Ezután beállítunk egy címkét, amelyre a játékos rákattinthat, hogy belépjen.

mceclip6.png

Ez a Szobalista jelenet. Itt fogja betölteni és megjeleníteni minden elérhető játéktermet. Egyszerűen a szoba nevére kattintva beléphet a játékos. Az eddigi viselkedéseinknek köszönhetően a lista automatikusan betölti az összes nyitott szobát és létrehozza a szobanevek címkéit a képernyőn. Ha semmi nem jelenik meg, van egy Frissítés lista gombunk, amely egyszerűen megismétli a viselkedéseket, hogy betölthessük őket újra.

mceclip7.png mceclip8.png

Itt van a lista beállításával kapcsolatos logikánk. Nem megyünk túl sok részletbe, mivel csak annyit akarunk tudni, hogyan kapcsolódik ez a szerverünkhöz.

Kezdésként az Emit a Sockethez viselkedést használjuk. Ez a szervert kéri, hogy küldjön információt a rendelkezésre álló szobákról. Ezután egy Get Array Value viselkedést alkalmazunk. Az összes, a szerverről érkező adat Egy tömbben küldik el, és az első érték tartalmazza a szükséges információt. Tehát a Get Array Value viselkedést úgy állítjuk be, hogy az 0-ás indexnél lévő értéket szerezze be. Ebből a viselkedésünk kinyeri az adatokat, és egy címkét készít minden szobához, amelyet a képernyőn jelenítünk meg.

Ezután meg fogjuk vizsgálni azt az objektumot, amelyre meg kell érinteni, a jelenetünkben ez a szoba nevét viselő címke.

mceclip9.png

Ez a szöveg szolgál gombként a megjelenítésnél, de még mindenképpen kapcsolni kell a csatlakozni kívánt szoba ID-t. Ezt úgy tudjuk megtenni, hogy először megkapjuk a szoba ID-t, és ezt a Get Attribute viselkedéssel dinamikusra állítjuk. Ezután Emitáljuk a szervernek, hogy szeretnénk csatlakozni ehhez a szobához és belépni a váróterembe.

mceclip10.png

socket.on('joinRoom', (roomId, callback) => {

Ez a belépési pont a 'joinRoom' socket eseményhez. Az első paraméter értéke a szobának az ID-ja, amelyhez csatlakozni szeretnénk, és amely a szerverhez lett továbbítva. Itt ezt a paramétert 'roomId'-nak neveztük.

const room = rooms[roomId];
joinRoom(socket, room);

A megadott roomId használatával megtalálhatjuk a megfelelő szoba példányt a szerveren. Ezzel felhívjuk a globális 'joinRoom' funkciót (29. sor) a játékos csatlakozási socketjével és a szoba példányával. A 'joinRoom' funkciót mindjárt áttekintjük.

callback();
});

Végül meghívjuk a callback funkciót, hogy értesítsük az ügyfelet a Váróterem jelenet betöltéséről, ami a 'joinRoom' socket esemény befejezésének jele.

Szóval, mi történik pontosan a 'joinRoom' funkcióban? Nézzük meg.

mceclip11.png

room.socket.push(socket);

Ahogy korábban említettük, a 'room.socket' tömb nyomon követi a szobában csatlakozott socketeket. Ez a sor pontosan ezt teszi, a socketet a tömbhöz rendelve.

socket.join(room.id, () => {
socket.roomId = room.id;
console.log(socket.id, "Csatlakozott", room.id);
});

Ez a hivatalos hívás a kliens szobához történő csatlakoztatására az ID-ja alapján. Először megmondjuk a socketnek, hogy csatlakozzon egy szobához az ID-jával. Amikor ezt már befejeztük, a következő callback hívódik, ahol a szoba ID-t a sockethez rendeljük. Végül bejegyzést készítünk a konzolon arról, hogy egy játékos csatlakozott egy szobához!

mceclip12.png

A Váróterem

A váróterem egyszerűen egy jelenet, amelybe a játékosokat betöltik, miközben várják, hogy más játékosok csatlakozzanak, vagy hogy a játék elkezdődjön.

mceclip13.png

Belépéskor Emitálni fogunk egy 'ready' üzenetet a szervernek. Amint a szerver megkapott két ilyen üzenetet, elküldi az üzenetet, hogy elkezdi a játékot ('initGame'). Ezt az üzenetet a Socket eseményünkkel fogjuk érinteni, amely betölti a játék szinten. A viselkedéseink szempontjából nagyjából ennyi. Ha szeretné, hozzáadhat egy gombot is, amely leválasztja Önt a szobáról, és visszatér a főmenübe.

A szerveren nézzük meg a kódot, hogy lássuk, mi történik ott.

mceclip14.png

Ez a 'ready' esemény, amely akkor hívódik, amikor egy kliens csatlakozott egy szobához, és készen áll a csatlakozásra.

const room = rooms[socket.roomId];

Mivel a szoba ID-ját a sockethez rendeltük, így képesek vagyunk hozzáférni a szobához és ellenőrizni, hogy a játék elindulhat-e.

if (room.sockets.length == 2) {

Itt ellenőrizzük, hogy most már két játékos várakozik-e a szobában. Tegyük fel, hogy ez most igaz, és folytatjuk a játékot.

for (const client of room.sockets) {
client.emit('initGame');
}

Most, hogy két játékos van, átfutunk minden socketen, és emitáljuk az 'initGame' eseményt, hogy minden kliens betöltse a Szint jelenetet, ahogy korábban bemutattuk.

5. Rész: Játék Menete

Most áttérhetünk a lényegre. Ez az, ahol az összes munkánk 90%-a zajlik. Az alábbi képen a játék szintjénket látja, amelyet ehhez a bemutatóhoz terveztünk.

mceclip15.png

Azonban mielőtt ebbe belemennénk, van egy címkénk, amely "Játék Logika" felirattal rendelkezik, nézzük meg, mit tartalmaz.

mceclip16.png

Wow, ez sok viselkedés! Ne aggódjon, ez csupán a játékosok spawnálásának folyamata. Nézzük meg közelebbről;

mceclip17.png

Kezdünk egy Emit a Sockethez viselkedéssel, amely megmondja a szervernek, hogy a játék elkezdődött, a 'startGame' eseménnyel. Ezután megragadjuk a tömböt, amelyet a szerver visszaküld, lekérjük az első értékét, és a Get Dictionary Value segítségével megszerezzük az objektumunk különböző attribútumait. Egy külön fa ugyanezt teszi, de az ellenfelek esetében. Végül emitáljuk az 'init' üzenetet a játékos objektumunkhoz, hogy elinduljanak a dolgok.

Nézzük meg, mi történik a szerver oldalon, amikor emitáljuk a 'startGame' eseményt.

mceclip20.png

Az esemény első fele, amelyet itt látunk, a kezdeti értékek beállítása minden klienshez, majd a helyi 'others' tömbbe adunk hozzá minden ügyfelet, aki nem az emitáló kliens.

mceclip21.png

A második fele, egy helyi szótár lista létrejön 'ack' néven. Itt olyan információk találhatók, mint a saját adataink és a másik ügyfél(ek) adatai. Ezután visszaküldjük ezt az információt a kliensnek, úgy, hogy az 'ack' szótárunkat átadjuk a callback függvénynek, amely a hívott Emit a Sockethez viselkedés eredménye lesz.

Ezután egy 5 másodperces timeout hívást indítunk a kört végre hajtó hívás megkezdésére, miután mindenki megkapta az összes információt, amire szüksége van a játékhoz. A 'beginRound' funkció (99. sor) kezeli a projekthez kapcsolódó játék specifikus logikát. Nem fogunk ebbe mélyen belemerülni, de alapvetően kezeli a játékosok spawnálásának helyét, a pontszámok ellenőrzését, valamint azt, hogy miként mondjuk el az ügyfeleknek, ki a „Z”.

Ahogy már említettük, az 'init' üzenet a „Játék Logika” címkén hívódik meg, amikor minden kész. A játékos objektumán most megnézzük a viselkedéseit, ahová megkapja az 'init' üzenetet.

mceclip22.png

Itt látható, hogy több viselkedésfa jelen van a játékosunkon. Először elindulunk a bal fenti fával.

mceclip23.png

Ez a viselkedés gyakorlatilag mindent elindít a játékunkban.

Először megkapjuk az 'init' üzenetet, amelyet a "Játék Logika" címke küldött. Ezt követően megszerezzük az objektumunk szerver ID-ját, és bekapcsoljuk az egyik Socket Eseményünket, valamint beállítjuk a játékképernyőt, hogy pontosan nyomon követhessük a karakterünket.

A Mozgás Szinkronizálása

mceclip24.png

Itt van az egyik legfontosabb viselkedésünk. Ez a kis fa tervezi, hogy frissítse a játékosunk helyzetét a szerveren, amikor a joystickot mozgatjuk. Valószínűleg észrevette, hogy ez is hivatkozik néhány szótár értékre. Ezeket a boltban lévő szótár viselkedésből nyerjük, amely a játékosunk X és Y pozícióit tartalmazza.

Nézzük meg a 'moved' eseményt a szerverben.

mceclip25.png

data = JSON.parse(data);

A szótárak, amikor egy kliens küld a szervernek, a könnyebb olvashatóság érdekében parsolva kell, hogy legyenek. Ez azért van, mert a hyperPad szótárakat JSON struktúrába kódolja, amikor azokat a szervernek emitálják. Ez a sor a JSON string struktúrájának feldolgozását és a szótáralapú lista viszekét is elmenti ugyanabba a helyi 'data' változóba.

socket.x = data.x;
socket.y = data.y;

Itt frissítjük a socketon tárolt X és Y pozíciókat az ügyféltől kapott új értékekkel.

for (const client of room.sockets) {
if (client == socket) {
continue;
}
client.emit(socket.id, {
x: socket.x,
y: socket.y,
score: socket.score,
isIt: socket.isIt
});
}

Következőként végigfutunk az összes ügyfelet frissítve az új pozíciójukról és más részletekről, kivéve magunkat (azaz az emitáló kliensnek nincs szüksége saját pozíciójára).

mceclip26.png

Ez a fa vezérli a játékunk legnagyobb részét. Socket Eseményt használunk, amikor a szerver ellenőrzi, hogy ki az, akit It-nek lehet nevezni, amelyet a 'beginRound' (99. sor) lead az előtérbe.

Ezután a Dictionary Value segítségével megkapjuk a szerver ID-ját az objektumunkkal, és felbontjuk a különböző adathalmaszt. Ebből kinyerjük a pontszámunkat, hogy megjelöltük-e a „Z”-t, valamint az objektumunk x és y pozícióit, és az értékeket minden egyes objektumhoz hozzárendeljük. A további viselkedések a játék rajzi felületeinek beállításáról és ellenőrzéséről szolgálnak.

Összegzés

Sok információt kellett feldolgozni, de remélhetőleg ha idáig eljutott, megérti, hogyan kell kihasználni a Socket.io viselkedéseket, hogy többjátékos élményeket nyújtson a játékosainak.

Próbálja ki! Vegye egy meglévő játékot, amelyet létrehozott, és próbáljon meg online funkciókat hozzáadni, például egy legmagasabb pontszámú listát, amely csatlakozik a szerverhez, és kér egy listát a top 10 ponttal rendelkező játékos nevével.

Nehezen lehet egy olyan szkriptnyelvet, mint a Javascript, egy cikkben tanítani. Szerencsére, ha problémái vannak, rengeteg más forrás segíti a Javascript alkalmazások írását a Node.JS és a Socket.io-hoz;

Javascript megtanulása - https://developer.mozilla.org/bm/docs/Web/JavaScript

Socket.io megtanulása - https://socket.io/docs/

Node.JS megtanulása - https://nodejs.org/en/docs/