Games

Die Game Kitchen über 3 technische Herausforderungen bei der Entwicklung von The Stone of Madness

/ THE GAME KITCHENGuest Blog
Mar 6, 2025|11 Min.
Key-Art von The Stone of Madness von The Game Kitchen | Made mit Unity
Diese Website wurde aus praktischen Gründen für Sie maschinell übersetzt. Die Richtigkeit und Zuverlässigkeit des übersetzten Inhalts kann von uns nicht gewährleistet werden. Sollten Sie Zweifel an der Richtigkeit des übersetzten Inhalts haben, schauen Sie sich bitte die offizielle englische Version der Website an.

Anfang dieses Jahres hat The Game Kitchen The Stone of Madness veröffentlicht, ein taktisches RPG, in dem die Spieler fünf Insassen helfen, aus einem inquisitorischen Gefängnis zu entkommen. In diesem Gastbeitrag teilen drei Entwickler aus dem Studio, wie sie die Herausforderungen bei Rendering, Benutzeroberfläche und Tests während der Entwicklung angegangen sind.

Wir sind The Game Kitchen und haben kürzlich The Stone of Madness für PC und Konsolen veröffentlicht. Wir möchten einige der drängendsten Herausforderungen teilen, mit denen wir während der Entwicklung unseres neuesten Projekts konfrontiert waren, und sie aus einer technischen Perspektive mit praktischen Beispielen angehen. In diesem kollaborativen Artikel erläutert unser Programmierteam wichtige Lösungen, die wir in Unity implementiert haben, um sowohl die Leistung als auch die Entwicklungseffizienz zu optimieren.

Zuerst wird Adrián de la Torre (Grafikprogrammierer) erklären, wie wir die Kunstpipeline des Spiels entworfen und gerendert haben, um seinen unverwechselbaren visuellen Stil zu erreichen.

Als Nächstes wird Alberto Martín (UI-Programmierer) erläutern, wie wir Noesis genutzt haben, um die UI-Entwicklung zu optimieren und den Workflow mit UX-Verbesserungen basierend auf dem Feedback der Benutzer zu verbessern.

Schließlich wird Raúl Martón (Gameplay-Programmierer) zeigen, wie wir Tests für komplexe In-Game-Aktionen auf einem Server externalisiert und automatisiert haben, um sicherzustellen, dass mehrere Randfälle behandelt wurden, ohne die Integration zu stören.

Wahnsinn gut aussehen lassen: Ein Blick auf die benutzerdefinierte Render-Pipeline

Adrián de la Torre, Grafikprogrammierer, The Game Kitchen
Der Stein des Wahnsinns kombiniert 2D-Visuals mit 3D-Gameplay-Mechaniken, was eine einzigartige technische Herausforderung darstellt. Während die Spieler eine 2D-Welt sehen, arbeiten die zugrunde liegenden Systeme des Spiels im dreidimensionalen Raum und schaffen eine ausgeprägte Dualität in seinem Design.

Um diese Herausforderung zu bewältigen, hat unser Entwicklungsteam eine benutzerdefinierte Rendering-Pipeline erstellt, die effektiv die Lücke zwischen 3D-Spielinformationen und 2D-Visualisierungen überbrückt. Diese Lösung implementiert mehrere Rendering-Pässe und spezialisierte Techniken, um die visuelle Konsistenz aufrechtzuerhalten und gleichzeitig die beabsichtigte Spieltiefe zu bewahren, was eine nahtlose Übersetzung von 3D-Elementen in den charakteristischen 2D-Kunststil des Spiels ermöglicht.

In Der Stein des Wahnsinns gibt es zwei Hauptszenarien, die zur Darstellung eines Rahmens beitragen.

Das erste Szenario, das wir das Proxy-Szenario nennen, besteht aus geometrischen Primitiven, die die Beleuchtung des finalen Frames berechnen.

Ansicht der zugrunde liegenden 3D-Szene in The Stone of Madness von The Game Kitchen – Hergestellt mit Unity
Ansicht der zugrunde liegenden 3D-Szene (Proxy-Szenario)

Das zweite Szenario ist das Canvas-Szenario, das aus Sprites besteht, die der Form und Position der Proxy-Geometrie entsprechen. Die Leinwand ist in Schichten angeordnet, um den 3D-Raum zu simulieren und eine ordnungsgemäße Z-Sortierung mit sich bewegenden Spielelementen zu erreichen.

Der folgende Abschnitt beschreibt jeden Schritt in unserer Grafikpipeline für die Frame-Rendering.

