Schreiben einer rundenbasierten PvP-Arena mit gleichzeitigen Bewegungen

In diesem Artikel werde ich darüber sprechen, was zur Entwicklung des Spiels in einem so ungewöhnlichen Genre geführt hat, was für ein Genre es war, wie die Entwicklung fortgeschritten ist, auf welche Schwierigkeiten wir gestoßen sind und wie weniger als ein Jahr Arbeit am Abend es uns gelungen ist, einen vollständig spielbaren Prototyp zu erstellen.



Im Frühjahr 2017 stieß ich auf einen Atlas Reactor- Anreiz . Das Spiel war eine Art wilde Mischung aus Schach, Poker und Mobs, und eine so ungewöhnliche Kombination von Genres ist mir wirklich aufgefallen. Sie wurde mein Lieblingsspiel, ich nahm an Online-Turnieren und Events teil und alles würde gut werden, aber ...

Im Sommer 2019 waren die Server geschlossen, weil Aufgrund der geringen Beliebtheit des Spiels war ihre Unterstützung für den Publisher unrentabel. Das Spiel wurde nach dem Vorbild von Game-as-a-Service entwickelt. Durch das Herunterfahren der Server wurden die Clients zu fehlerhaften Codeteilen.

Aufgrund der einzigartigen Kombination von Genres ähnlicher Spiele gab es einfach keine Spiele auf dem Markt, aber ich wollte wirklich so etwas spielen.

Kurz nach dem Schließen stieß ich auf einen Beitrag auf dem reddit, dass eine Gruppe von Enthusiasten unter ehemaligen Spielern beschlossen hatte, einen privaten Server zu erstellen und den Client-Code anzupassen, um damit zu arbeiten, aber ich hatte keinen besonderen Wunsch, mich ihnen anzuschließen. Ich habe mich nie für Reverse Engineering interessiert, und außerdem sieht eine solche Aktivität nicht allzu legal aus.

Am Ende beschloss ich, Leute zu sammeln und die Arbeit am „spirituellen Erben“ zu organisieren - um ein Spiel mit ähnlichen Mechanismen, aber neuen Charakteren, Fähigkeiten, Karten und HNO zu machen. Abends und am Wochenende haben wir angefangen, an purer Begeisterung zu arbeiten. Wir wollten etwas Eigenes in das Genre bringen, Variabilität und Tiefe hinzufügen und die Fehler des Originals korrigieren. Von Anfang an war klar, dass das Spiel nicht sehr beliebt werden würde, aber ich war mir sicher, dass mindestens mehrere tausend Menschen daran interessiert sein könnten. Zumindest - Fans des geschlossenen Atlasreaktors.

Spielweise


Im Allgemeinen erinnert die Aktion an das Multiplayer-XCOM, jedoch mit einer 100% igen Chance auf Treffer und Helden (wie im MOBA-Genre).

Die Idee des Spiels ist, dass alle Ergebnisse vollständig durch die festgelegten Aktionen der Spieler bestimmt werden. Die Zufälligkeit fehlt vollständig und die Variation ist gering genug, so dass erfahrene Spieler alle wahrscheinlichen Ergebnisse berechnen und auf der Grundlage dieser Informationen handeln können. Um die Variabilität zu verringern, wird ein flaches Spielfeld verwendet, das in Zellen unterteilt ist. Das heißt, Helden können nur in der Mitte der Zellen stehen (obwohl die Fähigkeiten normalerweise überall angewendet werden, ohne auf das Gitter Bezug zu nehmen).

Normalerweise nehmen 8 Personen an einem Match teil. Sie sind in 2 Teams zu je 4 Personen aufgeteilt und steuern jeweils einen Charakter. Aufgrund der schrittweisen Vorgehensweise hindert jedoch nichts daran, einen Modus zu erstellen, an dem nur zwei Personen teilnehmen und jeder alle vier Charaktere seines Teams kontrolliert.

Das Spiel ist in Züge unterteilt. Jeder Schritt ist in zwei Phasen unterteilt - Entscheidung (Entscheidungsfindung) und Lösung(Anzeige der Ergebnisse der ausgewählten Aktionen). Die Dynamik wird durch die Tatsache ergänzt, dass beide Phasen für beide Teams gleichzeitig stattfinden (diese Art von Schritt für Schritt wird als We-Go bezeichnet) - es gibt nichts, was ein Team denkt, und das zweite wartet nur und schaut auf den Bildschirm, auf dem nichts passiert. Stattdessen treffen beide Teams Entscheidungen und beobachten gleichzeitig die Ergebnisse. Die Gleichzeitigkeit der Bewegungen und das Vorhandensein des Sichtfelds der Charaktere führt dazu, dass das Spiel nicht auf Spiele mit vollständigen Informationen zurückgeführt werden kann .

