Portage du Surreal Engine C++ vers WebAssembly

Dans cet article, je décrirai comment j’ai porté le moteur de jeu Surreal Engine vers WebAssembly.

Moteur surréaliste &#8211 ; un moteur de jeu qui implémente la plupart des fonctionnalités de l’Unreal Engine 1, des jeux célèbres sur ce moteur – Unreal Tournament 99, Unreal, Deus Ex, Undying. Il fait référence aux moteurs classiques qui fonctionnaient principalement dans un environnement d’exécution monothread.

Au départ, j’ai eu l’idée de me lancer dans un projet que je ne pouvais pas réaliser dans un délai raisonnable, montrant ainsi à mes abonnés Twitch qu’il y a des projets que même moi je ne peux pas réaliser. Lors de mon premier stream, j’ai soudainement réalisé que la tâche de porter Surreal Engine C++ vers WebAssembly à l’aide d’Emscripten était réalisable.

Surreal Engine Emscripten Demo

Après un mois, je peux faire une démonstration de mon ensemble fourche et moteur sur WebAssembly :
https://demensdeum.com/demos/SurrealEngine/

Le contrôle, comme dans l’original, s’effectue à l’aide des flèches du clavier. Ensuite, je prévois de l’adapter au contrôle mobile (tachi), en ajoutant un éclairage correct et d’autres fonctionnalités graphiques du rendu Unreal Tournament 99.

Par où commencer ?

La première chose que je veux dire est que n’importe quel projet peut être porté de C++ vers WebAssembly en utilisant Emscripten, la seule question est de savoir dans quelle mesure la fonctionnalité sera complète. Choisissez un projet dont les ports de bibliothèque sont déjà disponibles pour Emscripten ; dans le cas de Surreal Engine, vous avez beaucoup de chance, car le moteur utilise les bibliothèques SDL 2, OpenAL – ils sont tous deux portés sur Emscripten. Cependant, Vulkan est utilisé comme API graphique, qui n’est actuellement pas disponible pour HTML5, des travaux sont en cours pour implémenter WebGPU, mais il est également au stade de projet, et on ne sait pas non plus à quel point le port ultérieur de Vulkan vers WebGPU sera simple. , une fois qu’il est entièrement standardisé. Par conséquent, j’ai dû écrire mon propre rendu de base OpenGL-ES/WebGL pour Surreal Engine.

Construire le projet

Construire un système dans Surreal Engine – CMake, qui simplifie également le portage, car Emscripten fournit à ses constructeurs natifs – emcmake, emmake.
Le portage de Surreal Engine était basé sur le code de mon dernier jeu en WebGL/OpenGL ES et C++ appelé Death-Mask, de ce fait le développement était beaucoup plus simple, j’avais tous les indicateurs de build nécessaires avec moi et des exemples de code.

L’un des points les plus importants de CMakeLists.txt concerne les indicateurs de build pour Emscripten. Vous trouverez ci-dessous un exemple tiré du fichier de projet :


-s MAX_WEBGL_VERSION=2 \

-s EXCEPTION_DEBUG \

-fexceptions \

--preload-file UnrealTournament/ \

--preload-file SurrealEngine.pk3 \

--bind \

--use-preload-plugins \

-Wall \

-Wextra \

-Werror=return-type \

-s USE_SDL=2 \

-s ASSERTIONS=1 \

-w \

-g4 \

-s DISABLE_EXCEPTION_CATCHING=0 \

-O3 \

--no-heap-copy \

-s ALLOW_MEMORY_GROWTH=1 \

-s EXIT_RUNTIME=1")

Le script de build lui-même :


emmake make -j 16

cp SurrealEngine.data /srv/http/SurrealEngine/SurrealEngine.data

cp SurrealEngine.js /srv/http/SurrealEngine/SurrealEngine.js

cp SurrealEngine.wasm /srv/http/SurrealEngine/SurrealEngine.wasm

cp ../buildScripts/Emscripten/index.html /srv/http/SurrealEngine/index.html

cp ../buildScripts/Emscripten/background.png /srv/http/SurrealEngine/background.png

Ensuite, nous préparerons l’index .html , qui inclut le préchargeur du système de fichiers du projet. Pour télécharger sur le Web, j’ai utilisé Unreal Tournament Demo version 338. Comme vous pouvez le voir sur le fichier CMake, le dossier du jeu décompressé a été ajouté au répertoire de construction et lié en tant que fichier de préchargement pour Emscripten.