1. Sichtfeld

Immer wenn ein Sichtkegel oder eine Spielfähigkeit aktiviert wird, initiiert dies den ersten Schritt in der Pipeline. Wir positionieren eine Kamera aus der Sichtweise (PoV) des NPC, um die Tiefe der Proxys innerhalb seines Sichtfelds (FoV) darzustellen.

Tiefentextur, die von der Kamera erzeugt wird, die sich am Standpunkt des NPCs befindet.
Tiefentextur, die von der Kamera erzeugt wird, die sich am Standpunkt des NPCs befindet.

Dann gibt die Kamera in einer anderen Render-Textur einen Farbverlauf der Entfernung vom Ursprung des Spielers im B-Kanal aus, der für Fähigkeitenbereichseffekte verwendet wird.

Gradienttextur, die von einer Kamera erzeugt wird, die sich im Blickwinkel des Spielers befindet
Gradienttextur, die von einer Kamera erzeugt wird, die sich im Blickwinkel des Spielers befindet

Mit der Render-Textur der Perspektive des NPCs rendert die Kegel-der-Sicht-Kamera einen Kegel über die vorherige Textur in den R- und G-Kanälen mit Informationen über Hindernisse und Entfernung.

Kegel des Blicks überlagert auf der Gradientenstruktur
Kegel des Blicks überlagert auf der Gradientenstruktur

Der letzte Durchgang rendert Schallwellen im Alpha-Kanal.

Schallwellen, die im Alphakanal der Gradientenstruktur überlagert sind
Schallwellen, die im Alphakanal der Gradientenstruktur überlagert sind

Dies ist die endgültige Textur, die in diesem Schritt erstellt wurde und im Schritt "Canvas Camera" verwendet wird, um die Sprites der Szene zu rendern.

Endgültige Textur, die verwendet wird, um die Reichweite und Sichtkegel der Fähigkeiten darzustellen.
Endgültige Textur, die verwendet wird, um die Reichweite und Sichtkegel der Fähigkeiten darzustellen.

2. Leinwand Render-ID Kamera

Jeder Proxy in unserem Projekt hat eine zugeordnete Render-ID (ein Float-Wert). Der Proxy und sein zugehöriger Sprite teilen sich die gleiche Render-ID. In diesem Schritt rendern wir den Render-ID-Floatwert in eine Rendertextur.

ID-Textur rendern. Jede Farbe repräsentiert eine einzigartige Render-ID, die zwischen einem Proxy und seinem entsprechenden Sprite geteilt wird.
ID-Textur rendern. Jede Farbe repräsentiert eine einzigartige Render-ID, die zwischen einem Proxy und seinem entsprechenden Sprite geteilt wird.

Im nächsten Schritt verwenden wir diese Textur, um die Lichtinformationen, die im Proxy-Szenario berechnet wurden, mit den Sprites im Canvas-Szenario abzugleichen.

3. Bele

Die Beleuchtung in unserem Spiel besteht aus:

  • Gebackenes Licht Natürliche Lichter, die dauerhaft aktiv bleiben, wie Außenbeleuchtung
  • Gemischte Beleuchtung Statische Lichter in der Szene, die ein- und ausgeschaltet werden können, wie Kerzen.
  • Echtzeitbeleuchtung: Licht, das sich durch die Szene bewegt und ein- und ausgeschaltet werden kann (wir haben dies nur in einem Fall implementiert, Alfredos Öllampe)

Mit der RenderID-Textur erstellen wir eine Render-Textur, die die Beleuchtungsinformationen aus der Proxy-Szene enthält.

Schattentextur, die aus der Render-ID-Textur und Lichtberechnungen erzeugt wurde
Schattentextur, die aus der Render-ID-Textur und Lichtberechnungen erzeugt wurde

4. Leinwandkamera

Nachdem alle Render-Texturen erstellt wurden, beginnt eine Kamera, die Sprites mit Informationen über Beleuchtung, Wirkungsbereiche von Fähigkeiten, Sichtkegel und Geräuschwellen zu rendern.

5. Nachbearbeitung

Farbkorrektur, Vignettierung und andere Effekte werden in einem Nachbearbeitungsdurchgang angewendet.

6. UI

Schließlich ist die Benutzeroberfläche überlagert.

Wahnsinn im HUD: Benutzeroberflächenprozesse beschleunigen

Alberto Martín, UI Programmer, The Game Kitchen

