Pour réaliser la carte 2D interactive, au lieu d'utiliser une Scene Capture 2D classique (qui permet de prendre une capture de la scène 3D vue de haut), j'ai préféré inverser les rôles et utiliser une caméra orthographique, pointant vers le bas de la scène 3D.
Le principal avantage pour un prototype est que le joueur contrôle directement cette caméra, ce qui améliore grandement la fluidité, le gamefeel même pour un prototype, ainsi que l'interactivité en général car pour déplacer l'agent sur le terrain, le jeu récupère facilement sous forme de vector la position sélectionnée dans le monde.
Le plan en 2D est donc simplement la représentation minimaliste de la vraie map, en 3D posé directement sur le "vrai" level faisant office de plafond.
.avif)
L'agent sur le terrain peut réagir à son environnement. Que ce soit lorsqu'il interagit avec un élément et qu'il détecte un son, ou pour donner des précisions lorsque le joueur lui demande de se diriger vers un endroit.
Il sert de relais afin d'informer le joueur, par message, via sa caméra ou par l'affichage de la mini-carte, sur l'univers dans lequel il évolue.
Il peut également, dans certains cas, poser des questions au joueur, que ce soit pour être rassuré, ou plus simplement lorsqu'il souhaite avoir son avis. Cela permet de rendre l'agent sur le terrain plus vivant.
La mécanique principale de ce jeu est la distraction : le but est de compléter les objectifs de la mission sans que l'agent sur place ne se fasse repérer. Pour ce faire, l'agent peut compter sur l'Opérateur (vous-même) pour l'aider à passer les différents obstacles.
Le joueur a la possibilité de pirater à distance les différents objets interactifs visibles. Il existe deux types d'objets interactifs :
L'un étant identifié sur la carte 2D à l'aide d'une icône représentant l'objet en question (caméra, imprimante...). L'autre étant identifié par des points d'interrogation. Dans l'exemple ci-dessous, un des « ? » représente simplement une maquette budgétaire à voler, tandis qu'un autre représente un levier ouvrant l'accès à la salle des serveurs.
Pour réaliser ce système d'interaction basé sur l'objet sélectionné, j'ai utilisé un système d'interface où j'appelle la même fonction (nommée ici ExecuteAction avec un paramètre de type integer pour savoir quelle action le joueur a choisie) et chaque objet exécute sa propre action en conséquence (notamment une fonction TriggerNoise qui permet à n'importe quel objet d'émettre un son de distraction où chaque classe enfant peut l'override pour y mettre ses propres paramètres, son propre son, cooldown...).
Afin de réaliser le système d'intelligence artificielle, j’ai utilisé les State Trees. Concrètement, cela permet de créer une logique facilement compréhensible, légère en termes de performances, tout en améliorant la modularité ainsi que la maintenance.
Ci-dessous, vous trouverez deux vidéos :
L'une montrera la logique globale utilisée à l'aide des State Trees pour les ennemis. Vous retrouverez les états principaux de l'IA (patrouille, état d'alerte, lorsqu'elle entend un bruit...) ainsi que la logique dans chaque état.
La seconde montrera la manière dont est géré le système de détection visuelle de l'agent. Le principe est plutôt simple : à l'aide d'une interface que possèdent les ennemis, lorsque l'AIPerception de l'agent se met à jour, il vérifie si l'acteur possède l'interface. Si oui, il appelle une fonction sur l'acteur qui le fait apparaître sur la minimap. Si l'agent perd de vue l'ennemi en question, un délai de recharge (ou temps d'attente / compte à rebours) de 15 secondes se déclenche ; à la fin de celui-ci, si l'agent n'a pas revu l'ennemi, l'icône de l'ennemi disparaît.
À la fin de la partie, un résumé de celle-ci est affiché à l'écran. Pour le réaliser, j'ai créé l'animation complète dans l'UMG d'Unreal Engine, et au niveau des statistiques, elles sont toutes stockées de base dans le GameMode ou le GameState.
Notamment pour le temps passé, je stocke le temps de départ, puis je récupère le temps d'arrivée et, en soustrayant les deux, j'obtiens le temps passé en secondes qu'il ne me reste qu'à formater.
Également au niveau de l'objectif bonus, si le joueur l'accomplit, j'appelle depuis une interface sur le GameMode la fonction SetBonusDone, ce qui me permet à la fin de savoir si oui ou non le joueur a réalisé l'objectif bonus.