Sissejuhatus

Saate järgida neid samme koos selle videoga (iga sammul on ka timestamp). Looge uus projekt GitLabis ja kloonige see IntelliJ-sse. Projekti loomisel looge kaust client (game kaust videos) ja pärast LibGDX seadistamist looge server moodul. Klient tegeleb kasutajaliidese ja mänguloogikaga, see osa mängust töötab mängija seadmel, samas kui server haldab mitme kliendi vahelist suhtlust, võimaldades mitmikmängu suhtlust. Klient suhtleb serveriga, et vahetada teavet mängumaailma ja mängija tegevuste kohta. Alustamine LibGDX-iga (timestamp)

Alustamine LibGDX-iga

Looge LibGDX-projekt, luues IntelliJ mänguprojektis kausta libs. Laadige alla LibGDX Project Setup Tool. Avage IntelliJ projektis terminal, navigeerige kausta libs käsu cd libs abil ja kasutage java -jar .\gdx-setup.jar avamiseks. Konfigureerige oma projekti üksikasjad (seadistusaknas nimetage projekt vastavalt oma mängule, paketi nimeks valige ee.taltech. ja oma mängu nimi, nimetage oma mänguklass vastavalt oma mängule, väljundkausta sisestage oma client kausta tee), valige Desktop toetatud platvormiks ja valige mõni kasulik ametlik laiendus (nt Bullet, box3d, AI). Pärast genereerimist avage client kaust uues IntelliJ aknas. Projekti ehitamiseks kasutage Tasks > build > build ja mängu käivitamiseks kasutage Tasks > other > run.

Serveri seadistamine

(timestamp) Loo server moodul Gradle’i ehitussüsteemi jaoks ja kasuta Gradle DSL-ina Groovy’d. Ava server moodul uues IntelliJ aknas. Projekti ehitamiseks kasutage Tasks > build > build ja serveri käivitamiseks kasutage Tasks > other > run.

Serveri loogika rakendamine Kryonet’iga

(timestamp) Loo server klass, lisades uue directory src\main\java, luues package ee.taltech.game.server ja lisades uue Java klassi serveri loogika jaoks (nt GameServer). Külastage Kryoneti GitHubi lehte rakenduse üksikasjade kohta. Vaadake Kryonet’i kasutamise näiteid.

Lisa Kryonet’i dependency Gradle’ile

(timestamp) Ava build.gradle fail ja navigeeri Kryoneti Maveni Repository, et leida sobiv Gradle’i dependency teave. Lisa Kryonet’i dependency oma projekti, muutes build.gradle faili. Ehita projekt lisatud sõltuvusega kasutades Tasks > build > build.

Kryonet’i rakendamine Serveri klassis

(timestamp) Impordi com.esotericsoftware.kryonet.Server

oma serveri klassi. Lisage oma serveri klassi Server instance: private Server server = new Server();. Konstruktoris initsialiseerige server ja käsitlege vigu järgmise koodiga:

this.server = new Server();
try {
    server.start();
    server.bind(8080, 8081);
} catch (IOException e) {
    throw new RuntimeException(e);
}

server.start() algatab serveri ja valmistab selle ette ühenduste käsitlemiseks, server.bind(8080, 8081) seob serveri TCP pordile 8080 ja UDP pordile 8081, try-catch plokk aitab vigu käsitleda.

Lisage oma serveri klassi põhimeetod vastavalt oma serveri klassi nimele:

public static void main(String[] args) { GameServer gameServer = new GameServer(); }

Järgmine asi, mida lisada oma konstruktorisse, on Listener. (timestamp) Kryoneti listener vastutab erinevate sündmuste ja sõnumite käsitlemise eest Kryonet’i serveri käivitamise ajal. Kood, mis lisab listener, et printida vastuvõetud objekte, on järgmine:

server.addListener(new Listener() {
    public void received(Connection connection, Object object) {
        System.out.print(object);
    }
});

Klient

(timestamp) LibGDX on genereerinud meie projekti kliendi osa, mis koosneb kahest moodulist: core ja desktop. Desktop moodul võimaldab lihtsat viisi mängu testida ja arendada töölauakeskkonnas. Core moodul on koht, kuhu saate panna ühise koodi, mis hõlmab tavaliselt mängu loogikat või ressurside laadimist.