Die endgültige Veröffentlichungsversion von The Stone of Madness verfügt über mehr als 50 Benutzeroberflächen. Der Grund für diese Zahl ist, dass dieses Spiel viele Daten hat, um dem Benutzer zu zeigen. Unsere UI-Arbeit war sehr zeitaufwendig, insbesondere da das Team zu Beginn so klein war, und daher haben wir kontinuierlich unsere Prozesse optimiert, um sicherzustellen, dass wir in möglichst kurzer Zeit gute Ergebnisse erzielen.

Unsere UI-Arbeit umfasste das gesamte Projekt, daher war es wichtig, dass unsere UI/UX-Designer alle Funktionen, die wir implementieren mussten, klar verstanden. Um sicherzustellen, dass unser Spiel eine gute Benutzererfahrung bot und Spaß machte, waren wir darauf bedacht, eine offene Kommunikationslinie zwischen den Programmier- und Designteams aufrechtzuerhalten.

Um die besten Versionen aller unserer UI-Komponenten zu erstellen, mussten wir die Silos zwischen unseren technischen Teams und unseren kreativen/forschenden Teams abbauen, damit jeder aktiv an der Entwicklung des Spiels beteiligt war. So haben wir diesen zweigeteilten Arbeitsablauf angegangen.

Die Rolle von Forschung und Kreativität im UI-Design

Unsere UI/UX-Designer sind dafür verantwortlich, wie die UI-Elemente im endgültigen Spiel aussehen werden, und dafür zu sorgen, dass wir ein zufriedenstellendes Benutzererlebnis bieten. In Anbetracht dessen begannen sie damit, jedes Element mit minimaler technischer Belastung zu erstellen und es mit potenziellen Nutzern zu validieren. Dieser Prozess sah so aus:

  1. Voraussetzungen: Die Bedürfnisse der Spieler zu verstehen und eine Liste der Bedürfnisse des Spiels sowie der Benutzerziele zu erstellen.
  2. Untersuchung Andere Spiele betrachten, um zu sehen, wie sie ähnliche Probleme gelöst haben.
  3. Drahtgitter Arbeiten an den Schaltplänen und der Struktur (noch keine endgültige Kunst zu diesem Zeitpunkt)
  4. Mock-up An diesem Punkt montieren wir die fast vollständig gestaltete Benutzeroberfläche mit zuvor erstellten Elementen (Schaltflächen, Scrollleisten, Rahmen usw.), was es uns ermöglicht, ohne großen Aufwand zu iterieren.
  5. Prototyp Wir erstellen einen Prototypen in Figma mit unserem Mock-up, simulieren Interaktionen mit Gamepads und Tastatur/Maus, um zu zeigen, wie es in einer realen Umgebung funktionieren wird.
  6. Benutzertest: Mit unserem zuvor erstellten Prototyp führen wir einen Benutzertest durch, um die Bedürfnisse und Ziele zu validieren, die wir in Schritt 1 identifiziert haben.
  7. Iterationsphase Wenn der Benutzertest den Erwartungen entspricht, wird er an technische Teilprozesse weitergegeben, es werden weitere Iterationen durchgeführt oder zusätzliche Tests durchgeführt, wenn es sinnvoll ist.

Technische UI-Implementierung

Wie bereits erwähnt, ist die Anzahl der UI-Elemente in The Stone of Madness riesig. Die Entwicklung einer UI-Engine ist teuer, daher mussten wir ein Framework verwenden, das leicht zu erlernen ist und anständige Werkzeuge und Arbeitsabläufe bietet. Nach der Bewertung einer Reihe von Middleware wählen wir Noesis GUI, das dem Model-View-ViewModel (MVVM)-Muster folgt.

Wir haben Noesis gewählt, weil es auf WPF (Windows Presentation Framework) basiert und das MVVM-Modell in einer Weise folgt, dass wir die meisten Dokumentationen, Bibliographien, Foreneinträge usw. wiederverwenden können, um die Mehrheit der Probleme zu beheben. Dieses Framework gibt es schon eine Weile – es ist jetzt 18 Jahre her, seit seiner ersten Veröffentlichung – und es ist vielen UI-Entwicklern vertraut, was unserem Studio die Möglichkeit gibt, aus einem vergleichsweise größeren Talentpool zu rekrutieren, um Schnittstellen und Werkzeuge für unsere Projekte zu implementieren. Eine weitere wichtige Sache über Noesis ist, dass wir die gleichen Werkzeuge wie in WPF verwenden können.

Mit XAML war unser kreatives UI-Team an der Layoutarbeit beteiligt und hat alle Elemente mit minimalem technischem Aufwand verfeinert. Dank des MVVM-Ansatzes konnten sich unsere technischen UI-Programmierer auf die Funktionalität konzentrieren und die kreativen Teams in bestimmten Bereichen bei Bedarf unterstützen.

