Cette page explique comment utiliser les énumérations basées sur ScriptableObject dans votre projet Unity.
Il s'agit du troisième d'une série de six mini-guides créés pour aider les développeurs Unity avec la démo qui accompagne le livre électronique, Créer une architecture de jeu modulaire dans Unity avec ScriptableObjects.
La démo s'inspire des mécanismes classiques des jeux d'arcade à balles et à raquettes et montre comment ScriptableObjects peut vous aider à créer des composants testables, évolutifs et conviviaux pour les concepteurs.
Ensemble, le livre électronique, le projet de démonstration et ces mini-guides fournissent les meilleures pratiques pour utiliser les modèles de conception de programmation avec la classe ScriptableObject dans votre projet Unity. Ces conseils peuvent vous aider à simplifier votre code, à réduire l'utilisation de la mémoire et à favoriser la réutilisabilité du code.
Cette série comprend les articles suivants :
Avant de vous plonger dans le projet de démonstration ScriptableObject et cette série de mini-guides, n'oubliez pas qu'à la base, les modèles de conception ne sont que des idées. Ils ne s’appliqueront pas à toutes les situations. Ces techniques peuvent vous aider à apprendre de nouvelles façons de travailler avec Unity et ScriptableObjects.
Chaque modèle a des avantages et des inconvénients. Choisissez uniquement ceux qui profitent de manière significative à votre projet spécifique. Vos concepteurs s’appuient-ils fortement sur l’éditeur Unity ? Un modèle basé sur ScriptableObject pourrait être un bon choix pour les aider à collaborer avec vos développeurs.
En fin de compte, la meilleure architecture de code est celle qui convient à votre projet et à votre équipe.
Les énumérations sont un moyen pratique de gérer un ensemble fixe de valeurs nommées dans votre code. Cependant, ils comportent certaines limites. Étant donné que les valeurs d'énumération sérialisées sont stockées sous forme d'entiers plutôt que sous forme de noms symboliques, la suppression ou la réorganisation d'une valeur peut entraîner un comportement incorrect ou inattendu. Cela signifie que les énumérations, en particulier lorsque vous en avez beaucoup, peuvent créer des maux de tête dans le développement d'Unity.
L'approche standard
Voici à quoi ressemble une énumération typique :
[System.Serializable]
énumération publique HandGestures
{
Rocher,
Papier,
Ciseaux
}
Vous pouvez sérialiser une énumération avec l'attribut System.Serializable et elle apparaît dans l'inspecteur.
Le problème
La réorganisation ou la suppression d’une valeur peut entraîner des problèmes. Étant donné que chaque valeur est en interne un entier, ce qu’elle représente peut devenir quelque chose de différent. Dans l'exemple donné, la suppression de la valeur Paper amènerait Scissors à prendre la valeur 1.
Ou, si nous ajoutions une valeur comme dans l'exemple ci-dessous.
La valeur d'énumération sélectionnée changerait si elle apparaissait après l'entrée supprimée.
Cela peut entraîner des problèmes lors de la maintenance et de la mise à jour des projets, en particulier lorsque votre énumération contient de nombreuses valeurs. Vous pouvez atténuer ce problème en laissant un élément vide ou inutilisé, ou en définissant explicitement des valeurs entières. Cependant, aucune des deux solutions n’est idéale.
Les énumérations basées sur ScriptableObject vous offrent les fonctionnalités des énumérations traditionnelles mais sont stockées en tant qu'actifs individuels. Par exemple, regardez le PlayerIDSO ScriptableObject dans le projet PaddleBallSO dans l'exemple ci-dessous.
Essentiellement, il s’agit d’un ScriptableObject vide.
Vous pouvez l'utiliser pour créer un certain nombre d'actifs ScriptableObject dans le projet, comme P1, P2, etc. Même s'ils ne contiennent aucune donnée, vous pouvez utiliser des ScriptableObjects à des fins de comparaison. Créez simplement un nouvel asset ScriptableObject dans le projet et donnez-lui un nom.
Vous pouvez créer autant d'identifiants de joueur que vous le souhaitez au sein du projet et basculer facilement entre eux. Modifiez simplement l’élément attribué dans le script GameDataSO.
Si vous vérifiez l’égalité, cela fonctionne de manière similaire à une énumération. Deux variables font-elles référence au même ScriptableObject ? Si c’est le cas, il s’agit du même type d’objet. Sinon, ils ne le sont pas.
Même sans aucune donnée supplémentaire, le ScriptableObject représente une catégorie ou un type d'élément.
Dans PaddleBallSO, le PlayerIDSO devient une désignation d'équipe. Nous utilisons les ressources P1 et P2 dans GameDataSO pour différencier les deux raquettes.
Le script GameSetup attribue à chaque raquette un identifiant de joueur. Pendant le jeu, les scripts Paddle comparent la saisie du joueur avec l'ID d'équipe désigné.
Ceci a des applications pour tout type de jeu multijoueur. Vous pouvez également envisager de les adopter partout où vous utilisez une énumération.
Puisqu'il s'agit simplement d'affectations dans l'inspecteur, les ScriptableObjects ne sont pas soumis aux mêmes problèmes de renommage et de réorganisation.
Vous souhaitez modifier les noms d’identifiant en « Joueur1 » ou « Joueur2 » respectivement ? Vous pouvez le faire et tout continue de fonctionner. Ajouter plus d'objets scriptables ? Ce n’est pas un problème : l’affectation des ressources dans l’inspecteur reste la même.
Ce comportement est utile pour créer un gameplay. Dans la démo Patterns, cliquez sur le bouton Switch Enum pour changer d'équipe. Un MonoBehaviour sur le DemoBall met à jour le SpriteRenderer en conséquence.
La balle inflige-t-elle des dégâts à un bloc lorsqu'elle entre en collision ? Découvrez-le en effectuant un test rapide d’égalité. Voici une façon de les comparer dans l'exemple de code ci-dessous.
Cette méthode peut déterminer si deux GameObjects font partie de la même équipe, ce qui est utile pour vérifier les interactions entre amis et ennemis. Cette comparaison simple peut s’appliquer aux objets récupérés, aux dégâts ou à tout autre élément ayant une « équipe » ou un « alignement ».
La partie amusante se produit lorsque vous ajoutez de la logique à vos ScriptableObjects. Contrairement à une énumération conventionnelle, un ScriptableObject peut avoir des champs et des méthodes, en plus de contenir des données.
Utilisez-les pour que chaque ScriptableObject puisse avoir une logique de comparaison spécialisée. Par exemple, vous pouvez avoir un ScriptableObject qui définit des effets de dégâts spéciaux (par exemple, froid, chaleur, électricité, magie, etc.).
Si votre application nécessite un système d'inventaire pour équiper des objets de jeu, les ScriptableObjects peuvent représenter des types d'objets ou des emplacements d'armes. Certains personnages ne sont-ils pas autorisés à détenir certains objets ? Certains objets sont-ils magiques ou ont-ils des capacités spéciales ? Les énumérations basées sur ScriptableObject peuvent ajouter des méthodes pour vérifier cela.
Le MonoBehaviour DemoBall de l'exemple précédent inclut la méthode AreEqual pour comparer les ScriptableObjects. Lors de l’extension du comportement, vous pouvez regrouper la logique de comparaison à l’intérieur de l’objet Scriptable lui-même.
Dans la démo Patterns, vous pouvez modifier la balle pour qu'elle soit plus sélective lors d'une collision avec un objet. Regardez un élément à usage général pour la collision dans l’exemple de code ci-dessous.
Cela pourrait produire des résultats similaires à la démo actuelle, mais il dispose désormais d'un champ m_Weakness . Cela permet à chaque ScriptableObject de définir un autre ScriptableObject à détruire en cas de collision.
Plutôt que d'appeler la méthode AreEqual , chaque ScriptableObject gère simplement sa propre logique de comparaison.
Le résultat est plus flexible et extensible. Au lieu de laisser le ballon détruire un bloc d’une équipe différente, vous pouvez être précis. Plusieurs balles dans la scène peuvent détruire différents blocs, en fonction de leurs CollisionItems individuels.
Cela ouvre la voie à des interactions différentes et plus complexes. Si vous souhaitez créer un système de type pierre-papier-ciseaux, vous pouvez définir trois objets scriptables : Pierre, papier et ciseaux. Chacun pourrait avoir son propre m_Weaknessunique et utiliser la méthode IsWinner pour gérer les interactions.
Contrairement aux énumérations, les ScriptableObjects rendent ce processus modulaire et adaptable. Il n’est pas nécessaire de s’appuyer sur des structures de données supplémentaires ou d’ajouter une logique supplémentaire pour se synchroniser avec un ensemble de données distinct. Ajoutez simplement un champ et/ou une méthode supplémentaire pour gérer la logique.
Une fois que vous serez familiarisé avec les énumérations basées sur ScriptableObject, vous constaterez qu'elles peuvent améliorer votre flux de travail, en particulier lorsque vous travaillez avec des coéquipiers. Puisqu’il s’agit d’actifs, leur mise à jour crée moins de conflits de fusion, réduisant ainsi le risque de perte de données.
L'ajout de nouvelles énumérations basées sur ScriptableObject est similaire à la création d'un autre actif. Contrairement aux énumérations traditionnelles, l'ajout de nouvelles valeurs ne cassera pas votre code existant. De plus, Unity dispose déjà d’outils intégrés pour les rechercher, les filtrer et les organiser, comme n’importe quel autre actif.
En prime, l'utilisation de l'interface utilisateur glisser-déposer de l'éditeur permet à vos concepteurs d'étendre les données de jeu sans l'aide supplémentaire d'un développeur de logiciels. Vous devrez toujours coordonner la manière de configurer les champs au départ, mais les concepteurs peuvent ensuite remplir eux-mêmes ces champs avec des données.
Les énumérations basées sur ScriptableObject sont une ressource supplémentaire que votre équipe peut utiliser pour améliorer la collaboration et l'efficacité.
Pour en savoir plus sur les modèles de conception avec ScriptableObjects, consultez notre livre électronique technique Créer une architecture de jeu modulaire dans Unity avec ScriptableObjects. Vous pouvez également en savoir plus sur les modèles de conception de développement Unity courants dans Améliorez votre code avec les modèles de programmation de jeux.