Entscheidung- eine Phase, in der die Spieler sofort die Möglichkeit haben, ihre gewünschten Aktionen auszuwählen. Das Spielfeld „friert“ für einige zehn Sekunden ein und die Spieler müssen auswählen, welche spezifischen Aktionen die von ihnen kontrollierten Charaktere ausführen sollen, wenn der „Zeitstopp“ vorbei ist. Jeder Spieler sieht, welche Aktionen seine Verbündeten ausführen werden, aber die von den Gegnern gewählten Aktionen sind verborgen.

Auflösung - Die Phase, in der ausgewählte Aktionen ausgeführt werden. Mit der Zeit dauert es ungefähr das Gleiche wie bei der Entscheidung oder etwas weniger. Währenddessen haben die Spieler keine Kontrolle - sie beobachten einfach, was passiert und überlegen sich die Aktionen für den nächsten Zug.

Die Auflösung ist in Phasen unterteilt. Die Phasen verlaufen nacheinander und für jede Fähigkeit wissen die Spieler im Voraus, in welcher Phase sie funktionieren wird. Darüber hinaus spielt die Reihenfolge der Funktionsweise der Fähigkeiten innerhalb einer Phase keine Rolle.



In der Regel wird Schaden in der Explosionsphase verursacht, sodass die Verteidigungsfähigkeiten früher ausgelöst werden. Sie können entweder in der Vorbereitungsphase Schilde anbringen oder sich in der Dash-Phase bewegen (ausweichen). Beim Ausweichen kann der Feind jedoch Schaden erleiden, wenn er eine Falle passiert (vom Spieler in der Vorbereitungsphase festgelegt). Wenn der Feind nicht ausweicht, sondern einfach an Ort und Stelle bleibt, funktioniert die Falle nicht und verursacht ihm keinen Schaden. Das Gleiche gilt für Schilde: Wenn Sie einen geschützten Charakter nicht angreifen, brennen sie am Ende des Zuges einfach, ohne dass dies Auswirkungen hat. Das Interesse hierbei ist, dass, wie oben erwähnt, die Handlungen der Gegner zum Zeitpunkt der Entscheidungsfindung verborgen sind und daher vorausgesehen werden müssen.

Der typische Schadenswert überschreitet nicht 35, um es den Spielern zu erleichtern, in ihren Gedanken zu zählen. Statuseffekte und Fähigkeiten sind aus demselben Grund gering genug. Der Hauptspielmodus ist das übliche Deathmatch, das bis zu 5 Kills oder 20 Züge umfasst.

Implementierung


Ich habe mich entschieden, in C # zu schreiben (da dies meine Hauptsprache ist), und ich habe Unity als Engine gewählt (da ich noch keine Erfahrung mit dem Erstellen von Spielen hatte, aber C # nativ unterstützt und für Anfänger recht freundlich ist).

Rundenbasierte Spiele erfordern keine großen Ressourcen, daher habe ich von Anfang an die kostengünstigsten Optionen für das Hosting des Hauptservers in Betracht gezogen. Es gab eine Idee, auf Heroku zu hosten (weil es im Allgemeinen kostenlos ist), aber ein Neustart der Anwendung mindestens einmal am Tag zu einer zufälligen Zeit ist äußerst unpraktisch. Er hielt bei VPS mit Linux für 45 Rubel pro Monat an.

Angesichts der begrenzten Ressourcen auf dem Hosting (insbesondere - sehr wenig Speicherplatz auf der Festplatte) und der Tatsache, dass die gesamte Spielelogik in 2D funktioniert, habe ich mich für .NET Core entschieden (indem ich meine leichte 2D-Engine geschrieben habe, um die von Fähigkeiten betroffenen Bereiche zu berechnen) und Unity verwendet rein zur clientseitigen Visualisierung. Dies ermöglichte es, das Sichtfeld der Zeichen auf der Serverseite einfach zu steuern und den Clients nur die Informationen zu senden, über die sie Bescheid wissen sollten. Die ausgewählten Aktionen der Spieler vor der Verarbeitung auf dem Server werden überprüft, wodurch die Möglichkeit des Betrugs vollständig ausgeschlossen wird.

Zur Vereinfachung für die Spieler wurde es von einem einfachen Launcher für WinForms abgesägt, der bei Bedarf die aktualisierte Version des Clients von Dropbox herunterlädt.