Testen (oder wie man nicht verrückt wird, während man ein Spiel mit systemischem Design erstellt)

Raul Martón, Gameplay Programmer, Teku Studios

Das Gameplay in The Stone of Madness basiert auf drei grundlegenden Säulen: Spielerfähigkeiten, NPC-KI und Szeneninteraktionen. Jedes dieser drei Systeme ist grundlegend miteinander verbunden, was die Anzahl der Situationen, die der Spieler kontrollieren muss, exponentiell erhöht – und die Anzahl der Szenarien, die wir testen müssen.

Sobald wir das Projekt gestartet hatten, wurde uns klar, dass ein traditionelles QA-System unzureichend sein würde. Es gab einfach zu viele Szenarien, die davon abhingen, dass mehrere Teile auf eine bestimmte Weise miteinander interagierten, was zu einer unkontrollierten Situation führte. Darüber hinaus könnten diese Situationen durchaus in einem Zeitfenster auftreten, das einfach zu klein ist, damit ein QA-Team bequem testen kann.

Um diese Probleme zu lösen, haben wir eine Reihe automatischer Tests erstellt. Die Idee war, dass alle möglichen Szenarien/Situationen, die unserem Entwicklungsteam in Bezug auf ein bestimmtes System begegnen könnten, viel effizienter in einer simulierten Spielumgebung berücksichtigt und automatisch getestet werden könnten.

Um ein Beispiel zu geben, hat eine der Hauptfiguren von The Stone of Madness, Amelia Exposito, die Fähigkeit zu pickpocketen. Während der Implementierung dieser Fähigkeit haben wir eine Reihe von Tests initiiert, um sicherzustellen:

  • Die grundlegende Funktionsweise der Fähigkeit war korrekt: Beim Stehlen von einem NPC würde das Taschendiebstahl-Minispiel geöffnet und das Spiel würde pausiert, bis es vorbei ist.
  • Weniger häufige Situationen werden ebenfalls abgedeckt: Wenn du versuchst, von einem NPC zu stehlen, während ein anderer NPC (wie ein Wächter) dich beobachtet, oder wenn der NPC rennt, ist die Aktion unmöglich.
Automatisiertes Playtesting der Fähigkeit "Taschendiebstahl", um zu überprüfen, ob sie in verschiedenen Spielszenarien wie erwartet funktioniert.
Automatisiertes Playtesting der Fähigkeit "Taschendiebstahl", um zu überprüfen, ob sie in verschiedenen Spielszenarien wie erwartet funktioniert.

Erstellen eines Integrationstests

Jeder Integrationstest, den wir erstellt haben, erforderte eine Einrichtung basierend auf den folgenden Anforderungen:

1. Eine Szene, die speziell vorbereitet wurde, um diese besondere Situation zu schaffen.

Um die Taschendiebstahl-Fähigkeit zu testen, haben wir eine Szene mit zwei Wachen und einem Spieler erstellt. Wir haben jede Figur so positioniert, dass sie in die Richtung schaut, die für die Situation benötigt wird, um genau getestet zu werden (denken Sie daran, dass der Spieler nicht stehlen kann, wenn er sich im Sichtfeld eines Wächters befindet).

Zusätzlich sollte die Szene nur die minimalen Komponenten enthalten, die notwendig sind, um das Szenario zu testen, da überflüssige Elemente das Maß beeinflussen können. Deshalb hat unsere Beispielszene kein HUD, kein manuelles Eingabesystem, keine Soundeffekte usw.

  • Dieser Schritt erfordert, dass die Spielstruktur gut compartmentalisiert ist, was einige Mühe kosten kann, aber, einmal erreicht, ist es die Mühe wert! 😉

2. Ein Testcode, der in der Lage ist, die zu testende Situation zu erzwingen.

Viele der Situationen, die wir testen mussten, können schwierig und zeitaufwendig manuell zu erstellen sein und benötigen einen Code-Push, um initiiert zu werden.

Zum Beispiel, wenn wir ein Testszenario erstellen wollen, um sicherzustellen, dass unsere NPCs niemals auf Mausefallen treten, es sei denn, der NPC bewegt sich, wäre die Anweisungskette:

  1. Die Szene starten
  2. Warte eine Sekunde
  3. Platziere eine Mausefalle unter dem NPC
  4. Warte eine weitere Sekunde
  5. Befehle dem NPC, in jede Richtung zu gehen.