Modifications du code principal

Ensuite, il a fallu changer la boucle de jeu du jeu, vous ne pouvez pas exécuter une boucle sans fin, cela conduit au gel du navigateur, vous devez plutôt utiliser emscripten_set_main_loop, j’ai écrit à propos de cette fonctionnalité dans ma note de 2017 « < a href="https://demensdeum.com /blog/ru/2017/03/29/porting-sdl-c-game-to-html5-emscripten/" rel="noopener" target="_blank">Porter le jeu SDL C++ vers HTML5 (Emscripten)”
Nous modifions le code pour quitter la boucle while en if, puis nous affichons la classe principale du moteur de jeu, qui contient la boucle de jeu, dans la portée globale, et écrivons une fonction globale qui appellera l’étape de boucle de jeu à partir de l’objet global :


#include <emscripten.h>

Engine *EMSCRIPTEN_GLOBAL_GAME_ENGINE = nullptr;

void emscripten_game_loop_step() {

	EMSCRIPTEN_GLOBAL_GAME_ENGINE->Run();

}

#endif

Après cela, vous devez vous assurer qu’il n’y a pas de threads d’arrière-plan dans l’application ; s’il y en a, préparez-vous à les réécrire pour une exécution monothread, ou utilisez la bibliothèque phtread dans Emscripten.
Le fil d’arrière-plan dans Surreal Engine est utilisé pour lire de la musique, les données proviennent du fil du moteur principal concernant la piste en cours, la nécessité de jouer de la musique ou son absence, puis le fil d’arrière-plan reçoit un nouvel état via un mutex et commence à jouer de la nouvelle musique. , ou le met en pause. Le flux d’arrière-plan est également utilisé pour mettre la musique en mémoire tampon pendant la lecture.
Mes tentatives de création de Surreal Engine pour Emscripten avec pthread ont échoué, car les ports SDL2 et OpenAL ont été construits sans le support de pthread, et je ne voulais pas les reconstruire pour le plaisir de la musique. Par conséquent, j’ai transféré la fonctionnalité du flux de musique de fond vers une exécution monothread à l’aide d’une boucle. En supprimant les appels pthread du code C++, j’ai déplacé la mise en mémoire tampon et la lecture de musique vers le thread principal, afin qu’il n’y ait pas de retard, j’ai augmenté la mémoire tampon de quelques secondes.

Ensuite, je décrirai des implémentations spécifiques des graphiques et du son.

Vulkan n’est pas pris en charge !

Oui, Vulkan n’est pas pris en charge en HTML5, bien que toutes les brochures marketing présentent le support multiplateforme et large plate-forme comme le principal avantage de Vulkan. Pour cette raison, j’ai dû écrire mon propre moteur de rendu graphique de base pour un type OpenGL simplifié – – ES, il est utilisé sur les appareils mobiles, parfois il ne contient pas les fonctionnalités à la mode de l’OpenGL moderne, mais il se porte très bien sur WebGL, ce qui est exactement ce qu’Emscripten implémente. L’écriture du rendu de tuiles de base, du rendu bsp, pour l’affichage GUI le plus simple et du rendu des modèles + cartes a été achevée en deux semaines. C’était peut-être la partie la plus difficile du projet. Il reste encore beaucoup de travail à faire pour implémenter toutes les fonctionnalités du rendu Surreal Engine, donc toute aide des lecteurs est la bienvenue sous forme de code et de demandes d’extraction.

OpenAL pris en charge !

La grande chance est que Surreal Engine utilise OpenAL pour la sortie audio. Après avoir écrit un simple hello world dans OpenAL et l’avoir assemblé dans WebAssembly à l’aide d’Emscripten, il m’est devenu clair à quel point tout était simple et j’ai décidé de porter le son.
Après plusieurs heures de débogage, il est devenu évident que l’implémentation OpenAL d’Emscripten avait plusieurs bugs, par exemple, lors de l’initialisation de la lecture du nombre de canaux mono, la méthode a renvoyé un nombre infini, et après avoir essayé d’initialiser un vecteur de taille infinie, C++ plante avec l’exception vector::length_error.
Nous avons réussi à contourner ce problème en codant en dur le nombre de canaux mono à 2 048 :


		alcGetIntegerv(alDevice, ALC_STEREO_SOURCES, 1, &stereoSources);



