Coop Modus - Multiplayer Indie Game - Gether

Ein kooperatives Spiel

Das Projekt Gether ist durch und durch ein kooperatives Videospiel ohne einen Einzelspielermodus.

Wie realisiert man so etwas?

Wer schon einmal ein Spiel von Grund auf entwickelt hat, weiß wie aufwendig der gesamte Prozess der Entwicklung sein kann. Bei einem Multiplayerspiel erhöht sich der Aufwand noch um eine Schwierigkeitsstufe. Um ein Multiplayerspiel zu entwickeln müssen sich von Anfang an Gedanken gemacht werden, welche Dinge manipulierbar sein dürfen (Visuelles wie Skins, Tiles, etc.) und welche nicht (Charakter Position, etc.).

Trivialstes Prinzip zum Datenaustausch.

Entwickelt man allerdings ein Spiel, wie wir es tun, in welchem es maximal zwei Spieler geben soll, kann natürlich auf vieles verzichtet werden. So ist es nicht wichtig, dass der Server jede neue Charakter Position validiert und Teleportationshacks verhindert, denn in der Regel verderben sich die Spieler so nur selbst den Spaß.

Anders wäre es in einem MMORPG mit tausend fremden Spielern, die es vermutlich nicht so berauschend finden würden, wenn sich jemand durch die gesamte Karte teleportiert um so beispielsweise die besten Gegenstände abzustauben.

SFML - Pakete senden & empfangen (TCP)

Da wir mit SFML arbeiten, verwenden wir auch die Netzwerkfähigkeiten die uns SFML bietet. Um ein Paket über TCP zu versenden benötigen wir eine gültige bestehende Verbindung.

Diese Verbindung stellen wir her, indem wir die Methode connect aufrufen.

int port = 7777;
sf::TcpSocket socket;
socket.connect("127.0.0.1", port);

Hier gehen wir davon aus, dass ein Server auf unserem heimischen Rechner unter dem Port 7777 läuft. Um einen solchen Server zu erstellen, benutzen wir die Methode listen.

Vielleicht auch interessant
Die Idee - Multiplayer Indie Game - Gether
Die Idee - Multiplayer Indie Game - Gether

Erste Anreize und die Idee hinter meinem Multiplayer Game Projekt.

sf::TcpListener listener;
listener.listen(port);

sf::Socket client;
if(listener.accept(client) == sf::Socket::Done)
{
// connected
}

SFML blockiert standardmäßig die Applikation, solange bis sich jemand verbindet, Pakete gesendet und empfangen werden. Das sorgt im Klartext dafür, dass unser Spiel ziemlich oft einfriert, wenn wir im Mainthread arbeiten. Um das zu verhindern, deaktivieren wir das Blockieren mit setBlocking.

socket.setBlocking(false);
client.setBlocking(false);

Um Pakete an den Server zu senden, verwenden wir send.

sf::Packet packet;
packet << 1.0f << 2.0f;

if(socket.send(packet) != sf::Socket::Done)
{
// Error!
}

Sehr wichtig ist hier, dass nicht garantiert werden kann, dass Pakete immer erfolgreich versendet werden. Das bedeutet, dass ein Mechanismus realisiert werden muss, welcher die fehlgeschlagenen Pakete in der richtigen Reihenfolge erneut versendet.

Das könnte so aussehen:

processFailedPackets();

if(socket.send(packet) != sf::Socket::Done)
{
// std::vector<sf::Packet>
failedPackets.push_back(packet);
}

Um Pakete nun serverseitig zu empfangen, müssen wir die Methode receive aufrufen, hier muss beachtet werden, dass immer nur jeweils an einer einzigen Stelle im Quelltext (pro Socket) die Methode aufgerufen wird.

sf::Packet packet;
if(client.receive(packet) == sf::Socket::Done)
{
float a, b;
packet >> a >> b;
}

Mehr...

Natürlich war das nur die grundlegende Logik. Für ein gesamtes Spielprojekt wird es minimal komplexer. In der Regel verpackt man das Ganze in Klassen und trennt sehr strikt Serverlogik von Client Logik. Wie ich dass ganze für Gether realisiert habe, kann im fertigen Projekt dann gerne eingesehen werden. Der gesamte Quelltext wird am Ende zur Verfügung stehen.

Nächster Artikel
Gether - Final (Full Code)
Hinterlasse gerne einen Like oder Kommentar (~‾▿‾)~
Name Text