Utilisation avancée de Room et de Portal

Rappels de gameplay

Bien que l'occlusion culling réduise considérablement le nombre d'objets devant être rendus, le maintien des objets dans un jeu entraîne d'autres coûts que le rendu final. Par exemple, dans Godot, les objets animés seront toujours animés, qu'ils apparaissent ou non à l'écran. Cela peut demander beaucoup de puissance de traitement, en particulier pour les objets qui utilisent le skinning logiciel (où le skinning est calculé sur le CPU).

N'ayez crainte, les salles et les portails peuvent résoudre ces problèmes, et bien plus encore.

En construisant notre système de pièces pour notre niveau de jeu, non seulement nous disposons des informations nécessaires pour l'occlusion culling, mais nous avons également créé les informations nécessaires pour savoir quelles pièces se trouvent dans la "zone de jeu" locale du joueur (ou de la caméra). Si vous y réfléchissez, dans de nombreux cas, il n'est pas nécessaire de faire beaucoup de simulation sur des objets qui n'ont rien à voir avec le gameplay.

La zone de jeu ne se limite pas aux objets que vous pouvez voir devant vous. L'IA des monstres derrière vous doivent encore vous attaquer lorsque vous avez le dos tourné ! Dans Godot, la zone de jeu est définie comme l'ensemble potentiellement visible (PVS) des pièces, à partir de la pièce dans laquelle vous vous trouvez actuellement. Autrement dit, s'il existe une partie d'une pièce qui peut éventuellement être vue depuis n'importe quelle partie de la pièce dans laquelle vous vous trouvez (même depuis un coin), elle est considérée comme faisant partie du PVS, et donc de la zone de jeu.

Cela fonctionne parce que si un monstre se trouve dans une zone qui est complètement hors de vue pour vous ou le monstre, vous êtes moins susceptible de vous soucier de ce qu'il fait.

Comment un monstre peut-il savoir s'il se trouve dans la zone de jeu ?

Ce problème est résolu car le système de portail contient un sous-système appelé le Gameplay Monitor qui peut être activé et désactivé à partir du RoomManager. Lorsqu'il est activé, tous les objets itinérants qui se déplacent à l'intérieur ou à l'extérieur de la zone de jeu (que ce soit en se déplaçant eux-mêmes ou en déplaçant la caméra) recevront des rappels pour les informer de ce changement.

Vous pouvez choisir de recevoir ces rappels soit sous la forme signals, soit sous la forme notifications.

Les notifications peuvent être traitées en GDScript ou dans d'autres langages de script :

func _notification(what):
        match what:
                NOTIFICATION_ENTER_GAMEPLAY:
                        print("notification enter gameplay")
                NOTIFICATION_EXIT_GAMEPLAY:
                        print("notification exit gameplay")

Les signaux sont envoyés comme n'importe quel autre signal. Ils peuvent être attachés aux fonctions à l'aide de l'inspecteur de l'éditeur. Les signaux sont appelés gameplay_entered et gameplay_exited.

En fait, vous ne recevez pas ces rappels uniquement pour les objets ROAMING. En outre, les Rooms et les RoomGroups (qui peuvent être utilisés pour former des groupes de salles) peuvent également recevoir des rappels. Par exemple, vous pouvez utiliser cela pour déclencher un comportement de l'IA lorsque le joueur atteint certains points dans un niveau.

VisibilityNotifier2D

Les rappels de gameplay ont une autre fonction utile. Par défaut, dans Godot, l'animation et la physique sont toujours traitées, qu'un objet soit visible ou non. Cela peut réduire les performances, en particulier lors de l'utilisation de l'habillage logiciel.

La solution du moteur à ce problème est le nœud VisibilityNotifier, et sa variante légèrement plus facile à utiliser, le nœud VisibilityEnabler. VisibilityEnabler peut être utilisé pour désactiver l'animation et mettre en veille la physique lorsqu'un objet se trouve en dehors du tronc de vue. Pour ce faire, il suffit de placer un nœud VisibilityEnabler dans votre sous-scène (pour un monstre, par exemple). Il fera le reste. Consultez la documentation du VisibilityEnabler pour plus de détails.