Jetzt werde ich detaillierter auf die interessantesten (oder schwierigsten) Momente eingehen, die wir bei der Entwicklung des Spiels erlebt haben.

Das Verfahren zur Verwendung von Fähigkeiten


Wie oben erwähnt, sollte das erzielte Ergebnis nicht von der Reihenfolge der Anwendung der Fähigkeiten innerhalb der Phase abhängen. Auf dem Server werden Fähigkeiten in aufsteigender Reihenfolge der Helden-ID verwendet, aber der Spieler sollte nicht darüber nachdenken. Diese Bedingung schränkt ein, was und in welchen Phasen auftreten kann (Spieleentwickler sind gezwungen, dies bei der Erstellung von Fähigkeiten zu berücksichtigen).

Wenn Sie beispielsweise in der Vorbereitungsphase Schilde anwenden können, können Sie keinen Schaden anrichten (andernfalls hängt dies von der ID ab, der Schaden geht auf die Schilde oder direkt auf die Gesundheit über, bevor sie angewendet werden). Da Schaden in der Explosionsphase verursacht werden kann, darf der Statuseffekt „Mächtig“ nicht angewendet werden, wodurch der vom Helden verursachte Schaden erhöht wird. Ähnliche Regeln wurden für alle Spielelemente angezeigt.

Einfache Spielelogik


Die Idee des Spiels ist, dass die Spieler in der Lage sind, die gesamte Entwicklung der Ereignisse innerhalb des Kurses in ihrem Kopf zu berechnen. Daher sollte die Logik aller Spielelemente einfach und intuitiv sein. Bei der Umsetzung des Plans traten jedoch viele Schwierigkeiten auf.

Erstens die Bewegung . Helden können sich während der Dash- und Move-Phase bewegen, und diese Bewegung muss gleichzeitig erfolgen. Zwei Helden dürfen sich in derselben Zelle befinden, während sie sich bewegen, aber am Ende der Bewegungsphasen sollte nicht mehr als ein Charakter in jeder Zelle verbleiben.

Die einfachste Regel zur Lösung von Konflikten am Ende der Bewegung lautet: "Wer zuerst aufgestanden ist, das und Hausschuhe." Wenn der Held einen langen Weg zurückgelegt hat, bevor er sich in einer „umstrittenen“ Zelle befindet, sollte er zurückgedrängt werden, und derjenige, der einen kleineren Weg zurückgelegt hat, sollte an Ort und Stelle bleiben. Wenn die Helden ihr Ziel erreicht haben und dieselbe Strecke zurückgelegt haben, schieben Sie sie beide. Aufgrund seines Determinismus wurde beschlossen, die Helden auf den Bahnen ihrer Bewegung zurückzudrängen. Die Abstoßung wird wiederholt, bis alle Konflikte gelöst sind.

Das zweite Problem ist die Äquivalenz . Angenommen, wir möchten ein Profil erstellen, das, wenn es einen Feind trifft, ihm Schaden zufügt und automatisch auf den nächsten abpralltfür ihn ein Charakter. Das Problem hierbei ist eine Kombination aus "automatisch" und "am nächsten". Helden befinden sich auf einem karierten Feld, was bedeutet, dass sich neben dem primären Ziel in derselben Mindestentfernung mehrere Zeichen befinden können.

Was ist zu tun?
  • id
Tatsächlich besteht die Lösung darin, dass wir mehr Daten haben - die Position, von der aus der Schuss abgefeuert wurde. Wenn Sie kein nächstgelegenes Ziel für den Abprall auswählen können, können Sie die Helden im Uhrzeigersinn sortieren, wobei das Hauptziel das Zentrum ist und der Held, der die Fähigkeit angewendet hat, die Startposition ist.

Ehrliche Geometrie


Wie sich herausstellte, ist es nicht interessant, mit ehrlicher Geometrie zu spielen. Die Wände sind für die meisten Schüsse undurchlässig und blockieren das Sichtfeld der Gegner. Außerdem dienen sie als Schutz (und wenn der Schaden von der Seite des Schutzes ausgeht, wird er um 50% verringert). Die Wände schränken jedoch den betroffenen Bereich für den Helden selbst extrem ein, und aus diesem Grund sahen die Spieler keinen Grund, sie zu verwenden.

Malzeiten

— , — . ( ) — . , 90 .

Es wurde beschlossen, den Sichtbereich nicht nur zwischen den Zentren, sondern auch zwischen bestimmten Punkten zu überprüfen.

Malen Sie zwei


