
Game-over scherm van Ocarina of Time (1998).

De layout in UI Toolkit.

De GameOverManager class.

De method die het game-over proces uitvoert.

Code die het scherm zwart maakt.

De method die verantwoordelijk is voor het dichterbij bewegen van de camera.
Game-over scherm van World Eater
30-12-2024 - Lennon Stolk
In deze devlog beschrijf ik het ontwikkelproces van het game-over scherm voor World Eater. Dit scherm verschijnt wanneer spelers al hun levens verliezen door aanvallen van de boss of door omgevingsgevaren. Ik wilde er iets bijzonders van maken dat past bij de sfeer van het spel.
Ik heb wel de game-over tekst aan de bovenkant van het scherm geplaatst zodat de tekst niet over de animatie heengaat.
De animatie van de speler is gemaakt door Chris Schouten. De animatie laat zien dat de speler het opgeeft en neervalt. Deze wordt vanuit de GameOverManager class afgespeeld door middel van een animation controller en een finite state machine.
In dit onderdeel ga ik op een technische wijze in op het systeem dat ik hiervoor heb gemaakt.
Wanneer OnPlayerDeath geactiveerd is worden er een aantal stappen uitgevoerd waardoor de UI van het game-over scherm verschijnt, de speler het karakter ziet doodgaan en de achtergrond zwart wordt.
Ook worden alle mogelijke interacties tussen de speler en objecten in het spel uitgezet, en het speler karakter wordt op zijn huidige positie vastgezet.
Daarom heb ik twee methods gemaakt die ervoor zorgen dat er geen interacties meer zijn. Namelijk: FreezePlayer en DisableSceneObjects.
FreezePlayer zet de movementLocked variabele in de PlayerController class op true. In de PlayerController worden vervolgens de bewegingsfuncties beëindigt wanneer deze variabele true is. Ook wordt de cursor status veranderd, zodat de speler op de knoppen kan klikken en niet meer de camera kan bewegen.
DisableSceneObjects vindt alle objecten in de scene met bepaalde tags, zoals bijvoorbeeld stenen die de boss uitspuugt en de boss zelf. Deze objecten worden vervolgens uitgezet door middel van Unity's .SetActive().
Helaas is een volledig soepele animatie niet mogelijk omdat een culling mask bestaat uit booleans en niet floats of doubles. Want een float of double zou je kunnen interpoleren van 0 naar 1.
De nieuwe camera staat dicht bij het spelerkarakter, zodat de speler de animatie goed kan zien. Het plaatsen van deze camera is iets lastiger dan je zou verwachten, omdat dit spel zich afspeelt op planeten die ervoor zorgen dat de speler ondersteboven kan staan.
De soepele overgang tussen de twee camera's is gedaan door middel van een CinemachineBlendDefinition met de EaseInOut animatiecurve.
Deze geïntegreerde aanpak zorgt voor een coherente game-over ervaring die past binnen de spelwereld van World Eater.
Dit is het einde. Bedankt voor het lezen!
Doelen en vereisten
Het game-over scherm heeft twee hoofddoelen: de speler duidelijk maken dat het spel voorbij is en de mogelijkheid bieden om opnieuw te beginnen. De belangrijkste vereisten waren:- Een duidelijke keuze tussen opnieuw proberen of stoppen
- Een passende doodanimatie voor het spelerskarakter
- Stijlvolle presentatie die aansluit bij de rest van het spel
- Volledige deactivatie van speelbare elementen tijdens het game-over scherm
Interface
Inspiratie
De vormgeving is geïnspireerd door The Legend of Zelda: Ocarina of Time (3DS-versie), waar een zwart scherm verschijnt bij het overlijden van Link. Ik heb dit concept aangepast door de game-over tekst bovenaan te plaatsen om overlap met de doodanimatie te voorkomen.Ik heb wel de game-over tekst aan de bovenkant van het scherm geplaatst zodat de tekst niet over de animatie heengaat.
Layout
De interface is bewust minimalistisch gehouden en gebouwd met Unity's UI Toolkit. De structuur bestaat uit twee hoofdelementen binnen een positionerend VisualElement:- Top: bevat de game-over tekst
- Bottom: bevat de restart- en quit-knoppen
Animatie
De tekst heeft een subtiele fade-in, waardoor er een kleine vertraging is voordat de speler geconfronteerd wordt met de game-over tekst en knoppen. De knoppen hebben een animatie als je de muis er opzet en maken ook een simpel klikgeluidje.De animatie van de speler is gemaakt door Chris Schouten. De animatie laat zien dat de speler het opgeeft en neervalt. Deze wordt vanuit de GameOverManager class afgespeeld door middel van een animation controller en een finite state machine.
Systeem architectuur
Het was best wel een uitdaging om de animatie, de camera beweging en de overgang naar het zwarte scherm juist te krijgen.In dit onderdeel ga ik op een technische wijze in op het systeem dat ik hiervoor heb gemaakt.
GameOverManager
De GameOverManager class is de class die alles regelt omtrent het doodgaan van het spelerkarakter. Bij deze class kan de OnPlayerDeath() method worden aangeroepen vanuit een andere class, in dit geval PlayerHealthBar. Dit proces gebeurt wanneer de PlayerHealthBars isDead variabele op true staat.Wanneer OnPlayerDeath geactiveerd is worden er een aantal stappen uitgevoerd waardoor de UI van het game-over scherm verschijnt, de speler het karakter ziet doodgaan en de achtergrond zwart wordt.
Ook worden alle mogelijke interacties tussen de speler en objecten in het spel uitgezet, en het speler karakter wordt op zijn huidige positie vastgezet.
Uitzetten van interacties
Het is belangrijk dat alle mogelijke interacties van de speler of van het lopende spel uit worden gezet, zodat deze niet de immersie van het game-over scherm verbreken. Denk bijvoorbeeld aan de speler die uit het scherm zakt omdat het karakter in de lucht zat en naar beneden viel.Daarom heb ik twee methods gemaakt die ervoor zorgen dat er geen interacties meer zijn. Namelijk: FreezePlayer en DisableSceneObjects.
FreezePlayer zet de movementLocked variabele in de PlayerController class op true. In de PlayerController worden vervolgens de bewegingsfuncties beëindigt wanneer deze variabele true is. Ook wordt de cursor status veranderd, zodat de speler op de knoppen kan klikken en niet meer de camera kan bewegen.
DisableSceneObjects vindt alle objecten in de scene met bepaalde tags, zoals bijvoorbeeld stenen die de boss uitspuugt en de boss zelf. Deze objecten worden vervolgens uitgezet door middel van Unity's .SetActive().
Overgang naar zwarte achtergrond
De overgang naar het zwarte scherm gebeurt via de FadeToBlack() method, die het volgende uitvoert:- Aanpassing van de camera's SolidColor achtergrond
- Modificatie van de culling mask voor selectieve weergave
Helaas is een volledig soepele animatie niet mogelijk omdat een culling mask bestaat uit booleans en niet floats of doubles. Want een float of double zou je kunnen interpoleren van 0 naar 1.
Beweging van camera
De beweging van de camera gaat via een aparte camera die dichter bij het speler kararakter staat. Ik heb een aparte camera aangemaakt omdat het een grote uitdaging zou zijn om de cinemachine camera van de normale gameplay te gebruiken. En dat zou ook onnodige complexiteit toevoegen aan dat systeem.De nieuwe camera staat dicht bij het spelerkarakter, zodat de speler de animatie goed kan zien. Het plaatsen van deze camera is iets lastiger dan je zou verwachten, omdat dit spel zich afspeelt op planeten die ervoor zorgen dat de speler ondersteboven kan staan.
De soepele overgang tussen de twee camera's is gedaan door middel van een CinemachineBlendDefinition met de EaseInOut animatiecurve.
Kerncomponenten
Het systeem steunt op drie hoofdklassen:- GameOverManager: centrale aansturing
- PlayerHealthBar: leven- en doodstatus
- PlayerController: bewegingscontrole
Deze geïntegreerde aanpak zorgt voor een coherente game-over ervaring die past binnen de spelwereld van World Eater.
Dit is het einde. Bedankt voor het lezen!