../../../_images/visibility_enabler.png

Et si le VisibilityEnabler pouvait désactiver les objets en cas d'occlusion ? Eh bien, il s'avère que le VisibilityEnabler peut le faire. Tout ce que vous avez à faire est d'activer le Gameplay Monitor dans le RoomManager et le reste se fait automatiquement.

Groupes de salles

Un :ref:`RoomGroup<class_RoomGroup>`est un nœud spécial qui permet de traiter un groupe de salles en une seule fois, au lieu de devoir écrire du code pour chacune d'entre elles. C'est particulièrement utile en conjonction avec les callbacks de gameplay. L'usage le plus import pour les RoomGroups est pour délimiter les zones "intérieures" et "extérieures".

../../../_images/roomgroups.png

Par exemple, à l'extérieur, quand vous souhaitez utiliser une DirectionalLight pour représenter le soleil. Quand le RoomGroup extérieur reçoit un callback enter gameplay, vous pouvez activer la lumière, et vous pouvez la désactiver quand le RoomGroup sort du gameplay. Avec la lumière désactivée, les performances augmenteront puisqu'il n'est pas nécessaire de la rendre en intérieur.

Voici un exemple d'un simple script RoomGroup pour allumer et éteindre une DirectionalLight. Notez que vous pouvez également utiliser les signaux pour les callbacks (le choix vous appartient) :

../../../_images/roomgroup_notification.png

Astuce

Vous pouvez appliquer la même technique pour activer et désactiver les effets météo, les skyboxes, et bien plus encore.

Salles intérieures

Il y a une autre astuce que les RoomGroups ont dans leur manche. C'est très courant de vouloir un niveau de jeu avec un environnement extérieur et intérieur. Nous avons déjà mentionné que les salles peuvent être utilisées pour représenter à la fois les salles d'un bâtiment, et les zones d'un paysage, comme un canyon.

Que se passe-t-il si vous souhaitez avoir une maison dans une 'salle' terrain ?

Avec la fonctionnalité décrite jusqu'à présent, vous pouvez le faire - il vous faudrait cependant placer des portails autour de l'extérieur de la maison, formant des salles inutiles au-dessus de la maison. Cela a été fait dans de nombreux jeux. Et s'il existait un moyen plus simple ?

Il s'avère qu'il existe un moyen plus simple de gérer ce scénario. Godot supporte les salles **à l'intérieur* de salles* (nous les appellerons "salles internes"). C'est-à-dire que vous pouvez placer une maison à l'intérieur d'une salle terrain, ou même un bâtiment, ou un ensemble de bâtiments, et même avoir des portails de sortie dans différentes salles terrain !

Pour créer des salles internes, vous n'avez pas besoin de placer une salle à l'intérieur d'une autre salle dans l'arbre de scènes - en fait, vous aurez un avertissement si vous essayez de le faire. Créez-les plutôt comme des salles normales. Les salles internes doivent être regroupées avec un RoomGroup comme parent. Si vous regardez dans l'inspecteur du RoomGroup, il y a un Room Group Priority qui est à 0 par défaut.

Si vous voulez qu'une salle ou ensemble de salles soit interne, définissez la priorité à une valeur plus grande que celle de la pièce externe (qui l'entoure), en utilisant le RoomGroup.

Le système utilise ce paramètre de priorité pour donner la priorité à la salle interne lorsqu'il décide de la salle dans laquelle une caméra ou un objet se trouve. La priorité la plus élevée l'emporte toujours. Tout le reste fonctionne de manière similaire.

