
Einführung
Die Geschichte begann mit einem Blockchain-basierten Hackathon. Zu Beginn der Veranstaltung traf ich einen Mann, der Brettspiele als Hobby entwickelt (ich war beim Spieltest eines solchen Spiels). Wir haben uns zusammengetan und ein Team gefunden, mit dem sie über das Wochenende ein einfaches strategisches Spiel „geblendet“ haben. Der Hackathon ging vorbei, aber die Begeisterung blieb. Und wir hatten die Idee eines Multiplayer-Kartenspiels über Glück, die Weltgemeinschaft und Wahlen.
In der Artikelserie werden wir unseren Weg zur Erstellung eines Spiels reflektieren, mit einer Beschreibung des Rakes, auf den wir bereits getreten sind, und auf dem wir vorwärts gehen werden.
Unter dem Schnitt wird sein:
- Spielübersicht
- Wie die Entscheidung getroffen wurde, was im Backend zu tun ist. Wo wird es „leben“, damit es sich in der Entwicklungsphase nicht bezahlt macht?
- Erste Schritte in der Entwicklung - Spielerauthentifizierung und Organisation des Matchmaking
- Weitere Pläne
Worum geht es in dem Spiel?
Die Menschheit hat die Weltkriege, die Erschöpfung der Ressourcen und den ständigen Wettbewerb satt. Die wichtigsten Fraktionen waren sich einig, moderne Technologie einzusetzen, um eine einzige Führung auszuwählen. Zum festgelegten Zeitpunkt muss die Weltwählerschaft über die Wahl eines Bruchteils entscheiden, der den Planeten für das nächste Jahrtausend regieren wird. Schlüsselfraktionen führen einen „ehrlichen“ Machtkampf. In einer Spielsitzung repräsentiert jeder Spieler einen Bruchteil.
In diesem Kartenspiel geht es um Wahlen. Jede Fraktion hat ein Budget für die Durchführung des Wahlkampfs, Einnahmequellen, die das Budget erhöhen, und Startstimmen. Zu Beginn des Spiels wird das Deck mit den Aktionskarten gemischt und jedem Teilnehmer werden 4 Karten ausgegeben. In jeder Runde können die Spieler bis zu zwei Spielaktionen ausführen. Um die Karte zu verwenden, legt der Spieler sie auf den Tisch und bestimmt gegebenenfalls das Ziel und zieht die Kosten für die Verwendung der Karte vom Budget ab. Nach dem Ende der Runde kann der Spieler nur eine der nicht verwendeten Karten behalten. Zu Beginn jeder Runde erhalten die Spieler Karten vom Stapel, so dass jeder Spieler zu Beginn jeder Runde 4 Aktionskarten zur Hand hat.
Am Ende der Runden 3, 6 und 9 wird der Spieler mit der geringsten Stimmenzahl aus dem Spiel entfernt. Wenn mehrere Spieler die gleiche Mindestanzahl an Stimmen haben, werden alle Spieler mit diesem Ergebnis aus dem Spiel ausgeschlossen. Die Stimmen dieser Spieler gehen in den allgemeinen Pool der Wähler.
Am Ende der 12. Runde ist der Gewinner derjenige mit den meisten Stimmen.
Auswahl eines Tools für das Backend
Aus der Beschreibung des Spiels folgt:
- Dies ist Multiplayer
- Es ist notwendig, Spieler irgendwie zu identifizieren und Konten zu verwalten
- Das Vorhandensein einer sozialen Komponente würde dem Spiel zugute kommen - Freunde, Gemeinschaften (Clans), Chats, Erfolge (Erfolge)
- Bestenlisten und Matchmaking-Funktionen sind erforderlich.
- Die Funktionen zur Turnierverwaltung werden in Zukunft nützlich sein
- Da es sich bei dem Spiel um ein Kartenspiel handelt, müssen Sie den Kartenkatalog verwalten und möglicherweise Karten speichern, die dem Spieler zur Verfügung stehen, sowie kompilierte Decks
- In Zukunft kann eine In-Game-Wirtschaft erforderlich sein, einschließlich In-Game-Währung und Austausch virtueller Güter (Karten).
Als ich mir die Liste der Bedürfnisse ansah, kam ich sofort zu dem Schluss, dass es keinen Sinn macht, in der Anfangsphase ein eigenes Backend zu erstellen, und ging zu Google, was andere Optionen sind. Daher fand ich heraus, dass es spezielle Cloud-Gaming-Backends gibt, unter denen sich PlayFab (von Microsoft gekauft) und GameSparks (von Amazon gekauft) hervorheben.
Im Allgemeinen sind sie funktional ähnlich und decken die Grundbedürfnisse ab. Darüber hinaus ist ihre interne Architektur sehr unterschiedlich, dieselben Aufgaben werden etwas unterschiedlich gelöst und explizite Entsprechungen in den Merkmalen sind schwer nachzuvollziehen. Nachfolgend finden Sie die positiven und negativen Merkmale jeder Plattform sowie Überlegungen zum Thema Ihrer Wahl.
Playfab
Positive Eigenschaften:
- Konten aus verschiedenen Spielen werden zu einem Hauptkonto zusammengefasst
- Die Gaming-Wirtschaft wird ohne eine einzige Codezeile beschrieben, einschließlich der Preisgestaltung für ein separates virtuelles Geschäft
- Freundliche Benutzeroberfläche
- Microsoft erwirbt Produkt nach der Akquisition
- Die Betriebskosten für die Produktion im Indie Studio-Abonnement betragen 99 USD (bis zu 100.000 MAU). Wenn Sie zum Professional 1k MAU-Abonnement wechseln, kosten Sie 8 USD (Mindestkonto 300 USD).
Negative Merkmale:
- Die Speicherung von Spieldaten ist streng begrenzt, z. B. in einem kostenlosen Abonnement zum Speichern von Daten für eine bestimmte Spielsitzung (wenn ich alles richtig verstehe, werden dafür Entitätsgruppen verwendet). Es sind 3 Slots mit jeweils 500 Byte verfügbar
- Um den Mehrspielermodus zu organisieren, müssen Sie Server von Drittanbietern verbinden, die Ereignisse von Clients verarbeiten und die Spielelogik berechnen. Dies ist entweder Photon auf Ihrer Hardware oder Azure Thunderhead, und Sie müssen nicht nur den Server organisieren, sondern auch Ihr Abonnement auf mindestens Indie Studio aktualisieren
- Es ist notwendig zu ertragen, dass der Cloud-Code ohne automatische Vervollständigung und es keine Möglichkeit gibt, in Module zu brechen (oder nicht gefunden?)
- Es gibt keinen normalen Debugger. Sie können nur Protokolle in CloudScript schreiben und anzeigen
Gamesparks
Positive Eigenschaften:
- Speicherung von Spieldaten. Es gibt nicht nur viele Orte, an denen Sie Daten speichern können (allgemeine Spielmetadaten, virtuelle Güter, Spielerprofil, Mehrspielersitzungen usw.), sondern die Plattform bietet auch eine vollwertige Datenbank als Service, die an nichts gebunden ist. Darüber hinaus sind sowohl MongoDB als auch Redis für verschiedene Datentypen sofort verfügbar. In der Entwicklungsumgebung können Sie 10 MB speichern, im Kampf 10 GB
- Multiplayer ist in einem kostenlosen Abonnement (Entwicklung) mit einem Limit von 10 gleichzeitigen Verbindungen und 10 Anforderungen pro Sekunde verfügbar
- Bequeme Arbeit mit CloudCode, einschließlich eines integrierten Tools zum Testen und Debuggen (Test Harness)
Negative Merkmale:
- Das Gefühl, dass seit dem Kauf durch Amazon (Winter 2018) das Tool stagniert hat, gibt es keine Innovationen
- Nach der Übernahme von Amazon verschlechterten sich die Tarife erneut, und früher war es möglich, bis zu 10.000 MAU kostenlos in der Produktion zu verwenden
- Die Produktionsbetriebskosten beginnen bei 300 USD (Standardabonnement).
Reflexionen
Zuerst müssen Sie das Konzept des Spiels überprüfen. Zu diesem Zweck möchte ich einen Prototyp aus Stöcken und Klebeband ohne Geldinvestitionen bauen und mit dem Testen der Spielmechanik beginnen. Daher möchte ich bei der Auswahl zunächst die Möglichkeit eröffnen, einen Mechaniker mit einem kostenlosen Abonnement zu entwickeln und zu testen.
GameSparks erfüllt dieses Kriterium, PlayFab jedoch nicht, da Sie einen Server benötigen, der die Ereignisse von Spieleclients verarbeitet, und ein Abonnement auf Indie-Studio-Ebene (99 US-Dollar).
Gleichzeitig akzeptiere ich das Risiko, dass Amazon keine GameSparks entwickelt, was bedeutet, dass es "sterben" kann. Angesichts dieser und immer noch der Betriebskosten in der Produktion denke ich an die potenzielle Notwendigkeit, entweder auf eine andere Plattform oder in mein eigenes Backend zu wechseln.
Erste Schritte in der Entwicklung
Verbindung und Authentifizierung
Die Wahl fiel also auf GameSparks als Backend in der Prototyping-Phase. Der erste Schritt besteht darin, zu lernen, wie Sie eine Verbindung zur Plattform herstellen und den Player authentifizieren. Ein wichtiger Punkt ist, dass der Benutzer unmittelbar nach der Installation des Spiels ohne Registrierung und SMS spielen kann. Zu diesem Zweck bietet GameSparks die Möglichkeit, ein anonymes Profil durch Aufrufen der DeviceAuthenticationRequest-Methode zu erstellen. Später können Sie auf der Grundlage eines anonymen Profils ein vollwertiges Profil erstellen, indem Sie beispielsweise eine Verbindung mit Ihrem Google-Konto herstellen.
Da ich eine Gehirn-TDD habe, habe ich zunächst einen Test erstellt, um den Client mit dem Spiel zu verbinden. Da CloudCode in Zukunft in JS geschrieben werden muss, werde ich Integrationstests in JS mit mocha.js und chai.js durchführen. Der erste Test verlief wie folgt:
var expect = require("chai").expect; var GameClientModule = require("../src/gameClient"); describe("Integration test", function () { this.timeout(0); it("should connect client to server", async function () { var gameClient = new GameClientModule.GameClient(); expect(gameClient.connected()).is.false; await gameClient.connect(); expect(gameClient.connected()).is.true; }); })
Standardmäßig beträgt das Timeout in mocha.js 2 Sekunden. Ich mache es sofort endlos, da es sich bei den Tests um Integration handelt. Im Test erstelle ich einen Spielclient, der noch nicht implementiert wurde, überprüfe, ob keine Verbindung zum Server besteht, rufe den Befehl zum Herstellen einer Verbindung zum Backend auf und überprüfe, ob der Client erfolgreich eine Verbindung hergestellt hat.
Damit der Test grün wird, müssen Sie das GameSparks JS SDK herunterladen und zum Projekt hinzufügen, seine Abhängigkeiten (crypto-js und ws) verbinden und natürlich GameClientModule implementieren:
var GameSparks = require("../gamesparks-javascript-sdk-2018-04-18/gamesparks-functions"); var config = new require("./config.json"); exports.GameClient = function () { var gamesparks = new GameSparks(); this.connected = () => (gamesparks.connected === true); this.connect = function () { return new Promise(function (resolve, reject) { gamesparks.initPreview({ key: config.gameApiKey, secret: config.credentialSecret, credential: config.credential, onInit: () => resolve(), onMessage: onMessage, onError: (error) => reject(error), logger: console.log }); }); } function onMessage(message) { console.log("GAME onMessage: " + JSON.stringify(message)); } }
Bei der Startimplementierung des Spielclients werden die Schlüssel, die für die technische Autorisierung zum Herstellen einer Verbindung aus der Clientanwendung erforderlich sind, aus der Konfiguration gelesen. Die verbundene Methode umschließt dasselbe Feld aus dem SDK. Das Wichtigste, was bei der Verbindungsmethode passiert, ist, dass sie ein Versprechen mit Rückrufen für eine erfolgreiche Verbindung oder einen Fehler zurückgibt und den onMessage-Handler an denselben Rückruf bindet. onMessage fungiert vom Backend aus als Nachrichtenverarbeitungsmanager. Lassen Sie es jetzt Nachrichten in der Konsole protokollieren.
Es scheint, dass die Arbeit abgeschlossen ist, aber der Test bleibt rot. Es stellt sich heraus, dass das GameSparks JS SDK nicht mit node.js funktioniert. Ihnen fehlt der Browserkontext. Lassen Sie ihn denken, dass der Knoten Chrome auf der Mohnblume ist. Wir gehen zu gamesparks.js und fügen ganz am Anfang hinzu:
if (typeof module === 'object' && module.exports) {
Der Test wurde grün und ging weiter.
Wie ich bereits geschrieben habe, sollte ein Spieler in der Lage sein, sofort mit dem Spielen zu beginnen, sobald er das Spiel betritt, während ich anfangen möchte, Analysen in Aktivitäten zu sammeln. Dazu binden wir entweder an die Gerätekennung oder an eine zufällig generierte Kennung. Überprüfen Sie, ob dies ein solcher Test ist:
it("should auth two anonymous players", async function () { var gameClient1 = new GameClientModule.GameClient(); expect(gameClient1.playerId).is.undefined; var gameClient2 = new GameClientModule.GameClient(); expect(gameClient2.playerId).is.undefined; await gameClient1.connect(); await gameClient1.authWithCustomId("111"); expect(gameClient1.playerId).is.equals("5b5f5614031f5bc44d59b6a9"); await gameClient2.connect(); await gameClient2.authWithCustomId("222"); expect(gameClient2.playerId).is.equals("5b5f6ddb031f5bc44d59b741"); });
Ich habe mich entschlossen, sofort 2 Clients zu überprüfen, um sicherzustellen, dass jeder Client sein eigenes Profil im Backend erstellt. Dazu benötigt der Spielclient eine Methode, mit der Sie eine bestimmte Kennung außerhalb von GameSparks übertragen und dann überprüfen können, ob der Client das gewünschte Spielerprofil kontaktiert hat. Im Voraus erstellte Profile auf dem GameSparks-Portal.
Für die Implementierung in GameClient fügen Sie Folgendes hinzu:
this.playerId = undefined; this.authWithCustomId = function (customId) { return new Promise(resolve => { var requestData = { "deviceId": customId , "deviceOS": "NodeJS" } sendRequest("DeviceAuthenticationRequest", requestData) .then(response => { if (response.userId) { this.playerId = response.userId; resolve(); } else { reject(new Error(response)); } }) .catch(error => { console.error(error); }); }); } function sendRequest(requestType, requestData) { return new Promise(function (resolve) { gamesparks.sendWithData(requestType, requestData, (response) => resolve(response)); }); }
Bei der Implementierung wird eine DeviceAuthenticationRequest-Anforderung gesendet, die Kennung des Spielers aus der Antwort empfangen und in die Eigenschaft des Clients gestellt. In einer separaten Methode schickte der Helfer sofort Anfragen mit einem Wrapper in einem Promis an GameSparks.
Beide Tests sind grün, es bleibt noch das Schließen der Verbindung und des Refaktors hinzuzufügen.
In GameClient habe ich eine Methode hinzugefügt, die die Verbindung zum Server schließt (trennen) und connectAsAnonymous, indem connect und authWithCustomId kombiniert werden. Einerseits verstößt connectAsAnonymous gegen das Prinzip der Einzelverantwortung, scheint aber nicht zu verletzen ... Gleichzeitig erhöht es die Benutzerfreundlichkeit, da in Tests häufig die Authentifizierung von Clients erforderlich ist. Was denkst du darüber?
In Tests fügte er einen Factory-Methoden-Helfer hinzu, der eine neue Instanz des Spiel-Clients erstellt und das Array der erstellten Clients erweitert. Im speziellen Mokka-Handler rufe ich nach jedem Test für Clients im Array die Trennungsmethode auf und lösche dieses Array. Ich mag "magische Zeichenfolgen" im Code noch nicht, daher habe ich ein Wörterbuch mit benutzerdefinierten Bezeichnern hinzugefügt, die in den Tests verwendet wurden.
Der endgültige Code kann im Repository angezeigt werden, ein Link, den ich am Ende des Artikels geben werde.
Organisation der Spielsuche (Matchmaking)
Ich starte die Matchmaking-Funktion, die für den Mehrspielermodus sehr wichtig ist. Dieses System beginnt zu funktionieren, wenn wir in einem Spiel auf die Schaltfläche „Spiel suchen“ klicken. Sie nimmt entweder Rivalen oder Teamkollegen oder beide auf (je nach Spiel). In solchen Systemen hat jeder Spieler in der Regel einen numerischen Indikator MMR (Match Making Ratio) - eine persönliche Bewertung des Spielers, mit der andere Spieler mit den gleichen Fähigkeiten ausgewählt werden.
Um diese Funktionalität zu testen, habe ich folgenden Test entwickelt:
it("should find match", async function () { var gameClient1 = newGameClient(); var gameClient2 = newGameClient(); var gameClient3 = newGameClient(); await gameClient1.connectAsAnonymous(playerCustomIds.id1); await gameClient2.connectAsAnonymous(playerCustomIds.id2); await gameClient3.connectAsAnonymous(playerCustomIds.id3); await gameClient1.findStandardMatch(); expect(gameClient1.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await gameClient2.findStandardMatch(); expect(gameClient2.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await gameClient3.findStandardMatch(); expect(gameClient3.state) .is.equals(GameClientModule.GameClientStates.MATCHMAKING); await sleep(3000); expect(gameClient1.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient1.challenge, "challenge").is.not.undefined; expect(gameClient1.challenge.challengeId).is.not.undefined; expect(gameClient2.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient2.challenge.challengeId) .is.equals(gameClient1.challenge.challengeId); expect(gameClient3.state) .is.equals(GameClientModule.GameClientStates.CHALLENGE); expect(gameClient3.challenge.challengeId) .is.equals(gameClient1.challenge.challengeId); });
Drei Clients sind mit dem Spiel verbunden (in Zukunft ist dies ein notwendiges Minimum, um einige Szenarien zu überprüfen) und für die Suche nach dem Spiel registriert. Nach der Registrierung des 3. Spielers auf dem Server wird eine Spielsitzung gebildet, und die Spieler müssen eine Verbindung herstellen. Gleichzeitig ändert sich der Status der Clients und der Kontext der Spielsitzung mit derselben Kennung wird angezeigt.
Bereiten Sie zuerst das Backend vor. In GameSparks gibt es ein vorgefertigtes Tool zum Anpassen der Suche nach Spielen, das unter dem Pfad „Konfigurator-> Übereinstimmungen“ verfügbar ist. Ich erstelle eine neue und fahre mit dem Setup fort. Zusätzlich zu den Standardparametern wie Code, Name und Beschreibung des Spiels wird die minimale und maximale Anzahl von Spielern angegeben, die für einen benutzerdefinierten Spielmodus erforderlich sind. Ich werde dem erstellten Match den Code "StandardMatch" zuweisen und die Anzahl der Spieler von 2 bis 3 angeben.
Jetzt müssen Sie die Regeln für die Auswahl der Spieler im Abschnitt „Schwellenwerte“ konfigurieren. Für jeden Schwellenwert werden der Zeitpunkt seiner Aktion, der Typ (absolut, relativ und in Prozent) und die Grenzen angegeben.

Angenommen, ein Spieler mit einer MMR von 19 beginnt mit der Suche. Im obigen Beispiel werden in den ersten 10 Sekunden andere Spieler mit einer MMR von 19 bis 21 ausgewählt. Wenn die Spieler nicht ausgewählt werden können, wird der zweite Suchrand aktiviert, wodurch der Suchbereich für die nächsten 20 Sekunden von 16 erweitert wird ( 19-3) bis 22 (19 + 3). Als nächstes wird der dritte Schwellenwert aufgenommen, innerhalb dessen eine Suche für 30 Sekunden im Bereich von 14 (19-25%) bis 29 (19 + 50%) durchgeführt wird, während das Spiel als abgeschlossen gilt, wenn die erforderliche Mindestanzahl von Spielern angesammelt wurde (Min. Akzeptieren) Spieler).
Tatsächlich ist der Mechanismus komplizierter, da er die MMR aller Spieler berücksichtigt, die es geschafft haben, an einem bestimmten Spiel teilzunehmen. Ich werde diese Details analysieren, wenn es an der Zeit ist, den Bewertungsmodus des Spiels festzulegen (nicht in diesem Artikel). Für den Standardspielmodus, in dem ich MMR noch nicht verwenden möchte, benötige ich nur einen Schwellenwert.
Wenn alle Spieler ausgewählt wurden, müssen Sie eine Spielsitzung erstellen und die Spieler damit verbinden. In GameSparks ist die Spielsitzungsfunktion die „Herausforderung“. Als Teil dieser Entität werden Spielsitzungsdaten gespeichert und Nachrichten zwischen Spielclients ausgetauscht. Um einen neuen Herausforderungstyp zu erstellen, müssen Sie dem Pfad „Konfigurator-> Herausforderungen“ folgen. Dort füge ich einen neuen Typ mit dem Code "StandardChallenge" hinzu und gebe an, dass diese Art von Spielsitzung rundenbasiert ist, d. H. Spieler wechseln sich ab, nicht gleichzeitig. Gleichzeitig übernimmt GameSparks die Kontrolle über die Reihenfolge der Züge.
Damit sich ein Client registrieren kann, um nach einem Spiel zu suchen, können Sie eine Anfrage vom Typ MatchmakingRequest verwenden, die ich jedoch nicht empfehlen würde, da der MMR-Wert des Spielers als einer der Parameter erforderlich ist. Dies kann zu Betrug seitens des Spielclients führen, und der Client sollte keine MMR kennen, dies ist ein Backend-Geschäft. Um mich korrekt für die Spielsuche zu registrieren, erstelle ich ein beliebiges Ereignis vom Client. Dies erfolgt im Abschnitt „Konfigurator-> Ereignisse“. Ich rufe das Ereignis FindStandardMatch ohne Attribute auf. Jetzt müssen Sie die Reaktion auf dieses Ereignis konfigurieren. Dazu gehe ich zum Abschnitt "Konfigurator-> Cloud-Code" des Cloud-Codes. Ich schreibe den folgenden Handler für FindStandardMatch im Abschnitt "Ereignisse":
var matchRequest = new SparkRequests.MatchmakingRequest(); matchRequest.matchShortCode = "StandardMatch"; matchRequest.skill = 0; matchRequest.Execute();
Dieser Code registriert einen Spieler in StandardMatch mit einem MMR von 0, sodass alle Spieler, die für die Suche nach einem Standardspiel registriert sind, zum Erstellen einer Spielsitzung geeignet sind. Bei der Auswahl eines Bewertungsspiels kann auf die privaten Daten des Spielerprofils zurückgegriffen werden, um die MMR dieser Art von Spiel zu erhalten.
Wenn genügend Spieler vorhanden sind, um eine Spielsitzung zu starten, sendet GameSparks eine MatchFoundMessage-Nachricht an alle ausgewählten Spieler. Hier können Sie automatisch eine Spielsitzung erstellen und Spieler hinzufügen. Fügen Sie dazu unter „User Messages-> MatchFoundMessage“ den folgenden Code hinzu:
var matchData = Spark.getData(); if (Spark.getPlayer().getPlayerId() != matchData.participants[0].id) { Spark.exit(); } var challengeCode = ""; var accessType = "PRIVATE"; switch (matchData.matchShortCode) { case "StandardMatch": challengeCode = "StandardChallenge"; break; default: Spark.exit(); } var createChallengeRequest = new SparkRequests.CreateChallengeRequest(); createChallengeRequest.challengeShortCode = challengeCode; createChallengeRequest.accessType = accessType; var tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); createChallengeRequest.endTime = tomorrow.toISOString(); createChallengeRequest.usersToChallenge = []; var participants = matchData.participants; var numberOfPlayers = participants.length; for (var i = 1; i < numberOfPlayers; i++) { createChallengeRequest.usersToChallenge.push(participants[i].id) } createChallengeRequest.Send();
Der Code überprüft zunächst, ob es sich um den ersten Spieler auf der Teilnehmerliste handelt. Als nächstes wird im Namen des ersten Spielers eine Instanz von StandardChallenge erstellt und die verbleibenden Spieler werden eingeladen. Eingeladene Spieler erhalten eine ChallengeIssuedMessage-Nachricht. Hier können Sie sich ein Verhalten vorstellen, wenn eine Einladung zur Teilnahme am Spiel auf dem Client angezeigt wird und eine Bestätigung durch Senden von AcceptChallengeRequest erfordert, oder Sie können die Einladung im stillen Modus annehmen. Also werde ich es tun. Dazu füge ich unter "User Messages-> ChallengeIssuedMessage" den folgenden Code hinzu:
var challangeData = Spark.getData(); var acceptChallengeRequest = new SparkRequests.AcceptChallengeRequest(); acceptChallengeRequest.challengeInstanceId = challangeData.challenge.challengeId; acceptChallengeRequest.message = "Joining"; acceptChallengeRequest.SendAs(Spark.getPlayer().getPlayerId());
Im nächsten Schritt sendet GameSparks das ChallengeStartedMessage-Ereignis. Der globale Handler dieses Ereignisses ("Globale Nachrichten-> ChallengeStartedMessage") ist ein idealer Ort zum Initialisieren einer Spielsitzung. Ich werde mich bei der Implementierung der Spielelogik darum kümmern.
Es ist Zeit für die Client-Anwendung. Änderungen im Client-Modul:
exports.GameClientStates = { IDLE: "Idle", MATCHMAKING: "Matchmaking", CHALLENGE: "Challenge" } exports.GameClient = function () { this.state = exports.GameClientStates.IDLE; this.challenge = undefined; function onMessage(message) { switch (message["@class"]) { case ".MatchNotFoundMessage": this.state = exports.GameClientStates.IDLE; break; case ".ChallengeStartedMessage": this.state = exports.GameClientStates.CHALLENGE; this.challenge = message.challenge; break; default: console.log("GAME onMessage: " + JSON.stringify(message)); } } onMessage = onMessage.bind(this); this.findStandardMatch = function () { var eventData = { eventKey: "FindStandardMatch" } return new Promise(resolve => { sendRequest("LogEventRequest", eventData) .then(response => { if (!response.error) { this.state = exports.GameClientStates.MATCHMAKING; resolve(); } else { console.error(response.error); reject(new Error(response)); } }) .catch(error => { console.error(error); reject(new Error(error)); }); }); } }
In Übereinstimmung mit dem Test wurden einige Felder auf dem Client-Status und der Herausforderung angezeigt. Die onMessage-Methode hat ein aussagekräftiges Aussehen erhalten und antwortet nun auf Nachrichten zum Start einer Spielsitzung und auf die Nachricht, dass es nicht möglich war, ein Spiel aufzunehmen. Die findStandardMatch-Methode wurde ebenfalls hinzugefügt, die die entsprechende Anforderung an das Backend sendet. Der Test ist grün, aber ich bin zufrieden, die Auswahl der Spiele gemeistert.
Was weiter?
In den folgenden Artikeln werde ich den Prozess der Entwicklung der Spielelogik beschreiben, von der Initialisierung einer Spielsitzung bis zur Verarbeitung von Zügen. Ich werde die Funktionen zum Speichern verschiedener Datentypen analysieren - eine Beschreibung der Metadaten des Spiels, Eigenschaften der Spielwelt, Daten aus Spielsitzungen und Daten über Spieler. Die Spielelogik wird durch zwei Arten von Tests entwickelt - Einheit und Integration.
Ich werde die Quellen auf Github in Teilen
hochladen, die an Artikel gebunden sind.
Es besteht das Verständnis, dass Sie unser Team von Enthusiasten erweitern müssen, um bei der Erstellung eines Spiels effektiv voranzukommen. Der Künstler / Designer wird bald beitreten. Und der Guru in Unity3D, der die Front für mobile Plattformen bilden wird, bleibt abzuwarten.