#if __EMSCRIPTEN__

		monoSources = 2048; // for some reason Emscripten's OpenAL gives infinite monoSources count, bug?

#endif



Y a-t-il un réseau ?

Surreal Engine ne prend actuellement pas en charge le jeu en ligne, jouer avec des robots est pris en charge, mais nous avons besoin de quelqu’un pour écrire l’IA pour ces robots. Théoriquement, vous pouvez implémenter un jeu en réseau sur WebAssembly/Emscripten à l’aide de Websockets.

Conclusion

En conclusion, je voudrais dire que le portage de Surreal Engine s’est avéré assez fluide grâce à l’utilisation de bibliothèques pour lesquelles il existe des ports Emscripten, ainsi que mon expérience passée dans l’implémentation d’un jeu en C++ pour WebAssembly. sur Emscripten. Vous trouverez ci-dessous des liens vers des sources de connaissances et des référentiels sur le sujet.
M-M-M-MONSTER KILL !

De plus, si vous souhaitez aider le projet, de préférence avec le code de rendu WebGL/OpenGL ES, alors écrivez-moi dans Telegram :
https://t.me/demenscave

Liens

https://demensdeum.com/demos/SurrealEngine/
https://github.com/demensdeum/SurrealEngine-Emscripten

https://github.com/dpjudas/SurrealEngine

Flash Forever – Interceptor 2021

Recently, it turned out that Adobe Flash works quite stably under Wine. During a 4-hour stream, I made the game Interceptor 2021, which is a sequel to the game Interceptor 2020, written for the ZX Spectrum.

For those who are not in the know – the Flash technology provided interactivity on the web from 2000 to around 2015. Its shutdown was prompted by an open letter from Steve Jobs, in which he wrote that Flash should be consigned to history because it lagged on the iPhone. Since then, JS has become even more sluggish than Flash, and Flash itself has been wrapped in JS, making it possible to run it on anything thanks to the Ruffle player.

You can play it here:
https://demensdeum.com/demos/Interceptor2021

Video:
https://www.youtube.com/watch?v=-3b5PkBvHQk

Source code:
https://github.com/demensdeum/Interceptor-2021

Jeux de démonstration Masons-DR

Masonry-AR est un jeu de réalité augmentée dans lequel vous devez naviguer dans la ville dans le monde réel et collecter des connaissances maçonniques à partir de livres, obtenir de la monnaie et capturer un territoire pour votre ordre maçonnique. Le jeu n’a aucun rapport avec des organisations réelles, tous les matchs sont aléatoires.

Démo du jeu :
https://demensdeum.com/demos/masonry-ar/client

Vicki :
https://demensdeum.com/masonry-ar-wiki-ru/

Code source :
https://github.com/demensdeum/Masonry-AR

Coureur de moteur en acier à flamme

Je présente à votre attention Flame Steel Engine Runner – plate-forme de lancement d’applications multimédias basées sur la boîte à outils Flame Steel Engine. Les plates-formes prises en charge sont Windows, MacOS, Linux, Android, iOS et HTML 5. L’accent du développement du code d’application s’est déplacé vers les scripts – les scripts et les scripts. Pour le moment, le support de JavaScript a été ajouté à l’aide de TinyJS, la boîte à outils elle-même et le moteur continueront d’être développés dans des langages proches du matériel (C, C++, Rust, etc.)
Flame Steel Engine Runner Demo
Sur la page ci-dessous, vous pouvez faire tourner le cube, écrire du code en JavaScript, télécharger des modèles, des sons, de la musique, du code à l’aide du bouton Télécharger des fichiers et démarrer à partir du fichier main.js à l’aide du bouton Exécuter.
https://demensdeum.com/demos/FlameSteelEngineRunner/

RPG d’action Space Jaguar 0.0.4

Le premier prototype du jeu Space Jaguar Action RPG pour Webassembly :

Le chargement prendra beaucoup de temps (53 Mo) sans indication de chargement.

Action RPG Space Jaguar – simulateur de vie d’un pirate de l’espace. Pour le moment, les mécanismes de jeu les plus simples sont disponibles :

  • voler dans l’espace
  • mourir
  • manger
  • dormir
  • embaucher une équipe
  • regardez le flux du temps agité et rapide