Vaadake näidisklienti GitHubis.

Kryonet’i seadistamine kliendi jaoks

(timestamp) Peate lisama Kryonet’i implementation gradle’i dependency ka kliendi jaoks. Lisa Kryonet’i implementation Gradle’i dependency. Ava build.gradle ja navigeeri Kryoneti Maveni Repository, et leida sobiv Gradle’i dependency teave. Ehita projekt lisatud sõltuvusega kasutades Tasks > build > build.

Kliendi mänguklass

Nüüd avage oma kliendi mänguklass. LibGDX genereeris mõned meetodid mängu loomiseks. create meetodit kutsutakse üks kord, kui rakendus luuakse esmakordselt. Siin tavaliselt initsialiseeritakse ressursid, seatakse mängumaailm ja tehakse muud seadistamise ülesanded. render meetod on koht, kus värskendatakse mänguloogikat, käsitsetakse sisendit ja joonistatakse graafikat. dispose meetod kutsutakse rakenduse sulgemisel või hävitamisel. Siin tuleks vabastada kõik ressursid, näiteks tekstuurid, helid või muud varad, et vabastada mälu ja vältida ressursilekkeid.

Kliendi connection serveriga

(timestamp) Impordi Kryonet oma kliendi mänguklassi: import com.esotericsoftware.kryonet.Client; Loo create meetodis Kryonet’i klient:

client = new Client();
client.start();

Sõnumi saatmiseks serverile mängu alguses kasutage create meetodis client.sendTCP("Start"); selleks, et saata sõna “Start” serverile. Testige render meetodit, kirjutades sinna client.sendTCP("test"); . Connect serveriga järgmise koodiga create meetodis:

try {
    client.connect(5000, "localhost", 8080, 8081);
} catch (IOException e) {
    throw new RuntimeException(e);
}

kus 5000 on aegumisaeg, mille jooksul klient ootab connectioni loomist, localhost on serveri hostinimi või IP-aadress, 8080 ja 8081 on TCP ja UDP portide numbrid, millele klient connectib. Pärast sessiooni lõppu sulgege klient dispose meetodis:

client.close();
try {
    client.dispose();
} catch (IOException e) {
    throw new RuntimeException(e);
}

Käivitage oma server (kui pole veel käivitatud) ja käivitage oma klient connectioni testimiseks. Peaksite nägema pidevat sõnumit “test”.

Liikumise lisamine kliendile

(timestamp) Nüüd lisame näiteks juba genereeritud LibGDX-assetile liikumise. Render meetodis kasutatakse sprite’i renderdamiseks SpriteBatchi. begin() ja end() meetodid määratlevad partii ulatuse, ja draw() meetodit kasutatakse iga individuaalse sprite’i jaoks. Näeme, et batch.draw(img, 0, 0); esimene 0 on img sprite’i x-koordinaat ja teine 0 on y-koordinaat. Sprite’i liigutamiseks peame olema võimelised muutma neid koordinaate. Lisage klassile privaatsed int muutujad private int x = 0, y = 0;. Muutke render meetodis batch.draw(img, 0, 0); batch.draw(img, x, y); -ks.

Liikumisi käsitlemine

(timestamp) Render meetodisse lisage järgmine kood, et muuta liikumist vastavalt nupulevajutusele:

if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
    x -= 10;
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
    x += 10;
}

Nüüd muutub x-koordinaat. Saate klientmängu käivitada selle testimiseks. Nüüd laseme mängijate koordinaadid serverile saata. Rakendage meetod private void sendPositionInfoServer() { client.sendUDP(x + " " + y);} mängija koordinaatide saatmiseks serverile ja kutsuge seda iga kord pärast koordinaatide muutmist, nii et see oleks näiteks

if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
    x -= 10;
    sendPositionInfoServer();
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
    x += 10;
    sendPositionInfoServer();
}

ja nüüd iga kord, kui liigute, saadab see teie koordinaatide teabe serverile.

N-mängijate connection