Dieser Teil des Projekts ist während der Entwicklung sehr empfindlich gegenüber Änderungen (abhängig von Faktoren wie sich ändernden Spiel-Spezifikationen und verschiedenen unerwarteten Szenarien). Daher ist es entscheidend, dass sowohl der Testcode als auch das daraus resultierende Feedback so klar wie möglich sind.

Es gibt nichts Schlimmeres als einen Test, der fehlschlägt, ohne klare Informationen darüber zu geben, was tatsächlich schiefgeht.

3. Eine zuverlässige Möglichkeit zu wissen, ob das Szenario wie beabsichtigt funktioniert oder ob der Test einen Fehler in der Logik erkannt hat.

Automatisiertes Testen erfordert weiterhin Aufsicht. Die zunehmende Anzahl von Tests mit größerer Spezifität darüber, was getestet wird, kann schwierig zu überwachen sein, oder Szenarien werden nicht lange genug getestet, um statistisch signifikant zu sein. Um diese Probleme zu umgehen, haben wir maßgeschneiderte Werkzeuge erstellt.

Zum Beispiel beinhalteten einige unserer Tests kombinierte Interaktionen zwischen mehreren NPCs in einer Szene. Um diese Fälle ordnungsgemäß zu überwachen, haben wir ein System erstellt, um die verschiedenen KI-Zustände zu protokollieren, durch die NPCs während des Tests wechseln.

Ein Wach-NPC folgt während eines automatisierten Tests nicht der erwarteten Verfolgungssequenz.
Ein Wach-NPC folgt während eines automatisierten Tests nicht der erwarteten Verfolgungssequenz.

Wir benötigten auch eine gute API, die uns Einblick in den aktuellen Spielzustand gibt (wurde ein NPC bewusstlos geschlagen?) Hat ein NPC einen gerouteten Zustand erreicht? Wie oft? Welcher Spielercharakter wurde gefangen genommen? Und so weiter).

4. Ein System, um all diese Tests schnell starten zu können:

Im Gegensatz zu Unit-Tests müssen automatisierte Tests durchgeführt werden, während das Spiel in Echtzeit läuft. Das kann das Ausführen dieser Tests sehr langsam machen.

Unter diesen Umständen sind wir in der Lage, den Vorteil zu nutzen, dass unser Spiel nicht das standardmäßige Updatesystem von Unity verwendet. Stattdessen verwenden alle unsere Komponenten eine Tick()-Funktion, die Unity-Updates simuliert, aber auf kontrollierte Weise von unserer Spiel-Engine gestartet wird.

Das hat uns geholfen, ein paar verschiedene Ziele mit unseren Tests zu erreichen:

  • Zuerst könnten wir ihre Ausführung mit einer Zwangsfunktion beschleunigen, die für jedes Frame des Spiels mehrere Code-Frames ausführt.
  • Zweitens, da diese Tests in Echtzeit durchgeführt werden, sind sie sehr anfällig für Variationen, die durch die Bildraten des Computers verursacht werden, der das Testszenario ausführt. Durch die Umwandlung in eine kontrollierte Bildrate vermeiden wir diese Varianz: Wenn ein Test auf einer Maschine besteht, besteht er auf allen Maschinen, und umgekehrt.

Und das wäre das Ergebnis.

Wie sicheres Testen uns hilft, fehlerhafte Builds zu vermeiden

Mit der Erstellung dieses Test-Suites mussten wir auch eine Sicherheitsmaßnahme implementieren, die den Merge eines Branches automatisch unterbricht, wenn er Fehler enthält. Um dies sicherzustellen, erstellen wir ein automatisches Zusammenführungs-Skript, das jedes Mal gestartet wird, wenn eine Änderung am Hauptprojektzweig vorgenommen wird.

Dieses Skript stellt sicher, dass alle diese Tests gestartet und ihre Ergebnisse überwacht werden. Wenn ein Test fehlschlägt, wird ein Fehler erkannt und der Merge wird unterbrochen.

Mit diesem System können wir Situationen vermeiden, in denen eine Änderung in einem scheinbar isolierten System andere Mechanismen, mit denen es interagiert, beeinträchtigt.

Danke an The Game Kitchen, dass sie diesen Blick hinter die Kulissen der Entwicklung von The Stone of Madness geteilt haben. Entdecken Sie weitere mit Unity erstellte Spiele auf unserer Steam-Kuratorseite und erhalten Sie weitere Einblicke von Entwicklern auf der Ressourcen-Seite von Unity.