En raison d’une mauvaise optimisation du rendu des scènes 3D dans la version Web, la possibilité de se déplacer dans un environnement 3D n’est pas disponible. L’optimisation sera ajoutée dans les versions futures.

Le code source du moteur, du jeu et des scripts est disponible sous licence MIT. Toutes les suggestions d’amélioration sont reçues de manière extrêmement positive :

https://gitlab.com/demensdeum/space-jaguar -action-rpg

Captures d’écran de la version native pour Linux :

Développement de jeux pour ZX Spectrum en C

Cet article absurde est dédié au développement d’un jeu pour l’ancien ordinateur ZX Spectrum en C. Jetons un coup d’œil au beau mec :

Sa production a commencé en 1982 et a été produite jusqu’en 1992. Caractéristiques techniques de la machine : processeur Z80 8 bits, 16-128 Ko de mémoire et autres extensions, comme la puce sonore AY-3-8910.

Dans le cadre du concours Yandex Retro Games Battle 2019 pour cette machine, j’ai écrit un jeu appelé Interceptor 2020. Comme je n’ai pas eu le temps d’apprendre le langage assembleur pour le Z80, j’ai décidé de le développer en C. En tant que chaîne d’outils, j’ai choisi un ensemble prêt à l’emploi – z88dk, qui contient des compilateurs C et de nombreuses bibliothèques auxiliaires pour accélérer la mise en œuvre des applications pour Spectrum. Il prend également en charge de nombreuses autres machines Z80, telles que les calculatrices MSX et Texas Instruments.

Ensuite, je décrirai mon survol superficiel de l’architecture informatique, la chaîne d’outils z88dk, et montrerai comment j’ai réussi à mettre en œuvre l’approche POO et à utiliser des modèles de conception.

Fonctionnalités d’installation

L’installation de z88dk doit être effectuée conformément au manuel du référentiel, cependant, pour les utilisateurs d’Ubuntu, je voudrais noter une fonctionnalité – Si vous avez déjà installé des compilateurs pour Z80 à partir de packages deb, vous devez les supprimer, puisque z88dk y accédera à partir du dossier bin par défaut en raison de l’incompatibilité des versions du compilateur de la chaîne d’outils, vous ne pourrez probablement rien compiler.< /p>

Bonjour tout le monde

Écrire Hello World est très simple :

#include 

void main()
{
    printf("Hello World");
}

Il est encore plus simple de compiler un fichier tap :

zcc +zx -lndos -create-app -o helloworld helloworld.c

Pour l’exécuter, utilisez n’importe quel émulateur ZX Spectrum prenant en charge les fichiers Tap, par exemple en ligne :
http://jsspeccy.zxdemo.org/

Dessinez sur l’image en plein écran

tl;dr Les images sont dessinées en tuiles, des tuiles de taille 8×8 pixels, les tuiles elles-mêmes sont intégrées dans la police Spectrum, puis l’image est imprimée sous forme de ligne à partir des index.

La bibliothèque de sortie de sprites et de tuiles sp1 génère des tuiles en utilisant UDG. L’image est traduite en un ensemble d’UDG individuels (tuiles), puis assemblés sur l’écran à l’aide d’indices. Il ne faut pas oublier que UDG est utilisé pour afficher du texte, et si votre image contient un très grand ensemble de tuiles (par exemple, plus de 128 tuiles), alors vous devrez dépasser les limites de l’ensemble et effacer le spectre par défaut. fonte. Pour contourner cette limitation, j’ai utilisé une base de 128 – 255 en simplifiant les images tout en laissant la police d’origine en place. À propos de la simplification des images ci-dessous.

Pour dessiner des images en plein écran, vous devez vous armer de trois utilitaires :
Gimp
img2spec
png2c-z88dk

Il existe un moyen pour les vrais hommes ZX, les vrais guerriers rétro, celui-ci consiste à ouvrir un éditeur graphique à l’aide de la palette Spectrum, connaissant les caractéristiques de la sortie de l’image, à la préparer manuellement et à la télécharger en utilisant png2c-z88dk ou png2scr.< /p>

Le moyen le plus simple – prenez une image 32 bits, changez le nombre de couleurs sur 3-4 dans Gimp, modifiez-la légèrement, puis importez-la dans img2spec afin de ne pas travailler manuellement avec les restrictions de couleur, exportez png et convertissez-la en tableau C en utilisant png2c- z88dk.

