📜 ⬆️ ⬇️

Screwing multiplayer to the mobile game "Make a word from a word" on iOS and Android, written in C ++

Earlier, I already wrote about my experience in developing a mobile word game on Android and iOS, which enjoys a certain popularity, and I decided to tie the multiplayer mode to it, when two players compete with each other, making up words one by one as the final round of the TV show Sergei Suponev Star. hour".



It took me a month and a half to study and implement multiplayer, in the article I will try to describe the concept without source code examples, making a squeeze from the amount of work done.

A bit of history


The application was written in C ++ using the Marmalade SDK. Since then, the vendor has stopped supporting this platform, selling sorts to the Japanese, and the future of this development environment has become very vague.
')


The question arose of what to port the current projects for their further support.

Why not cocos2d-x




Cocos2d-x is one of the most common engines for developing cross-platform mobile games in C ++. Apparently, due to its free and open source. The engine is poorly documented. The description covers a scanty part of the engine and most of the material is long outdated.

According to the results of a certain period, I still managed to create a prototype of my application. But the impressions were very bad: the feeling that cocos2d-x is assembled on the knee. The levels of abstraction Scene, Sprite, Application Delegate seemed to me very inconvenient, and the need to look for answers to questions on the coconut forum more often lead you to think that you are doing something wrong. Probably my hands are not growing from that place.

My choice fell on SDL




SDL , as well as Marmalade SDL, is not an engine, it is a platform. It provides a low-level API, from which I then build convenient levels of abstraction for me. All this is written in C, the source code is open.

In a nutshell, SDL is a free cross-platform library for working with graphics, sound, and processing messages from the operating system. It is very convenient to do a win32 build and debug the game logic on Windows, leaving only OS debugging for mobile emulators and physical devices.

Fortunately or unfortunately, the SDL does not provide tools for such a narrow task as developing multiplayer for iOS and Android, so I had to integrate with the corresponding services myself.

Multithreaded application architecture


The application logic and all the work with graphics is implemented in the main thread, which is the message processing cycle and starts in the main function. Let's call this thread SDL Thread. In turn, other threads throw events (SDL_PushEvent) to it for processing into a queue, and that one reads them from it using SDL_WaitEvent and SDL_PollEvent. These are either system events thrown by the system and whose support is already implemented in the SDL, or calls to Callbacks and Listeners that we implement above SDL functionality.



The whole logic of the game is written in C ++. The project directory contains a set of * .cpp files that can be divided into three groups:


Accordingly, there are three separate directories for the project of each platform:


Integration with multiplayer services


Now we need to paste a separate layer, which will be responsible for such functionality as:


Both iOS and Android platforms support Real-time Multiplayer (RTMP). In the case of Android, we integrate with Google Play Services (GPS), in the case of iOS - Game Center. Previously, Google supported and integration with iOS, but this year decided to abandon it.

In this article I will not describe the actions that need to be performed in the Google Play Console and AppStoreConnect to configure multiplayer, I will not describe the specification of classes and integration methods - all this is described on vendor sites.

Next, I briefly describe what changes need to be made in the project for each of the platforms.

Android


How? I have not said this yet? To compile C ++ code, Android NDK is used . Although, if you are an Android developer, then you already know.

General instructions for integrating Google Play Services into an Android project are described on the website for Android developers. In my project I use the following dependencies:

implementation 'com.google.android.gms:play-services-games:16.0.0' implementation 'com.google.android.gms:play-services-nearby:16.0.0' implementation 'com.google.android.gms:play-services-auth:16.0.1' 

Initially, the idea was to use C ++ api , which comes in the form of compiled static libraries without source codes. Due to the fact that there is no build for the x86_64 platform in the list of libraries, I decided that the guys from Google didn’t really follow the relevance of this SDK and decided to invent my bike to write this layer in Java, wrapping it with JNI wrappers. And then, why do I need an extra dependency in the form of a lib without source code, which is still jerking Java inside itself? In addition to the relevance of Java classes, it will also be necessary to monitor the relevance of these libs.