Die Verwendung von zusätzlichen vier Punkten entlang der Ränder des Helden reduzierte die "tote Zone" auf 60 Grad (was bereits ziemlich spielbar geworden ist).

Infolgedessen wurden die Wände wirklich nützlich.

Malen Sie drei

, 50% ( , ).

Zusätzliche Punkte befinden sich genau in der Mitte zwischen der Mitte der Zelle und ihren Rändern, und diese Auswahl ist nicht zufällig. Bei rechteckigen Angriffen ist es sehr wichtig, von wo aus der Schuss abgefeuert wird (da dieser Punkt zur Berechnung von Rückprallen von Wänden, Explosionen und einigen anderen Angriffsmodifikatoren verwendet wird). Ein einfacher Algorithmus ermöglichte es, den Startpunkt innerhalb des Helden abhängig von der Position der Maus automatisch zu verschieben. In diesem Fall befindet sich der Punkt so, dass die Reichweite des Schusses nahe der Wand maximiert wird.

Hier ist ein Link zum GIF (20 MB) , wo Sie sehen können, wie die automatische Verschiebung des Aufnahmepunkts funktioniert.

Lokalisierung


Um die Lokalisierung hinzuzufügen, habe ich string.Format (damit ausgewogene Änderungen der Schadenszahlen keine neuen Linien erzeugen) und eine Google-Platte verwendet. Alle Zeichenfolgen, die zur Anzeige auf dem Bildschirm verwendet werden, werden in eine Methode eingeschlossen, die aus bekannten Übersetzungen interpoliert und mit dem Wörterbuch vergleicht. Zu Beginn der Debütversion des Spiels werden Übersetzungen von der Google-Platte in eine Textdatei im JSON-Format geladen, und die Zeilen aus dem Quellcode ohne Übersetzungen werden beim ersten Versuch, auf dem Bildschirm angezeigt zu werden, automatisch auf dieselbe Google-Platte heruntergeladen. In der Release-Version des Spiels gibt es aus offensichtlichen Gründen keine Online-Funktionalität für die Arbeit mit der Tabelle, und Übersetzungen werden beim Start einfach aus der vorhandenen Textdatei geladen.

Für Übersetzer war die Lösung nicht sehr praktisch (da das Ändern eines Wortes zur Erstellung einer neuen Zeile in der Tabelle führt), aber sie war sehr einfach zu implementieren und belastete die Programmierer nicht mit der Arbeit mit Ressourcen. Es wäre ideal, wenn sich die Linien während des Entwicklungsprozesses nicht ändern würden, aber dies war bei uns nicht der Fall.

Rechen


Nun - das interessanteste. Einige offensichtliche Tipps, die unerfahrenen Programmierern helfen können, die sich entscheiden, ihr Lieblingsprojekt in einem Team von Gleichgesinnten zu schneiden.

  • Wenn möglich, das Rad nicht neu erfinden.
    Wenn das Problem weit verbreitet ist, sollte es viele vorgefertigte Lösungen dafür geben. Das Finden einer geeigneten vorgefertigten Lösung kann weniger Zeit in Anspruch nehmen, als sie selbst von Grund auf neu zu schreiben (insbesondere wenn das Problem komplex ist).
    . , . , , . NetworkStream-, TcpClient- Json. , , . 30 ( MagicOnion, )

  • — , . — . . — . — .

  • — , . - summary readme. .
  • ,
    . . — , — , , .
  • Git — ,
    , . .
  • ,
    . .
  • ,
    . , , , , . , , , .


Es stellte sich heraus, dass in weniger als einem Jahr ein spielbarer Prototyp erstellt wurde. Ein Teil der aktiven Community hat sich an der Entwicklung oder dem Testen beteiligt, sodass jetzt fast täglich mindestens ein paar Spiele stattfinden. Es ist wirklich cool zu sehen, wie die Leute das Spiel genießen, an dessen Erstellung ich aktiv teilnehme.

Persönlich habe ich während der Arbeit an dem Projekt gesprochenes Englisch gepumpt (da die Community international ist) und Erfahrungen mit Linux, Programmierung und Verwendung von Unity gesammelt. Haustierprojekte sind cool.

Mit der Zeit werden wir definitiv Schulungen für neue Spieler, normale Modelle und Animationen, ein angemessenes Menü und eine bequemere Benutzeroberfläche als Ganzes hinzufügen. Da gute 3D-Modelle sehr teuer sind, haben sie ein Konto bei Patreon erstellt und die Community hat begonnen, uns finanziell zu unterstützen.

Links für Interessenten
Discord-. .

, , - — , Atlas Reactor

All Articles