N’oubliez pas que pour une exportation réussie, chaque vignette ne peut pas contenir plus de deux couleurs.

En conséquence, vous recevrez un fichier h contenant le nombre de tuiles uniques, s’il y en a plus de ~128, alors simplifiez l’image dans Gimp (augmentez la répétabilité) et effectuez la procédure d’exportation sur une nouvelle. .

Après l’exportation, vous chargez littéralement la « police » des vignettes et imprimez le « texte » des index des vignettes sur l’écran. Vous trouverez ci-dessous un exemple de la « classe » de rendu :

// грузим шрифт в память
    unsigned char *pt = fullscreenImage->tiles;

    for (i = 0; i < fullscreenImage->tilesLength; i++, pt += 8) {
            sp1_TileEntry(fullscreenImage->tilesBase + i, pt);
    }

    // ставим курсор в 0,0
    sp1_SetPrintPos(&ps0, 0, 0);

    // печатаем строку
    sp1_PrintString(&ps0, fullscreenImage->ptiles);

Dessiner des sprites sur l’écran

Ensuite, je décrirai une méthode pour dessiner des sprites de 16 à 16 pixels sur l’écran. Je n’ai pas abordé l’animation et le changement de couleurs, parce que… C’est trivial qu’à ce stade déjà, comme je suppose, j’ai manqué de mémoire. Par conséquent, le jeu ne contient que des sprites monochromes transparents.

Nous dessinons une image png monochrome 16×16 dans Gimp, puis en utilisant png2sp1sprite nous la traduisons en un fichier d’assemblage asm, en code C nous déclarons des tableaux à partir du fichier d’assemblage et ajoutons le fichier au stade de l’assemblage.< /p>

Après l’étape de déclaration de la ressource sprite, celle-ci doit être ajoutée à l’écran à la position souhaitée, ci-dessous un exemple de code pour la « classe » de l’objet du jeu :

    struct sp1_ss *bubble_sprite = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0);
    sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2,    SP1_TYPE_2BYTE, col2-col1, 0);
    sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2RB,  SP1_TYPE_2BYTE, 0, 0);
    sp1_IterateSprChar(bubble_sprite, initialiseColour);

À partir des noms des fonctions, vous pouvez comprendre approximativement la signification de « – allouez de la mémoire pour le sprite, ajoutez deux colonnes 8×8, ajoutez une couleur pour le sprite.

La position du sprite est indiquée dans chaque image :

sp1_MoveSprPix(gameObject->gameObjectSprite, Renderer_fullScreenRect, gameObject->sprite_col, gameObject->x, gameObject->y);

Émulation de la POO

Il n’y a pas de syntaxe pour la POO en C, que devez-vous faire si vous le souhaitez toujours ? Vous devez connecter votre esprit et être éclairé par l’idée qu’il n’existe pas d’équipement POO ; tout revient finalement à l’une des architectures de machines, dans lesquelles il n’y a tout simplement aucun concept d’objet et d’autres abstractions qui lui sont associées.< /p>

Ce fait m’a empêché pendant très longtemps de comprendre pourquoi la POO est nécessaire, pourquoi il est nécessaire de l’utiliser si en fin de compte tout se résume au code machine.

Cependant, après avoir travaillé dans le développement de produits, j’ai découvert les plaisirs de ce paradigme de programmation, principalement, bien sûr, la flexibilité du développement, les mécanismes de protection du code, avec la bonne approche, la réduction de l’entropie, la simplification du travail d’équipe. Tous les avantages ci-dessus découlent de trois piliers : polymorphisme, encapsulation, héritage.

Il convient également de noter la simplification de la résolution des problèmes liés à l’architecture des applications, car 80 % des problèmes architecturaux ont été résolus par des informaticiens au siècle dernier et décrits dans la littérature sur les modèles de conception. Ensuite, je décrirai les façons d’ajouter une syntaxe de type POO au C.

Il est plus pratique de prendre des structures C comme base pour stocker les données d’une instance de classe. Bien sûr, vous pouvez utiliser un tampon d’octets, créer votre propre structure pour les classes, les méthodes, mais pourquoi réinventer la roue ? Après tout, nous réinventons déjà la syntaxe.

Données de classe

Exemple de champs de données « classe » GameObject :

