Przykład: gra multiplayer w SFML

W tym przykładzie zajmiemy się zrobieniem prostej gry sieciowej dla 2 osób. Naszą grą będzie znana wszystkim gra „Kółko i krzyżyk”, także pod nazwą „Tic Tac Toe”. Ten przykład jest robiony częściowo „na żywo” tzn. kod jest pisany równolegle z pisaniem artykułu, jeżeli chcielibyście zobaczyć lekcje w stylu kursu Unity na YT to napiszcie o tym w komentarzach.

Na początku oczywiście przygotowujemy sobie projekt pod SFML, ja zlinkowałem swój statycznie. Jeżeli nie wiesz w jaki sposób należy przygotować swoje IDE do pracy z SFML zapraszam do podstawowego kursu SFML do działu Zaczynamy (instalacja SFML).

Ten przykład będzie raczej dosyć mocno przeze mnie opisany więc się nie zraź ewentualną jego długością bo w dużej części będą to rzeczy wyjaśnione przeze mnie w poradnikach, które możesz znaleźć na tym blogu.

Zaczynamy oczywiście od dołączenia nagłówków do naszej gry:

Następnie przechodzimy do funkcji main(), w której m.in tworzymy okno, a także jeżeli jesteśmy leniwi wczytujemy ip znajomego z pliku aby nie musieć go wpisywać za każdym razem.

Kolejnym krokiem jest wyświetlenie komunikatu z zapytaniem czy chcemy być serwerem czy klientem.

Skorzystałem tam z czcionki robotastic dostępnej m.in tutaj.

Jeżeli nie wczytujemy ip z pliku to pojawi się nam kolejny komunikat z prośbą o podanie ip, którego podanie zatwierdzamy klawiszem Enter (Return).

Komunikaty

Skoro mamy już informację kto jest serwerem, a kto klientem, a także znamy IP osoby, z którą będziemy grali to czas zacząć pisać właściwi kod.

Nasze próbne połączenie działa, tylko że jest 1 mały problem: nie może się nie udać. Tzn. będzie istniała próba nawiązania połączenia dopóki ono nie wystąpi, a to tego czasu nasze okno będzie nieaktywne i nieklikalne co rozwiążemy nieco później.

Na razie połączmy się sami ze sobą i zobaczmy jak nasze okno będzie wyglądało:

 

Moim zdaniem jest całkiem ok, po prawej stronie będzie można dodać informację z ilością wygranych gracza, czasem gry, itd. Teraz zajmiemy się nieco tym nieszczęsnym blokowaniem okna, przez co sprawia wrażenie że gra się zawiesiła.

Aby przeciwdziałać temu skorzystamy wątków (threads), o których możesz poczytać np. TUTAJ. Przy okazji wszelkie ustawienia przed pętlą główną gry.

Oraz funkcje odpowiadające za wysyłanie/odbieranie danych.

Pętlę główną rozbijemy sobie na kilka fragmentów bo jest ona dość spora.

Zaraz po rozpoczęciu pętli głównej mamy fragment, który odpowiada za odbieranie danych o ile jest taka potrzeba. Jeżeli jest ruch przeciwnika to jest uruchamiany wątek odpowiadający za odebranie danych i następnie zostaje w odpowiedni sposób wykorzystany.

Polecam tutaj na przeanalizowanie kodu. Kolejnym fragmentem jest pętla zdarzeń, gdzie w trochę winny sposób zakańczamy pracę naszego programu, przede wszystkim zakańczamy działanie wątków.

Następnym krokiem jest oczywiście sposób w jaki program ma się zachować gdy jest nasza tura, który jednocześnie kończy pętlę zdarzeń.

Oraz końcowa część kodu:

Jeżeli chciałbyś cały kod w 1 kawałku to będzie on dostępny poniżej w wersji na gitHub. Teraz zajmiemy się takimi czynnościami jak sprawdzenie wygranej.

Oto nasza funkcja sprawdzająca wygraną, jeżeli zwraca 0 to nic się nie dzieje, jeżeli 1 to wygrał serwer, jeżeli 2 to klient, jeżeli 3 to mamy remis.

Pod pętlą zdarzeń doszło nam właśnie sprawdzenie pól:

Jest tutaj także nowa zmienna exit, która decyduje o tym że po zmianie na true po 2 sekundach zakańcza działanie programu.

Zrobienie ewentualnych liczników i restartów programów pozostawiam wam, jeżeli chcecie możecie pochwalić się swoim kodem w komentarzach (np. umieszczając link do niego do pastebin, itp).

Powiedzcie też co sądzicie o tym abym pisał i komentował kod w formie filmu.

GitHub | .EXE