As a guide used a good example from Google Samples . Thank you google for this. Apple, take a cue from Google!

iOS


To integrate with the Game Center you need to connect the GameKit framework. We describe the entire layer of integration with the Game Center in one * .m-file and provide the interface to it through a separate * .h file. Since C ++ is a subset of the language objective-C, then with the assembly of * .cpp and * .m files in one project there will be no problems.

In addition to the official documentation, I guided this project: GameCenterManager . True, some things from the example are already outdated, XCode 10 will indicate this to you and you will replace the outdated functionality with a new one.

The principle of working with a multiplayer layer


Single entry point


Having studied the features of working with multiplayer on both platforms, I created a single C ++ asbestos for my application and, at the time of compilation, the corresponding implementation is “attached” to it depending on the specific platform. That is, my application does not know about any Google Play Services, Game Center and their features. It knows only the C ++ api provided to it, where, for example, there are such methods as:

 SignIn() //     SignOut() //     LeaveRoom() //    SendMessage(...) //    ShowLeaderboards() //    SubmitScore(...) //    ... 

Search for an opponent


A player can invite a friend from his list of contacts, or start a game with a random opponent. The player who received the invitation can accept it, or reject it. For all these scenarios, I use the standard interface of the service used. It should be noted that google muzzles look much nicer than iOS-ovsky. Maybe someday my hands will get there and I will write my interface with dominoes and young ladies.

Connect to the game room


When two players have connected to the virtual gaming room, they receive the appropriate callback. Now you need to choose who will be the host.

Host selection


Among the players, you need to select a host so that it determines the initial state of the game.
Consider possible ways to route messages between players in the general case. Please note that in the second version the host also has the role of the router.



Since I always have only two players in the game, it turns out that I have a special case of peer-to-peer connections. And therefore, only the definition of the initial state drops to the role of the host, namely, the choice of the word from which the words will be composed.

So, after the players connected to the game room, each of the players knows the list of identifiers of the participants in the game that has begun. We will call it a list of participantID . A participantID is a kind of unique string identifier for a participant in a game, which is assigned by the service. It is necessary to choose which of them will be the host, bring it to the host itself and inform the other that its opponent is selected as the host. How to do it?

Choosing a host on Android

In the Google dock, I did not find tips on choosing a host. Silent, partisans. But kind people at stackoverflow.com threw a link to the video , which explains in detail the following principle:


IOS Host Selection

For iOS, there is a method selectBestHostPlayerWithCompletionHandler , which greatly simplifies the scenario of choosing a host compared to what I described for Android. But, judging by the noticeable delays during the call of this method, it evaluates the parameters of the network response, measures the ping and, on the basis of these statistics, decides who will be the host. It is more suitable for the above client-server architecture, where the host serves as a router. In my own variant of a private peer-to-peer connection, this does not make sense, and in order to save time, I use a principle similar to what I did for Android.

Messaging between players


What is a message? The message is an array of bytes.


There are 2 types of sending messages:


Unreliable is usually delivered faster than Reliable. More information can be found on the vendors website:


How will we use this array? Very simple:


So, we define the enum with the types of messages that players will exchange with each other during the game:


When an application receives an incoming message from an opponent, the corresponding Callback is called, which in turn sends it to the main SDL Thread for processing.

Connection monitoring


Gaming services (like Google’s, Apple’s) have listener functions that, in one form or another, are designed to alert us to breaking the connection with an opponent. But, I noticed that if one of the players is disconnected from the Internet, the second one does not immediately recognize that the first one has disconnected and there is no one to play with. Callbacks are not called in such cases, or they are called after a rather long time. So that in this case the second player would not have to wait for the cancer on the mountain to whistle, I had to do my own monitoring of the compound, working on the principle:


Result


As a result of the work done, I got a game that I play with my friends and family. I play both on iOS, and on Android.

True, there is a nuance on iOS - for some reason, points in Leaderboards are not fixed, which I am currently in correspondence with Apple support.

I hope this article will be useful as the members of my team, and those who are interested in developing mobile applications. Thanks for attention.

Source: https://habr.com/ru/post/433172/


All Articles