Poradnik: Jak napisać grę multiplayer RPG szybko i przyjemnie
Poradnik: Jak napisać grę multiplayer RPG
szybko i przyjemnie
Zasady
Pierwsza: nie zrobisz w ten sposób super hiper mega MMO Druga: jest masa lepszych sposobów aby to zrobić, ten jest prosty i mój Trzecia: możesz to traktować jako wstęp, ogólną ideę Czwarta: używam C++ i SFML Piąta: najpierw przeczytaj potem patrz kod na githubie :)
Pierwsze kroki
Zaczynamy od stworzenia klienta i serwera. Tutaj klient służy do komunikacji z serwerem i do wyświetlania świata gry. Serwer otrzymuje komendy od klienta i na ich podstawie aktualizuje świat gry i wysyła kopię do klienta. Świat składa się z graczy, przedmiotów, obiektów itd. Na początek przygotowujemy połączenie. Skoro doszedłeś do etapu, gdzie chcesz programować swoją grę multiplayer to zakładam, że sobie poradzisz z tą prostą czynnością. Tutaj masz link: https://www.sfml-dev.org/tutorials/2.4/network-socket.php
Dodanie gracza do serwera
Zadania:
- gracz potrzebuje unikalnego ID po stronie serwera
- musimy dodać gracza do Świata
- trzeba wysłać informacje o nowym graczu do klientów
Tak więc, kiedy klient łączy się z serwerem to on musi zrobić jakieś unikalne ID. Ja to zrobiłem w ten sposób:
std::string player_id = "player_id__" + std::to_string(reinterpret_cast<uint32_t>(client));
W ten sposób mamy ID dla gracza. Po prostu pobiera z pamięci adres clienta i robi z tego string. Wystarczająco dobre dla prostej, lokalnej gry.
world->addPlayer(Player(player_id, sf::Vector2f(100, 100), sf::Vector2f(66, 92), 100));
Tak dodajemy gracza do świata z wcześniej utworzonym id, pozycją, rozmiarem i życiem. Następnie wysyłamy informację o graczu do klienta.
sf::Packet start_packet;
start_packet << "connect" << *world->getPlayer(player_id);
client->send(start_packet);
Strona klienta: - wydobywamy ID gracza z otrzymanego pakietu i przechowujemy go w kliencie (pozwoli nam to informować serwer kim jesteśmy) Więc kiedy otrzymamy pakiet sprawdzamy czy to jest 'connect' i wydobywamy ID gracza i przypisujemy do
client_player_id = received_id;
Logika
Reszta logiki jest podobna. Na przykład: Klient wysyła komendę 'update world' - serwer po otrzymaniu tego wysyła cały świat do gracza Kiedy klient otrzyma 'update world' podmienia świat na ten, który dostał z serwera Klient wysyła 'move player up' i swój id do serwera, który przesuwa gracza o danym id w górę Sprawa jest ogólnie prosta. Zobacz na mój przykładowy kod do komunikacji pomiędzy klientem i serwerem. Klient:
void Client::runCommand(const std::string& command, const std::string& id)
{
if(command == "player move")
{
sf::Packet packet;
packet << "player move" << id << player_id;
socket.send(packet);
}
if(command == "destroy item")
{
sf::Packet packet;
packet << "destroy item" << id;
socket.send(packet);
}
}
To jest część kodu z klasy Client. Używam tutaj prostej funkcji, która wysyła polecenia do serwera. Serwer:
sf::Packet packet;
if(client.receive(packet) == sf::Socket::Done)
{
std::string event;
if(packet >> event)
{
if(event == "player move")
{
std::string player_id;
std::string direction;
if(packet >> direction >> player_id)
{
if(direction == "up")
world->getPlayer(player_id)->position.y -= 5;
if(direction == "down")
world->getPlayer(player_id)->position.y += 5;
if(direction == "left")
world->getPlayer(player_id)->position.x -= 5;
if(direction == "right")
world->getPlayer(player_id)->position.x += 5;
}
}
if(event == "update world")
{
sf::Packet send_packet;
send_packet << "update world" << *world;
client.send(send_packet);
}
if(event == "destroy item")
{
std::string item_id;
if(packet >> item_id)
{
world->removeItem(item_id);
}
}
}
}
Podsumowanie
Może nie jest to idealne rozwiązanie. Może nie robi się tak gier. Nie takie jest zadanie tego postu. Ma on pokazać ogólną ideę stojącą za komunikacją w grach pomiędzy serwerem i graczem. Nawet jeśli nie jest to zrobione idealnie to dla mnie jest to kod z którego jestem dumny. Nie ma dobrych poradników, które za rękę poprowadzą kogoś jak się robi gry multiplayer. Przynajmniej nie było kiedy to programowałem (rok 2015). Jestem na tyle dumny z tego kodu, że często się nim posługuję pokazując, że jestem w stanie samemu wymyślić sposób aby rozwiązać jakiś problem.
Obiecany kod
Github: PMR - Patys MMO RPG