struct GameObjectStruct {
    struct sp1_ss *gameObjectSprite;
    unsigned char *sprite_col;
    unsigned char x;
    unsigned char y;
    unsigned char referenceCount;
    unsigned char beforeHideX;
    unsigned char beforeHideY;
};
typedef struct GameObjectStruct GameObject;

Enregistrez notre classe sous « GameObject.h », faites #include « GameObject.h » au bon endroit et utilisez-la.

Méthodes de classe

Compte tenu de l’expérience des développeurs du langage Objective-C, la signature d’une méthode de classe sera constituée de fonctions dans une portée globale, le premier argument sera toujours la structure des données, suivi des arguments de la méthode. Vous trouverez ci-dessous un exemple de « méthode » de la « classe » GameObject :

void GameObject_hide(GameObject *gameObject) {
    gameObject->beforeHideX = gameObject->x;
    gameObject->beforeHideY = gameObject->y;
    gameObject->y = 200;
}

L’appel de méthode ressemble à ceci :

GameObject_hide(gameObject);

Les constructeurs et les destructeurs sont implémentés de la même manière. Il est possible d’implémenter un constructeur en tant qu’allocateur et initialiseur de champ, mais je préfère contrôler l’allocation et l’initialisation des objets séparément.

Travailler avec la mémoire

Gestion manuelle de la mémoire du formulaire à l’aide de malloc et free enveloppé dans des macros new et delete pour correspondre à C++ :

#define new(X) (X*)malloc(sizeof(X))
#define delete(X) free(X)

Pour les objets utilisés par plusieurs classes à la fois, une gestion semi-manuelle de la mémoire est implémentée sur la base d’un comptage de références, à l’image et à la ressemblance de l’ancien mécanisme Objective-C Runtime ARC :

void GameObject_retain(GameObject *gameObject) {
    gameObject->referenceCount++;
}

void GameObject_release(GameObject *gameObject) {
    gameObject->referenceCount--;

    if (gameObject->referenceCount < 1) { sp1_MoveSprAbs(gameObject->gameObjectSprite, &Renderer_fullScreenRect, NULL, 0, 34, 0, 0);
        sp1_DeleteSpr(gameObject->gameObjectSprite);
        delete(gameObject);
    }
}

Ainsi, chaque classe doit déclarer l’utilisation d’un objet partagé en utilisant retention, libérant ainsi la propriété via release. La version moderne d’ARC utilise des appels automatiques de rétention/libération.

Le son !

Le Spectrum dispose d’un tweeter capable de reproduire de la musique 1 bit ; les compositeurs de l’époque étaient capables de reproduire jusqu’à 4 canaux sonores simultanément.

Le Spectrum 128k contient une puce sonore distincte AY-3-8910, qui peut lire de la musique de suivi.

Une bibliothèque est proposée pour utiliser le tweeter dans le z88dk

Ce qui reste à apprendre

Je souhaitais me familiariser avec Spectrum, implémenter le jeu à l’aide du z88dk et apprendre beaucoup de choses intéressantes. J’ai encore beaucoup à apprendre, par exemple l’assembleur Z80, car il me permet d’utiliser toute la puissance du Spectrum, de travailler avec des banques de mémoire et de travailler avec la puce sonore AY-3-8910. J’espère participer au concours l’année prochaine !

Liens

https://rgb.yandex
https://vk.com/sinc_lair
https://www.z88dk.org/forum/

Code source

https://gitlab.com/demensdeum/ zx-projects/tree/master/interceptor2020

Bêta sauvage de Death-Mask

Le jeu Death-Mask entre en version bêta publique (wild beta)
L’écran du menu principal du jeu a été repensé, une vue de la zone bleue du techno-labyrinthe a été ajoutée, avec une musique agréable en fond.

Ensuite, je prévois de retravailler le contrôleur de jeu, d’ajouter des mouvements fluides comme dans les anciens jeux de tir, des modèles 3D de haute qualité de boîtes, d’armes, d’ennemis, la possibilité de passer à d’autres niveaux du techno-labyrinthe non seulement via des portails ( ascenseurs, portes, chutes à travers des trous dans le sol, trous dans les murs), je vais ajouter un peu de variété à l’environnement du labyrinthe généré. Je travaillerai également sur l’équilibre du jeu.
Une animation squelettique sera ajoutée en tant que phase de peaufinage avant la sortie.< /p>