Les seules différences :

  • Les portails entre des salles internes et des salles externes doivent toujours être placés dans la salle intérieure (interne).

  • Les portails de salles internes ne sont pas considérés comme faisant partie de la limite des salles externes.

  • Les objets STATIC et DYNAMIC des salles externes ne s'étendront pas dans les salles internes. Si vous voulez que les objets traversent ces portails, placez-les dans la salle interne. Cela permet d'éviter que des objets de grande taille, tels que des sections de terrain, ne s'étendent dans des bâtiments entiers, et soient rendus lorsque ce n'est pas nécessaire.

Exemple de pièce intérieure

La tente est une simple salle à l'intérieur d'une salle terrain (qui contient le sol, les arbres, etc.).

../../../_images/tent.png

Note

Pour utiliser des salles internes pour des bâtiments, c'est généralement une bonne idée de séparer le modèle intérieur du bâtiment du modèle extérieur. L'extérieur peut être placé dans la salle externe (pour qu'il puisse être vu de l'extérieur, mais pas de l'intérieur), et l'intérieur doit être placé dans la salle intérieure (pour qu'il soit visible à l'intérieur, ou à travers le portail).

../../../_images/tent_terrain.png

C'est parfait pour améliorer les performances des jeux à monde ouvert. Souvent, vos bâtiments peuvent être des scènes (y compris les salles et les portails) qui peuvent être réutilisées. Lorsqu'ils sont vus de l'extérieur, les intérieurs seront en grande partie cachés, et lorsqu'ils sont vus de l'intérieur, les autres bâtiments et la plupart de l'extérieur seront cachés. Il en va de même pour les autres joueurs et les objets qui sont à l'intérieur et à l'extérieur des bâtiments.

La scène est 'Diorama Eco scene' par Odo, avec de légères modifications à des fins d'illustration. CC Attribution

Scènes d'intérieur

Examinons en détail un autre exemple pratique pour un monde ouvert. Nous voulons placer des maisons (en tant que salles internes) sur une île, mais faire de chaque maison une scène autonome contenant à la fois le modèle intérieur et extérieur de la maison.

../../../_images/house_scene.png

Nous avons créé un nœud Room (qui deviendra la salle interne) dans lequel nous avons placé les modèles d'intérieur. Nous avons également créé un Portal sans lien (donc la liaison automatique sera utilisée). Le modèle extérieure n'est pas à l'intérieur de la salle. Il sera placé automatiquement, et nous avons l'intention qu'il soit placé dans la salle externe.

Cependant, il y a un problème. L'algorithme naïf de placement automatique va regardez le centre du modèle extérieur, et va tenter de la placer à l'intérieur de la salle interne. Nous voulons éviter cela, car l'idée du modèle extérieur est d'avoir un rendu de l'extérieur, donc il doit être dans la salle externe pour que tout fonctionne.

Pour contourner ce problème, il y a un paramètre spécial qui vous permet d'exprimer une préférence pour le placement automatique dans une salle externe. Chaque objet a un paramètre Autoplace Priority. Lorsqu'il est défini à 0, il n'y a pas de préférence (l'objet sera placé dans la salle avec la plus haute priorité).

Cependant, si nous définissons cette priorité à -1 par exemple, le placement automatique choisira toujours une salle avec une priorité de -1 (s'il y en a une à cet endroit). Donc si nous définissons la priorité de la salle externe à -1, il placera toujours notre extérieur dans la salle "extérieure".

../../../_images/autoplace_priority.png

Cela nous donne un contrôle supplémentaire utile pour ce genre de situations, et rend l'ensemble du système beaucoup plus flexible.

Note

Comme la priorité de placement automatique est 0, vous ne pouvez pas forcer les objets à se mettre dans les RoomGroups qui ont une priorité de 0. Cependant, de nombreuses valeurs de priorité sont disponibles, ce qui ne devrait pas poser de problème en pratique.

La scène finale ressemble à quelque chose comme ça, avec les maisons instanciées où vous voulez dans une salle externe géante.

../../../_images/island.png

Les extérieurs de la maison seront placés dans la salle externe, et pourront donc toujours être vus de l'extérieur. Les intérieurs seront seulement rendus quand les portails d'entrée seront visibles à la caméra.