(timestamp) Lubage mitmeid eksemplare, muutes Run/Debug configurations ja lubades valikus Allow multiple instances Modify options-s. Serveri listeneri korral kasutage server.sendToAllUDP(object);, et saata teavet kõigile klientidele. (timestamp) Kliendi create meetodisse lisage listener, et vastu võtta andmeid serverilt (timestamp):

client.addListener(new Listener.ThreadedListener(new Listener() {
    @Override
    public void received(Connection connection, Object object) {
        System.out.print("received: " + object);
    }
}));

Nüüd saadab server teavet igale connected kliendile. (timestamp) Klientide eristamiseks kasutage serveris connectionide ID-sid ja haldage mänguobjekte ID-de ja koordinaatidega. Serveri klassi lisage private Map<Integer, String> gameObjects = new HashMap<>(); , et jälgida mänguobjekte. Nüüd lisage see kood serveri listeneri received meetodi sisse:

if (object instanceof String) {
    gameObjects.put(connection.getID(), (String) object);
}
server.sendToAllUDP(gameObjects.entrySet().stream().map(entry -> entry.getKey() + ":" + entry.getValue()).collect(Collectors.joining("|")));

See kood saadab iga connected kliendi ID ja koordinaadid kõigile klientidele.

Teiste klientide nähtavaks muutmine

(timestamp) Teise näitena teiste klientide nähtavaks muutmiseks kasutame LibGDX-i vara “drop.png”. Lisa kliendi klassi Texture opponentImg; ja initsialiseeri tekstuur create meetodis: opponentImg = new Texture("drop.png");.

Disconnectioni käsitlemine

(timestamp) Serveri listeneri korral ülekirjutage disconnected meetod ja eemaldage connected mängijad:

@Override
public void disconnected(Connection connection) {
    gameObjects.remove(connection.getID());
}

Muutke serveri edastusjoont serveri listeneri korral: server.sendToAllUDP(gameObjects.entrySet().stream().map(entry -> entry.getKey() + ":" + entry.getValue()).collect(Collectors.joining("|"))); saab server.sendToAllUDP(gameObjects);

Saadetud mänguobjektide käsitlemine kliendil

(timestamp) Loo vastaste SpriteBatchide jaoks kaardistus: private Map<Integer, SpriteBatch> opponentBatches = new HashMap<>(); Lisage kaart vastu võetud mänguobjektide salvestamiseks kliendile: private Map<Integer, String> receivedGameObjects = new HashMap<>(); Render meetodis käitle vastaste renderdamist järgmise koodiga:

for (Map.Entry<Integer, String> entry : receivedGameObjects.entrySet()) {
    int id = entry.getKey();
    if (id == clientId) continue;
    
    if (!opponentBatches.containsKey(id)) {
        opponentBatches.put(id, new SpriteBatch());
    }
    
    SpriteBatch b = opponentBatches.get(id);
    String[] coordinates = entry.getValue().split(",");
    b.begin();
    b.draw(opponentImg, Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]));
    b.end();
}

if (receivedGameObjects != null) {
    receivedGameObjects = null;
}

Lisage muutuja klient ID salvestamiseks private int clientId; kliendi klassis. Määrake kliendi ID create meetodis: clientId = client.getID(); Kliendi listeneri received meetodis salvestage saadud andmed receivedGameObjects:

if (object instanceof Map) {
    receivedGameObjects = (Map<Integer, String>) object;
}

Kryo registreerimine

(timestamp) Veenduge, et Kryo registreerimine oleks nii serveris kui ka kliendis. See tuleks teha võrguklassis nii serveris kui ka kliendis (näide), kuid me teeme selle põhiklassis näitena. Palun kasutage oma projektis selleks võrguklassi. Kryo registreerimist kasutatakse kõigi klasside jaoks, kuna see teavitab Kryo serialiseerimise raamistikku klassidest, mis võivad võrgu kaudu saata. Loo meetodis create HashMap’i registreerimiseks:

Kryo kryo = client.getKryo();
kryo.register(HashMap.class);

Serveri konstruktoris registreerige HashMap:

Kryo kryo = server.getKryo();
kryo.register(HashMap.class);

Järgmine osa videost käsitleb serveri JAR-faili loomist ja selle üleslaadimist TalTech’i serverisse. Te ei pea seda hetkel tegema, kuna see toimub semestri teises pooles.