Comment Utiliser Des Objets Scriptables Dans Unity

Considérez que vous développez un système marchand pour votre jeu dans Unity, où le marchand vend une liste d'articles avec un nom, un prix, une description et une image différents.

Le concepteur de jeu de votre équipe a déjà rédigé un document de 100 pages sur divers objets avec un chapitre entier consacré aux multiples types de potions. En tant que programmeur principal, vous devez décider où stocker chacun de ces éléments dans votre système, alors où le feriez-vous ?

Dans cet article, nous allons explorer le prototypage rapide dans Unity et la façon dont vous pouvez utiliser efficacement les objets scriptables dans le développement de votre jeu.

Structures sérialisables

Je crois que la première tentative pour s'attaquer à ce système consiste à utiliser une structure sérialisable qui encapsule les propriétés des éléments. Appelons-le ItemStruct. Ensuite, vous ajouteriez une liste d'ItemStruct dans le marchand.

Ainsi, via l'inspecteur, le game designer peut saisir manuellement chacun de ces éléments tout en vous laissant programmer les autres systèmes du jeu. Le code et l'inspecteur d'un tel système peuvent être vus ci-dessous :

[Serializable]
public struct ItemStruct
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;
}

Exemple d'inspecteur de structure d'élément

Cette approche est en fait assez polyvalente et, pour de nombreux systèmes simples, c'est certainement la méthode la plus simple et la plus stable.

Les structures sérialisables offrent un moyen simple d'apporter des modifications via l'inspecteur, tout en utilisant les avantages d'être une structure en C #, comme étant plus adéquates pour une agrégation de données plus petite par rapport aux classes, et pour avoir une sémantique de valeur.

Cependant, votre système marchand autorise différents marchands à travers le monde du jeu.

L'un d'eux, dans la zone de départ, est censé vendre des potions de bas niveau et des buffs temporaires faibles. Afin de soutenir les joueurs plus lents, les zones les plus avancées du jeu ont des marchands qui vendent toujours des potions de départ qui coûtent moins cher que leurs alternatives de niveau supérieur.

 

Le problème avec l'approche ItemStruct

Si l'on s'en tient à l'approche ItemStruct, c'est probablement le cas maintenant que les différentes instances des marchands ont maintenant des copies des mêmes ItemStructs.

Si vous avez déjà haussé un sourcil, préparez-vous à lever l'autre, car il y a de fortes chances que votre concepteur de jeu essaie, à un moment donné, d'équilibrer le jeu et d'accorder une réduction à toutes les potions de bas niveau. Étant donné que les ItemStructs ne sont pas connectés les uns aux autres, chaque instance de chaque marchand qui les vend doit être mise à jour. Applaudissements de ma part si vous utilisez déjà des préfabriqués et des variantes de préfabriqués , mais ils ont tous encore besoin d'être mis à jour.

L'achat est l'une des difficultés de la programmation de ces objets, mais considérez que le jeu comporte également des combats. Vaincre des ennemis rapporte du butin, comme des potions.

Il devrait être clair que la solution que nous recherchons consiste à détacher l'ItemStruct des marchands (et d'autres mécanismes) et à laisser chacun d'eux utiliser une référence à celui-ci.

Ainsi, toute modification apportée à l'ItemStruct affectera immédiatement ceux qui s'y réfèrent. Heureusement, Unity offre un moyen simple de le faire : des objets scriptables.

Utilisation d'objets scriptables

Les objets inscriptibles sont des objets contenant des données dans Unity qui n'ont pas besoin d'être attachés aux objets du jeu.

Ainsi, nous pouvons les créer sans les ajouter à un objet de notre scène ou à un préfabriqué. Ils existent par eux-mêmes et toute entité qui les utilise utilise une référence.

Les objets inscriptibles n'héritent pas de MonoBehavior, la classe par défaut des scripts Unity, mais ils ont des comportements analogues et peuvent être utilisés de la même manière.

Par exemple, ils ont leur appel Awake , ainsi que OnEnable et OnDisable. Ils peuvent avoir leurs méthodes et leurs variables membres, ainsi que bénéficier de l'utilisation des attributs.

De plus, ils sont aussi faciles à créer que les scripts de comportement mono réguliers :

[CreateAssetMenu(fileName = "New Item", menuName = "Item", order = 0)]
public class ItemScriptableObject : ScriptableObject
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;
}

Objet inscriptible d'élément

Comme vous l'avez vu dans l'exemple ci-dessus, pour augmenter l'efficacité de la création d'instances d'un objet scriptable, nous pouvons utiliser le CreateAssetMenuAttributepour ajouter un menu d'éditeur qui génère des fichiers de ce type.

Détacher les données des objets du jeu

Pour en revenir au problème dont nous avons discuté précédemment avec le détachement des ItemStructs des éléments du jeu, une solution simple consiste maintenant à remplacer ItemStructs par ItemScriptableObject. Chaque marchand détient une liste des ItemScriptableObjects qu'il vend.

Toute remise ou augmentation des prix d'un article est désormais appliquée à l'article lui-même. Le changement est immédiatement reflété dans toute entité qui s'y réfère. Que le game designer se réjouisse maintenant d' équilibrer l'économie du jeu.

De plus, d'autres mécanismes, tels que les largages d'objets de monstres ou le pillage de coffres au trésor, en bénéficient tout autant. Vous pouvez même aller plus loin et utiliser les mêmes objets scriptables pour concevoir un système d'inventaire ou un système d'artisanat.

L'objet scriptable que nous avons conçu comme exemple peut être facilement étendu pour contenir d'autres données, telles que l'image qu'il affiche sur l'interface utilisateur ou un type de fabrication.

Sur ce point, il existe deux extensions intéressantes que nous pouvons faire avec des objets scriptables qui méritent d'être mentionnées : Inheritance et CustomEditorScripts.

Développement d'objets scriptables

Commençons par l'héritage. Les objets inscriptibles héritent de la classe de base Object ; ainsi, ils peuvent être utilisés dans n'importe quel contexte, une classe C# standard peut être utilisée.

Cela signifie que nous pouvons avoir des objets scriptables abstraits et les utiliser pour modéliser le comportement, en bénéficiant de tous ces bons vieux avantages de la programmation orientée objet tels que l'abstraction de données et le polymorphisme.

Par exemple, nous pourrions avoir un objet scriptable abstrait pour les éléments de notre jeu, qui contient des informations standard telles que le nom, le coût et l'image d'affichage. Il contiendrait également une méthode abstraite Use( ). Ensuite, chaque type d'élément peut spécifier ce qu'il fait lorsqu'il est utilisé.

Ensuite, nous pourrions créer un objet scriptable concret pour les Potions, qui étend Item. L'objet scriptable Potions hérite des variables membres de sa classe parente et est obligé d'implémenter la Useméthode.

À partir de là, nous pourrions même ramifier davantage la hiérarchie en créant une extension HealthPotion ou une RejuvenationPotion afin que la Useméthode ait une implémentation plus précise et nous ajoutons des variables membres qui répondent mieux aux besoins de chaque type.

Vous vous êtes peut-être arrêté maintenant pour vous demander pourquoi nous n'aurions pas pu le faire auparavant, car il s'agit d'une pratique standard de programmation orientée objet.

Le fait est que nous avons toujours pu et c'est la beauté de l'utilisation d'objets scriptables : nous n'avons pas besoin de changer la façon dont nous modélisons nos systèmes. L'avantage est maintenant que nous pouvons créer des instances pour nos données détachées des systèmes eux-mêmes.

De plus, nous pouvons implémenter nos systèmes pour qu'ils soient basés sur des éléments, comme nous l'avons noté, même si notre concepteur de jeu ajoute maintenant les données pour le type LegendarySwordScriptableObject.

public abstract class ItemScriptableObject : ScriptableObject
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;

   public abstract void Use();
}[CreateAssetMenu(fileName = "New Potion", menuName = "Items/Potion", order = 0)]
public class PotionScriptableObject : ItemScriptableObject
{
   public override void Use()
   {
       //Do Something
   }
}

Utilisation de scripts d'éditeur personnalisés

L'autre aspect que j'ai soulevé auparavant était l'autonomisation des objets scriptables avec des scripts d'éditeur personnalisés. Les scripts d'éditeur personnalisés nous permettent de modifier et d'ajouter des comportements à la façon dont une certaine entité est affichée dans l'inspecteur Unity.

Ils sont couramment utilisés dans les scripts MonoBehavior réguliers pour ajouter des boutons ou pour afficher des étiquettes, et généralement pour accélérer le développement.

Les ScriptableObjects peuvent également être étendus avec leurs propres scripts d'éditeur personnalisés, ce qui en fait de puissants outils d'édition directement dans l'inspecteur et, encore une fois, détachés des autres entités.

Par exemple, nous avons suggéré que notre objet scriptable Item puisse contenir son image d'affichage. Avec des scripts d'éditeur personnalisés, nous pourrions afficher l'image sélectionnée directement dans l'inspecteur pour faciliter la vérification si les bons sprites sont utilisés.

Spécifiquement pour les potions, nous pourrions ajouter un bouton qui imprime le résultat de l'utilisation de la potion compte tenu de ses attributs, pour évaluer rapidement si ses résultats sont appropriés.

[CustomEditor(typeof(PotionScriptableObject))]
public class PotionScriptableObjectEditor : UnityEditor.Editor
{
   public override void OnInspectorGUI()
   {
       base.OnInspectorGUI();

       var potionScriptableObject = (PotionScriptableObject) target;
       if (potionScriptableObject.image == null) return;
       GUILayout.Box(potionScriptableObject.image.texture);

       if (GUILayout.Button("Test Use"))
       {
           potionScriptableObject.Use();
       }
   }
}

Exemple d'objet inscriptible Potion
(Remarque : les sprites utilisés ici sont issus du Mega Pack 2D pour Brackeys)

Avantages supplémentaires des objets scriptables

Ajuster les valeurs d'un objet scriptable, en utilisant ou non un script d'éditeur personnalisé, présente un autre avantage par rapport aux scripts MonoBehavior classiques : ils sont persistants entre l'éditeur et le mode de lecture.

Cela signifie que si vous modifiez un objet inscriptible tout en testant le jeu en mode de jeu, les modifications sont enregistrées dans l'objet inscriptible et persistent dans le mode éditeur.

Notez que ce n'est pas le cas pour la persistance entre les instances d'un jeu construit, c'est-à-dire que vous ne devez pas utiliser d'objets scriptables comme alternative à votre système de sauvegarde.

De plus, les modifications apportées aux objets scriptables persistent également entre les scènes. Cet avantage offre une meilleure alternative aux singletons lors du transfert d'informations entre les scènes et les états du jeu.

Par exemple, vous pouvez stocker les informations de votre joueur telles que la santé et l'expérience dans un objet scriptable et les faire référencer par les multiples systèmes de votre jeu.

Si votre personnage perd de la santé dans une scène de combat puis revient sur la carte du monde, les modifications apportées à la santé sont conservées dans l'objet scriptable et n'ont pas besoin d'être partagées via d'autres mécanismes, comme un PlayerManager marqué pour ne pas être détruit lors du chargement nouvelles scènes.

Cependant, il existe même une autre utilisation des objets scriptables qui semble assez contre-intuitive : les objets scriptables sans données.

Transmutation d'objets scriptables

Les instances d'objet inscriptible sont uniques par défaut puisque chacune d'entre elles contiendra un GUID.

Ainsi, plusieurs références à une instance d'un objet scriptable doivent obligatoirement utiliser la bonne, d'autant plus qu'elles sont très probablement liées dans l'inspecteur à leurs détenteurs de référence correspondants.

D'un autre côté, on pourrait aussi profiter de cette propriété pour comparer des objets scriptables, soit par leur contenu (en remplaçant la méthode Equals par exemple) soit par leurs identifiants.

Cela leur permet également d'être d'excellentes clés pour les dictionnaires et autres structures de données basées sur des clés.

Alternatives d'objets inscriptibles

Comme je l'ai laissé entendre précédemment, nous pourrions utiliser des objets scriptables uniquement dans le but d'être des clés, mais en conservant tous leurs avantages. Considérez, par exemple, que pour le système de marché mondial de votre jeu, vous souhaitez spécifier un dictionnaire qui relie les marchands à leurs villes correspondantes.

Chaque marchand ne peut être lié qu'à une seule ville et les villes peuvent héberger plusieurs marchands. Qu'utiliseriez-vous pour faire le lien entre le commerçant et la ville ? Un string? Une énumération ?

Comme vous l'avez peut-être deviné, un objet scriptable CityScriptableObject, par exemple, pourrait facilement résoudre ce dilemme.

Discutons d'abord des alternatives.

Chaîne de caractères

Une chaîne est liée aux fautes de frappe et autres erreurs, en plus d'être très inefficace pour la maintenance et les mises à jour (une ville a changé de nom en cours de développement en raison d'une dispute entre les auteurs du jeu, par exemple). La comparaison de chaînes n'est pas non plus très efficace.

Énumération

Une énumération fonctionne très bien, mais des changements dans la base de code doivent être effectués pour chaque nouvel ajout. De plus, cela peut être catastrophique si vous supprimez une entrée dans l'énumération et que vous devez corriger tout le code qui y fait référence (une ville a été détruite maintenant en raison d'une autre dispute entre les auteurs du jeu - ces gens-là !).

Pourquoi les objets scriptables sont bénéfiques

D'autre part, l'instance d'objet inscriptible peut être créée dans la vue du projet (aucun code n'est nécessaire) et elle peut être référencée en tant qu'objet normal dans le code, au lieu de s'appuyer sur des instructions switch et d'autres structures de flux de contrôle qui spécifient le entrées possibles.

Comme présenté précédemment, ce même objet scriptable peut être développé davantage en ajoutant simplement de nouveaux champs et méthodes. Si nous avons besoin d'une clé pour faire référence à une ville, notre objet scriptable peut être vide et utiliser le nom de fichier de l'actif lui-même comme clé (il a de toute façon un GUID).

Mais, si plus tard nous voulons que le commerçant utilise son nom de ville dans l'interface utilisateur, nous pouvons facilement l'ajouter en tant que propriété à l'intérieur du code CityScriptableObject et cela n'a aucun effet collatéral sur toute autre partie du code.

Si vous pensez maintenant à la façon dont cela semble être une utilisation assez peu orthodoxe des objets scriptables, rappelez-vous que cette pratique a été initialement proposée par Richard Fine, un employé de Unity Technologies lui-même, et a été validée par de nombreux autres développeurs de la communauté.

La mise en œuvre d'un système qui utilise des objets scriptables au lieu d'énumérations n'est pas très différente de la mise en œuvre d'un système qui utilise un système de clé fait maison.

Les entités contiendront des références aux objets scriptables et les systèmes utiliseront ces objets scriptables à des fins de comparaison et même utiliseront leurs propres méthodes membres. Vous souvenez-vous de notre Useméthode ? L'extrait du code ci-dessous devrait vous aider à envisager une approche possible de cette stratégie.

[UnityEngine.CreateAssetMenu(fileName = "New Magic Element", menuName = "Magic/Magic Element", order = 0)]

public class MagicElementScriptableObject : UnityEngine.ScriptableObject
{
//Nothing 
}public class MagicPotionScriptableObject : PotionScriptableObject
{
   public MagicElementScriptableObject magicElement;
   public int increaseBy;
  
   public override void Use()
   {   
character.IncreaseMagicElementPower(magicElement, increaseBy);
   }public class Character
{
   public Dictionary<MagicElementScriptableObject, int> magicElements;
  
   public void IncreaseMagicElementPower (MagicElementScriptableObject magicElement, int value)
   {
magicElements[magicElement] += value;
   }
}

Jugement des objets scriptables

Avec leur grande flexibilité et leur simplicité, les objets scriptables offrent de nombreuses nouvelles approches des systèmes, de la persistance, du stockage des données et même comme substituts des singletons et des énumérations.

Comme indiqué précédemment, en raison de leur héritage, leur comportement est similaire à de nombreux autres composants auxquels nous sommes déjà habitués, ce qui rend le processus de démarrage de leur utilisation plus accessible.

Certes, toutes les bonnes choses ont un coût - certaines des approches discutées précédemment pourraient également être mises en œuvre avec différentes techniques qui pourraient atteindre un niveau de performance ou de stabilité plus élevé pour la base de code.

Souplesse

La flexibilité d'utiliser des objets scriptables pour remplacer les énumérations peut être trop peu orthodoxe et donner des rendements décroissants une fois que votre jeu est déjà bien établi. Il peut alors être temps d'effectuer une substitution inverse et de récupérer les énumérations pour leurs avantages.

Notez que cela ne se produira probablement qu'après de longues séances de remue-méninges et de tests de jeu pendant les étapes de prototypage.

Performance

En termes de performances, les objets scriptables se comportent comme un objet C#. Leur impact sur les performances pourrait être perçu lors de leur sérialisation au démarrage du jeu et de la désérialisation lors de leur sauvegarde sur un disque.

Cependant, comme ils sont essentiellement implémentés sous forme de fichiers YAML, le coût des deux opérations est essentiellement le même que si vous le faisiez avec un fichier JSON standard. Dans un sens, l'utilisation d'objets scriptables sera aussi lourde en termes de performances que la plupart de vos autres stratégies de développement piloté par les données.

Il convient de mentionner que si vous enregistrez systématiquement des données dans un objet inscriptible et que vous souhaitez qu'elles soient enregistrées sur le disque immédiatement, vous devrez peut-être appeler l'API Unity via l' AssetDatabase.SaveAssets appel , par exemple.

Conclusion

En plus de tout cela, il reste encore beaucoup de place pour l'expérimentation et la conception. Les objets inscriptibles peuvent être des outils utiles dans les ensembles d'exécution, qui aident à garder une trace des informations entre les entités en partageant le même objet inscriptible, éliminant ainsi le besoin d'un singleton intermédiaire.

Dans le contexte de la réalité mixte (MR), une boîte à outils pour MR qui utilise des objets scriptables a été développée comme une couche pour coder des séquences, des instructions et même des questionnaires pour un outil de formation.

Augmentez la liberté et la polyvalence de la conception de votre jeu et accélérez votre phase de prototype. La pire chose qui puisse arriver est qu'une fois que votre jeu est stable et amusant, vous devrez peut-être refactoriser certaines parties du système, ce qui est sans aucun doute bien mieux que d'optimiser un cadre pour un jeu ennuyeux ou sans intérêt.

Merci d'avoir lu et faites-moi savoir si vous souhaitez des stratégies Unity plus peu orthodoxes pour un développement et un prototypage rapides. Vous pouvez voir plus de mon travail ici

Source : https://blog.logrocket.com/fast-prototyping-unity-scriptable-objects/

#unity 

What is GEEK

Buddha Community

Comment Utiliser Des Objets Scriptables Dans Unity

Comment Utiliser Des Objets Scriptables Dans Unity

Considérez que vous développez un système marchand pour votre jeu dans Unity, où le marchand vend une liste d'articles avec un nom, un prix, une description et une image différents.

Le concepteur de jeu de votre équipe a déjà rédigé un document de 100 pages sur divers objets avec un chapitre entier consacré aux multiples types de potions. En tant que programmeur principal, vous devez décider où stocker chacun de ces éléments dans votre système, alors où le feriez-vous ?

Dans cet article, nous allons explorer le prototypage rapide dans Unity et la façon dont vous pouvez utiliser efficacement les objets scriptables dans le développement de votre jeu.

Structures sérialisables

Je crois que la première tentative pour s'attaquer à ce système consiste à utiliser une structure sérialisable qui encapsule les propriétés des éléments. Appelons-le ItemStruct. Ensuite, vous ajouteriez une liste d'ItemStruct dans le marchand.

Ainsi, via l'inspecteur, le game designer peut saisir manuellement chacun de ces éléments tout en vous laissant programmer les autres systèmes du jeu. Le code et l'inspecteur d'un tel système peuvent être vus ci-dessous :

[Serializable]
public struct ItemStruct
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;
}

Exemple d'inspecteur de structure d'élément

Cette approche est en fait assez polyvalente et, pour de nombreux systèmes simples, c'est certainement la méthode la plus simple et la plus stable.

Les structures sérialisables offrent un moyen simple d'apporter des modifications via l'inspecteur, tout en utilisant les avantages d'être une structure en C #, comme étant plus adéquates pour une agrégation de données plus petite par rapport aux classes, et pour avoir une sémantique de valeur.

Cependant, votre système marchand autorise différents marchands à travers le monde du jeu.

L'un d'eux, dans la zone de départ, est censé vendre des potions de bas niveau et des buffs temporaires faibles. Afin de soutenir les joueurs plus lents, les zones les plus avancées du jeu ont des marchands qui vendent toujours des potions de départ qui coûtent moins cher que leurs alternatives de niveau supérieur.

 

Le problème avec l'approche ItemStruct

Si l'on s'en tient à l'approche ItemStruct, c'est probablement le cas maintenant que les différentes instances des marchands ont maintenant des copies des mêmes ItemStructs.

Si vous avez déjà haussé un sourcil, préparez-vous à lever l'autre, car il y a de fortes chances que votre concepteur de jeu essaie, à un moment donné, d'équilibrer le jeu et d'accorder une réduction à toutes les potions de bas niveau. Étant donné que les ItemStructs ne sont pas connectés les uns aux autres, chaque instance de chaque marchand qui les vend doit être mise à jour. Applaudissements de ma part si vous utilisez déjà des préfabriqués et des variantes de préfabriqués , mais ils ont tous encore besoin d'être mis à jour.

L'achat est l'une des difficultés de la programmation de ces objets, mais considérez que le jeu comporte également des combats. Vaincre des ennemis rapporte du butin, comme des potions.

Il devrait être clair que la solution que nous recherchons consiste à détacher l'ItemStruct des marchands (et d'autres mécanismes) et à laisser chacun d'eux utiliser une référence à celui-ci.

Ainsi, toute modification apportée à l'ItemStruct affectera immédiatement ceux qui s'y réfèrent. Heureusement, Unity offre un moyen simple de le faire : des objets scriptables.

Utilisation d'objets scriptables

Les objets inscriptibles sont des objets contenant des données dans Unity qui n'ont pas besoin d'être attachés aux objets du jeu.

Ainsi, nous pouvons les créer sans les ajouter à un objet de notre scène ou à un préfabriqué. Ils existent par eux-mêmes et toute entité qui les utilise utilise une référence.

Les objets inscriptibles n'héritent pas de MonoBehavior, la classe par défaut des scripts Unity, mais ils ont des comportements analogues et peuvent être utilisés de la même manière.

Par exemple, ils ont leur appel Awake , ainsi que OnEnable et OnDisable. Ils peuvent avoir leurs méthodes et leurs variables membres, ainsi que bénéficier de l'utilisation des attributs.

De plus, ils sont aussi faciles à créer que les scripts de comportement mono réguliers :

[CreateAssetMenu(fileName = "New Item", menuName = "Item", order = 0)]
public class ItemScriptableObject : ScriptableObject
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;
}

Objet inscriptible d'élément

Comme vous l'avez vu dans l'exemple ci-dessus, pour augmenter l'efficacité de la création d'instances d'un objet scriptable, nous pouvons utiliser le CreateAssetMenuAttributepour ajouter un menu d'éditeur qui génère des fichiers de ce type.

Détacher les données des objets du jeu

Pour en revenir au problème dont nous avons discuté précédemment avec le détachement des ItemStructs des éléments du jeu, une solution simple consiste maintenant à remplacer ItemStructs par ItemScriptableObject. Chaque marchand détient une liste des ItemScriptableObjects qu'il vend.

Toute remise ou augmentation des prix d'un article est désormais appliquée à l'article lui-même. Le changement est immédiatement reflété dans toute entité qui s'y réfère. Que le game designer se réjouisse maintenant d' équilibrer l'économie du jeu.

De plus, d'autres mécanismes, tels que les largages d'objets de monstres ou le pillage de coffres au trésor, en bénéficient tout autant. Vous pouvez même aller plus loin et utiliser les mêmes objets scriptables pour concevoir un système d'inventaire ou un système d'artisanat.

L'objet scriptable que nous avons conçu comme exemple peut être facilement étendu pour contenir d'autres données, telles que l'image qu'il affiche sur l'interface utilisateur ou un type de fabrication.

Sur ce point, il existe deux extensions intéressantes que nous pouvons faire avec des objets scriptables qui méritent d'être mentionnées : Inheritance et CustomEditorScripts.

Développement d'objets scriptables

Commençons par l'héritage. Les objets inscriptibles héritent de la classe de base Object ; ainsi, ils peuvent être utilisés dans n'importe quel contexte, une classe C# standard peut être utilisée.

Cela signifie que nous pouvons avoir des objets scriptables abstraits et les utiliser pour modéliser le comportement, en bénéficiant de tous ces bons vieux avantages de la programmation orientée objet tels que l'abstraction de données et le polymorphisme.

Par exemple, nous pourrions avoir un objet scriptable abstrait pour les éléments de notre jeu, qui contient des informations standard telles que le nom, le coût et l'image d'affichage. Il contiendrait également une méthode abstraite Use( ). Ensuite, chaque type d'élément peut spécifier ce qu'il fait lorsqu'il est utilisé.

Ensuite, nous pourrions créer un objet scriptable concret pour les Potions, qui étend Item. L'objet scriptable Potions hérite des variables membres de sa classe parente et est obligé d'implémenter la Useméthode.

À partir de là, nous pourrions même ramifier davantage la hiérarchie en créant une extension HealthPotion ou une RejuvenationPotion afin que la Useméthode ait une implémentation plus précise et nous ajoutons des variables membres qui répondent mieux aux besoins de chaque type.

Vous vous êtes peut-être arrêté maintenant pour vous demander pourquoi nous n'aurions pas pu le faire auparavant, car il s'agit d'une pratique standard de programmation orientée objet.

Le fait est que nous avons toujours pu et c'est la beauté de l'utilisation d'objets scriptables : nous n'avons pas besoin de changer la façon dont nous modélisons nos systèmes. L'avantage est maintenant que nous pouvons créer des instances pour nos données détachées des systèmes eux-mêmes.

De plus, nous pouvons implémenter nos systèmes pour qu'ils soient basés sur des éléments, comme nous l'avons noté, même si notre concepteur de jeu ajoute maintenant les données pour le type LegendarySwordScriptableObject.

public abstract class ItemScriptableObject : ScriptableObject
{
   public string name;
   public int price;
   [TextArea]
   public string description;
   public Sprite image;

   public abstract void Use();
}[CreateAssetMenu(fileName = "New Potion", menuName = "Items/Potion", order = 0)]
public class PotionScriptableObject : ItemScriptableObject
{
   public override void Use()
   {
       //Do Something
   }
}

Utilisation de scripts d'éditeur personnalisés

L'autre aspect que j'ai soulevé auparavant était l'autonomisation des objets scriptables avec des scripts d'éditeur personnalisés. Les scripts d'éditeur personnalisés nous permettent de modifier et d'ajouter des comportements à la façon dont une certaine entité est affichée dans l'inspecteur Unity.

Ils sont couramment utilisés dans les scripts MonoBehavior réguliers pour ajouter des boutons ou pour afficher des étiquettes, et généralement pour accélérer le développement.

Les ScriptableObjects peuvent également être étendus avec leurs propres scripts d'éditeur personnalisés, ce qui en fait de puissants outils d'édition directement dans l'inspecteur et, encore une fois, détachés des autres entités.

Par exemple, nous avons suggéré que notre objet scriptable Item puisse contenir son image d'affichage. Avec des scripts d'éditeur personnalisés, nous pourrions afficher l'image sélectionnée directement dans l'inspecteur pour faciliter la vérification si les bons sprites sont utilisés.

Spécifiquement pour les potions, nous pourrions ajouter un bouton qui imprime le résultat de l'utilisation de la potion compte tenu de ses attributs, pour évaluer rapidement si ses résultats sont appropriés.

[CustomEditor(typeof(PotionScriptableObject))]
public class PotionScriptableObjectEditor : UnityEditor.Editor
{
   public override void OnInspectorGUI()
   {
       base.OnInspectorGUI();

       var potionScriptableObject = (PotionScriptableObject) target;
       if (potionScriptableObject.image == null) return;
       GUILayout.Box(potionScriptableObject.image.texture);

       if (GUILayout.Button("Test Use"))
       {
           potionScriptableObject.Use();
       }
   }
}

Exemple d'objet inscriptible Potion
(Remarque : les sprites utilisés ici sont issus du Mega Pack 2D pour Brackeys)

Avantages supplémentaires des objets scriptables

Ajuster les valeurs d'un objet scriptable, en utilisant ou non un script d'éditeur personnalisé, présente un autre avantage par rapport aux scripts MonoBehavior classiques : ils sont persistants entre l'éditeur et le mode de lecture.

Cela signifie que si vous modifiez un objet inscriptible tout en testant le jeu en mode de jeu, les modifications sont enregistrées dans l'objet inscriptible et persistent dans le mode éditeur.

Notez que ce n'est pas le cas pour la persistance entre les instances d'un jeu construit, c'est-à-dire que vous ne devez pas utiliser d'objets scriptables comme alternative à votre système de sauvegarde.

De plus, les modifications apportées aux objets scriptables persistent également entre les scènes. Cet avantage offre une meilleure alternative aux singletons lors du transfert d'informations entre les scènes et les états du jeu.

Par exemple, vous pouvez stocker les informations de votre joueur telles que la santé et l'expérience dans un objet scriptable et les faire référencer par les multiples systèmes de votre jeu.

Si votre personnage perd de la santé dans une scène de combat puis revient sur la carte du monde, les modifications apportées à la santé sont conservées dans l'objet scriptable et n'ont pas besoin d'être partagées via d'autres mécanismes, comme un PlayerManager marqué pour ne pas être détruit lors du chargement nouvelles scènes.

Cependant, il existe même une autre utilisation des objets scriptables qui semble assez contre-intuitive : les objets scriptables sans données.

Transmutation d'objets scriptables

Les instances d'objet inscriptible sont uniques par défaut puisque chacune d'entre elles contiendra un GUID.

Ainsi, plusieurs références à une instance d'un objet scriptable doivent obligatoirement utiliser la bonne, d'autant plus qu'elles sont très probablement liées dans l'inspecteur à leurs détenteurs de référence correspondants.

D'un autre côté, on pourrait aussi profiter de cette propriété pour comparer des objets scriptables, soit par leur contenu (en remplaçant la méthode Equals par exemple) soit par leurs identifiants.

Cela leur permet également d'être d'excellentes clés pour les dictionnaires et autres structures de données basées sur des clés.

Alternatives d'objets inscriptibles

Comme je l'ai laissé entendre précédemment, nous pourrions utiliser des objets scriptables uniquement dans le but d'être des clés, mais en conservant tous leurs avantages. Considérez, par exemple, que pour le système de marché mondial de votre jeu, vous souhaitez spécifier un dictionnaire qui relie les marchands à leurs villes correspondantes.

Chaque marchand ne peut être lié qu'à une seule ville et les villes peuvent héberger plusieurs marchands. Qu'utiliseriez-vous pour faire le lien entre le commerçant et la ville ? Un string? Une énumération ?

Comme vous l'avez peut-être deviné, un objet scriptable CityScriptableObject, par exemple, pourrait facilement résoudre ce dilemme.

Discutons d'abord des alternatives.

Chaîne de caractères

Une chaîne est liée aux fautes de frappe et autres erreurs, en plus d'être très inefficace pour la maintenance et les mises à jour (une ville a changé de nom en cours de développement en raison d'une dispute entre les auteurs du jeu, par exemple). La comparaison de chaînes n'est pas non plus très efficace.

Énumération

Une énumération fonctionne très bien, mais des changements dans la base de code doivent être effectués pour chaque nouvel ajout. De plus, cela peut être catastrophique si vous supprimez une entrée dans l'énumération et que vous devez corriger tout le code qui y fait référence (une ville a été détruite maintenant en raison d'une autre dispute entre les auteurs du jeu - ces gens-là !).

Pourquoi les objets scriptables sont bénéfiques

D'autre part, l'instance d'objet inscriptible peut être créée dans la vue du projet (aucun code n'est nécessaire) et elle peut être référencée en tant qu'objet normal dans le code, au lieu de s'appuyer sur des instructions switch et d'autres structures de flux de contrôle qui spécifient le entrées possibles.

Comme présenté précédemment, ce même objet scriptable peut être développé davantage en ajoutant simplement de nouveaux champs et méthodes. Si nous avons besoin d'une clé pour faire référence à une ville, notre objet scriptable peut être vide et utiliser le nom de fichier de l'actif lui-même comme clé (il a de toute façon un GUID).

Mais, si plus tard nous voulons que le commerçant utilise son nom de ville dans l'interface utilisateur, nous pouvons facilement l'ajouter en tant que propriété à l'intérieur du code CityScriptableObject et cela n'a aucun effet collatéral sur toute autre partie du code.

Si vous pensez maintenant à la façon dont cela semble être une utilisation assez peu orthodoxe des objets scriptables, rappelez-vous que cette pratique a été initialement proposée par Richard Fine, un employé de Unity Technologies lui-même, et a été validée par de nombreux autres développeurs de la communauté.

La mise en œuvre d'un système qui utilise des objets scriptables au lieu d'énumérations n'est pas très différente de la mise en œuvre d'un système qui utilise un système de clé fait maison.

Les entités contiendront des références aux objets scriptables et les systèmes utiliseront ces objets scriptables à des fins de comparaison et même utiliseront leurs propres méthodes membres. Vous souvenez-vous de notre Useméthode ? L'extrait du code ci-dessous devrait vous aider à envisager une approche possible de cette stratégie.

[UnityEngine.CreateAssetMenu(fileName = "New Magic Element", menuName = "Magic/Magic Element", order = 0)]

public class MagicElementScriptableObject : UnityEngine.ScriptableObject
{
//Nothing 
}public class MagicPotionScriptableObject : PotionScriptableObject
{
   public MagicElementScriptableObject magicElement;
   public int increaseBy;
  
   public override void Use()
   {   
character.IncreaseMagicElementPower(magicElement, increaseBy);
   }public class Character
{
   public Dictionary<MagicElementScriptableObject, int> magicElements;
  
   public void IncreaseMagicElementPower (MagicElementScriptableObject magicElement, int value)
   {
magicElements[magicElement] += value;
   }
}

Jugement des objets scriptables

Avec leur grande flexibilité et leur simplicité, les objets scriptables offrent de nombreuses nouvelles approches des systèmes, de la persistance, du stockage des données et même comme substituts des singletons et des énumérations.

Comme indiqué précédemment, en raison de leur héritage, leur comportement est similaire à de nombreux autres composants auxquels nous sommes déjà habitués, ce qui rend le processus de démarrage de leur utilisation plus accessible.

Certes, toutes les bonnes choses ont un coût - certaines des approches discutées précédemment pourraient également être mises en œuvre avec différentes techniques qui pourraient atteindre un niveau de performance ou de stabilité plus élevé pour la base de code.

Souplesse

La flexibilité d'utiliser des objets scriptables pour remplacer les énumérations peut être trop peu orthodoxe et donner des rendements décroissants une fois que votre jeu est déjà bien établi. Il peut alors être temps d'effectuer une substitution inverse et de récupérer les énumérations pour leurs avantages.

Notez que cela ne se produira probablement qu'après de longues séances de remue-méninges et de tests de jeu pendant les étapes de prototypage.

Performance

En termes de performances, les objets scriptables se comportent comme un objet C#. Leur impact sur les performances pourrait être perçu lors de leur sérialisation au démarrage du jeu et de la désérialisation lors de leur sauvegarde sur un disque.

Cependant, comme ils sont essentiellement implémentés sous forme de fichiers YAML, le coût des deux opérations est essentiellement le même que si vous le faisiez avec un fichier JSON standard. Dans un sens, l'utilisation d'objets scriptables sera aussi lourde en termes de performances que la plupart de vos autres stratégies de développement piloté par les données.

Il convient de mentionner que si vous enregistrez systématiquement des données dans un objet inscriptible et que vous souhaitez qu'elles soient enregistrées sur le disque immédiatement, vous devrez peut-être appeler l'API Unity via l' AssetDatabase.SaveAssets appel , par exemple.

Conclusion

En plus de tout cela, il reste encore beaucoup de place pour l'expérimentation et la conception. Les objets inscriptibles peuvent être des outils utiles dans les ensembles d'exécution, qui aident à garder une trace des informations entre les entités en partageant le même objet inscriptible, éliminant ainsi le besoin d'un singleton intermédiaire.

Dans le contexte de la réalité mixte (MR), une boîte à outils pour MR qui utilise des objets scriptables a été développée comme une couche pour coder des séquences, des instructions et même des questionnaires pour un outil de formation.

Augmentez la liberté et la polyvalence de la conception de votre jeu et accélérez votre phase de prototype. La pire chose qui puisse arriver est qu'une fois que votre jeu est stable et amusant, vous devrez peut-être refactoriser certaines parties du système, ce qui est sans aucun doute bien mieux que d'optimiser un cadre pour un jeu ennuyeux ou sans intérêt.

Merci d'avoir lu et faites-moi savoir si vous souhaitez des stratégies Unity plus peu orthodoxes pour un développement et un prototypage rapides. Vous pouvez voir plus de mon travail ici

Source : https://blog.logrocket.com/fast-prototyping-unity-scriptable-objects/

#unity 

Nora Joy

1607328200

Why unity 3D is best for game app development

We can see an exponential growth in the game development industry today and the market for game development will increase day by day ,thanks to the increasing number of smartphone users and the technological advancements.Unity 3D is the trending game app development framework to serve the best quality.This game development framework enables developers to conduct 2D or 3D rendering with more than 1 mobile game to assist them in ratcheting. Apart from this the great qualities like cross-platform integration with asset management, high-end visual quality, intuitive design, interface flexibility and gameplay can now be leveraged.India is the leading game development hub and now people are** hire dedicated unity 3D developers in India** to create a high performing game app with best quality at affordable price which you can spread your games to larger audience.Lets have a look at why unity a 3D is the best platform for game development.
**
Support cross-platform**

Cross platforms save time and money as a single script can be compiled and used for multiple platforms such as Android, iOS, PC, Web and even Mac etcFeatures such as agile methodology allow speedy prototyping and constant releases to speed up the process of game development.

Open source

The large open source community of Unity 3D with an easy-to-understand documentation allows developers to come up with the most accurate and precise code and it saves a lot of time.

Graphics

Unity 3D can support graphic rendering from engines that use OpenGL ES, OpenGL and Direct 3D, as well as applications like 3DS Max, Blender and Adobe Photoshop. It enables high-quality audio and visual effects to be adapted without any distortion or compromise with quality.
**
Play mode feature
**
This feature allows easy and hassle free testing by allowing developers to look and play within the game instantly, evaluate and even review it,and also the Play or Play Plus mode can also be used to achieve frame to frame referencing.

Debugging

With Unity game development, the analysis and modification is incredibly easier as all the game factors are seen during ongoing interaction, which helps the engineers to troubleshoot the process at runtime.

These advantages make unity as the best game development platform and people h**ire dedicated unity 3D developers** for the best output.With Unity, countless games have been made and some of them have become instant classics.Take a look at some of the all-time trending Unity games .

  • Kerbal Space Program

  • Firewatch

  • Subnautica

  • Hollow Knight

  • Arizona Sunshine

  • Cuphead

  • Ori And The Blind Forest

  • Hearthstone

  • Beat Saber

  • Cities Skylines

  • Getting Over It With Bennett Foddy
    In terms of graphics, gameplay, consistency and realism, technical advances and rise of new technologies like AR & VR and AI & ML make the game more ambitious day by day.Today the entire global game development is booming and mobile gaming business are hire unity 3D developers in India to meet this heavy market.**Hire dedicated unity 3D developers **will benefits the following,

  • International standard game app development at lower cost.

  • Skilled and experienced game developers

  • Faster time to market

  • Best infrastructure

Conclusion

Unity 3D has taken over the business and has altered the advancement of cross-platform app development paths. Unity 3D has already become the favourite of developers as they can import games created from iOS, PC, Play Store or other game consoles from other platforms and allow minimum game modifications to take full advantage of Unity 3D’s features. So if you have any game development hire unity 3D developers with great experience.

#hire unity 3 d developers in india #hire dedicated unity 3 d developers in india #hire unity 3 d programmers in india #hire unity 3 d developers #hire dedicated unity 3 d developers #hire unity 3 d programmers

The  NineHertz

The NineHertz

1613126944

Unity Game Development Company | Hire Unity Developers

Hire Unity developers who are highly experienced to develop fantastic games and impress the user with their outstanding graphics. With the great and innovative imagination, we create rich gaming applications for all types of categories. From 2D to 3D games, our team has numerous game developers who provide error-free and unbeatable game applications for our clients.

#unity game development #unity mobile app development #unity development services #unity game development company

The  NineHertz

The NineHertz

1612786985

Unity Game Development Company | Hire Unity Developers

Hire unity app developers of The NineHertz at nominal cost. We provide all the possible support and ease to make the client satisfied. From our in depth analysis, we are always able to deliver quality work at time. Not only the quality but we make sure the outcome or the gaming solution as per the guidelines of the client and has functionality which meets the needs of the market. The game software built by our experts is seamless and robust which increases the user popularity graph.

#unity game development #unity mobile app development #unity development services #unity game development company

Anne  de Morel

Anne de Morel

1658334549

Comment Utiliser PlayerPrefs Dans Unity

Que vous soyez relativement nouveau dans le développement dans Unity ou que vous ayez quelques projets à votre actif, vous avez probablement réalisé à quel point il serait utile pour les joueurs de sauvegarder des données.

Si vous êtes comme la plupart d'entre nous, votre premier réflexe pourrait être de faire une recherche rapide sur la façon de sauvegarder les données des joueurs dans Unity. À partir de cette recherche, vous serez peut-être surpris qu'il existe de nombreuses réponses différentes, toutes de complexité variable.

La solution la plus simple est une classe Unity appelée PlayerPrefs. Dans cet article, nous allons passer en revue ce qui PlayerPrefsest, comment, quand et quand ne pas l'utiliser. Nous discuterons également d'alternatives raisonnables à l'utilisation de PlayerPrefs.

Utilisation PlayerPrefsdans Unity

Avec PlayerPrefs, vous pouvez avoir une interface facile à utiliser qui vous permet de commencer à conserver certaines données !

Disons que vous avez créé un jeu simple avec un certain nombre de niveaux. Vous avez décidé de sauvegarder le niveau auquel se trouve votre joueur lorsqu'il quitte le jeu afin que le niveau correct se charge à nouveau lorsqu'il recommence.

Eh bien, cela semble assez facile dans PlayerPrefs. Tout ce que vous avez à faire pour sauvegarder le niveau est le suivant :

<pre>
    // currentLevel is an integer variable representing the level the player is on
PlayerPrefs.SetInt("Level", currentLevel);
PlayerPrefs.Save();
</pre>

Lorsque vous êtes prêt à charger, obtenir la valeur enregistrée est tout aussi simple :

<pre>
// You can set a default return value if you haven't saved a "Level" yet with the second parameter
    currentLevel = PlayerPrefs.GetInt("Level", 0);
</pre>

Cela semble certainement être à peu près aussi simple que possible, il est donc temps de sauvegarder certaines données, n'est-ce pas ?

Eh bien, en quelque sorte. La réponse courte est que sauvegarder un état de jeu comme celui-ci est généralement une mauvaise idée.

La réponse la plus longue est que l'enregistrement et le chargement de données dans Unity est en fait un sujet très profond sans meilleure solution claire.

 

Inconvénients à l'utilisationPlayerPrefs

Commençons par regarder de plus près PlayerPrefspour voir si c'est quelque chose que nous voulons utiliser pour sauvegarder nos données de jeu. Une bonne première étape dans ce processus consiste à vérifier la documentation pourPlayerPrefs . Tout de suite, certaines choses devraient soulever des sourcils.

Mode de sauvegarde des données

Tout d'abord, PlayerPrefsenregistre les données par application. Cela signifie que si vous souhaitez avoir plusieurs fichiers de sauvegarde pour votre application, vous devez faire preuve de créativité. Par exemple, vous pouvez choisir d'ajouter un fichier de sauvegarde IDà chaque entrée dans PlayerPrefset uniquement charger et enregistrer en fonction de ce fichier ID.

Bien sûr, vous devez également trouver un moyen d'enregistrer une liste de joueurs ID, ce qui nous amène au problème suivant avec l'utilisation PlayerPrefs: vous ne pouvez enregistrer les données que sous forme de chaîne, de flottant ou d'entier.

Types de données spécifiques

Vous savez probablement qu'il existe plus de types de données que simplement string, float et integer. Vous pouvez probablement imaginer un scénario dans lequel vous voudriez utiliser un type de données autre que ces trois types. Cela devrait être un gros drapeau rouge pour nous lorsque nous essayons de déterminer si cette classe convient à la sauvegarde des données de jeu.

Si nous avons besoin de construire une sorte de système d'analyse de chaînes compliqué pour imiter le comportement d'une simple liste, nous pourrions nous tromper d'arbre.

Emplacement des données enregistrées

Une autre information importante que nous pouvons extraire des documents est l'endroit où l'emplacement des données PlayerPrefsest réellement enregistré. C'est peut-être quelque chose auquel vous n'avez pas beaucoup réfléchi si vous êtes relativement nouveau dans la programmation, mais les données enregistrées ne sont que des données qui existent quelque part dans un fichier.

Ce fichier peut se trouver sur un ordinateur différent à travers le pays dans le cas d'une candidature en ligne, ou il peut simplement se trouver dans un sous-dossier appelé data. Le fichier peut être structuré comme une base de données ou être un simple fichier texte, cela dépend simplement de ce que les développeurs de l'application ont envie de faire.

Dans ce cas, si nous sommes sur un ordinateur Windows, nous pouvons voir dans la documentation que PlayerPrefsles entrées sont enregistrées dans le registre. Cela devrait être un autre drapeau rouge lorsque vous envisagez de sauvegarder des données de jeu avec PlayerPrefs. Le registre n'est vraiment pas utilisé pour ce genre de choses et enregistre principalement les données de configuration du système et des applications.

Avec tous ces drapeaux et sourcils qui apparaissent, il est assez naturel de se demander à quoi PlayerPrefssert exactement sinon pour enregistrer les données de progression des joueurs. Eh bien, le premier indice (et point de confusion) vient du nom.

Quand utiliser UnityPlayerPrefs

Si vous pensiez que le nom "PlayerPrefs" fait allusion aux préférences du joueur, vous n'êtes certainement pas le seul, mais vous vous trompez également.

Le "Player" dans "PlayerPrefs" fait en fait référence à Unity Player, le nom de l'application autonome Unity Engine qui est créée lorsque vous transformez votre jeu en une application à part entière. Vous avez peut-être rencontré cette convention de dénomination lors de la modification des paramètres de votre projet dans Unity, car les options d'exécution se trouvent sous Player Settings .

Dans cet esprit, nous pouvons commencer à trouver des cas d'utilisation raisonnables pour PlayerPrefs.

La plupart des projets réalisés avec Unity voudront probablement être lancés avec une résolution ou un niveau de qualité spécifique. Bien que nous puissions choisir d'enregistrer les paramètres liés à ces choses avec le reste de nos données de jeu, il est également raisonnable de supposer qu'une résolution confortable n'est pas vraiment pertinente pour chaque sauvegarde, mais est plus pertinente pour l'application par rapport à l'ordinateur ça marche.

Dans ce cas, enregistrer la résolution avec PlayerPrefspourrait être parfaitement logique. Avec chaque nouveau fichier de sauvegarde créé par vos utilisateurs, la résolution de l'application reste celle qu'ils ont initialement définie. C'est plus optimal que de choisir par défaut une valeur qui peut même ne pas fonctionner sur la machine de chaque utilisateur chaque fois qu'il démarre une nouvelle sauvegarde.

La PlayerPrefsclasse n'est pas un moyen idéal pour enregistrer des données de jeu ou par utilisateur pour un projet Unity. Les types de données sont très restrictifs et les données ne peuvent pas être facilement séparées de chaque utilisateur. Cependant, il s'agit d'une excellente interface pour enregistrer les informations de configuration et de paramètres pertinentes pour chaque application spécifique, telles que la résolution, le niveau de qualité, le périphérique audio par défaut, etc.

Donc, si nous n'allons pas sauvegarder nos données de jeu en utilisant PlayerPrefs, qu'allons-nous faire ? La première étape consiste à vraiment réfléchir aux spécificités de votre application et à la manière dont les données utilisateur vont être gérées.

Par exemple, c'est une bonne idée de réfléchir à ce qui se passerait si l'utilisateur pouvait accéder aux données enregistrées par votre application. De manière réaliste, tout système de sauvegarde local (y compris l'utilisation PlayerPrefsde ) conduira à cette possibilité.

Si la réponse est que ce serait catastrophique, alors vous savez probablement déjà que vous devez enregistrer les données utilisateur hors site sur un serveur séparé (comme c'est le cas avec presque toutes les applications en ligne). Si vous faites une application hors ligne, cependant, les réponses peuvent varier énormément.

Dans le cas d'un jeu, le fait que vos utilisateurs accèdent à leurs propres données de sauvegarde n'est probablement pas la pire des choses, mais cela pourrait entraîner une manipulation de l'état du jeu ou même une corruption accidentelle de leur progression. Vous ne pouvez pas faire grand-chose à propos de ce dernier, car quel que soit le format dans lequel vos données sont stockées, il sera probablement toujours possible de trouver un moyen d'en supprimer une partie au hasard. Pour le premier, il existe quelques options allant de ne pas s'en soucier au chiffrement de vos données de sauvegarde pour les rendre plus difficiles, mais pas impossibles, à manipuler.

Stocker des données sansPlayerPrefs

Pour simplifier les choses, concentrons-nous sur la sauvegarde des données pour une application locale. Essentiellement, tout ce que nous devons faire pour enregistrer les données du joueur est d'écrire des informations dans un fichier. Dans Unity, la façon la plus simple de le faire est d'utiliser un StreamWriteret JsonUtility.

StreamWriternous laissera réellement écrire des données dans un fichier et JsonUtilityse chargera de convertir les données que nous voulons enregistrer en JavaScript Object Notation (JSON).

Bien que nous n'utilisions pas réellement de JavaScript, JSON est devenu l'un des standards de transmission de données en raison de sa commodité pour les applications Web. Il est très facilement lu par les humains et correspond très simplement aux objets JavaScript.

Pour nos besoins, nous laisserons Unity gérer la traduction réelle vers et depuis JSON via JsonUtility. JsonUtilityest en quelque sorte une bénédiction et une malédiction, car il est très rapide mais a plusieurs limites.

Avant de mettre cela en œuvre dans vos projets, je vous encourage à lire les docs . Il est très avantageux de comprendre certaines des limites JsonUtilityavant de se lancer dans un projet.

Jetons un coup d'œil à un exemple avant que les mauvaises herbes ne deviennent trop épaisses.

<pre>
using System.IO;
using UnityEngine;

public class DataManager
{
    private Data gameData;
    private static string dataFilePath = Path.Combine(Application.persistentDataPath, "GameData.json");

    public DataManager(int level = 0)
    {
        gameData = new Data();
        gameData.level = level;
    }

    // Here we set our level with some sort of GameManager
    public void SetLevel(int level)
    {
        if (gameData == null)
        {
            gameData = new Data();
        }

        gameData.level = level;
    }

    // The method to return the loaded game data when needed
    public Data GetGameData()
    {
        return gameData;
    }

    public void Save()
    {
        // This creates a new StreamWriter to write to a specific file path
        using (StreamWriter writer = new StreamWriter(dataFilePath))
        {
            // This will convert our Data object into a string of JSON
            string dataToWrite = JsonUtility.ToJson(gameData);

            // This is where we actually write to the file
            writer.Write(dataToWrite);
        }
    }

    public void Load()
    {
        // This creates a StreamReader, which allows us to read the data from the specified file path
        using (StreamReader reader = new StreamReader(dataFilePath))
        {
            // We read in the file as a string
            string dataToLoad = reader.ReadToEnd();

            // Here we convert the JSON formatted string into an actual Object in memory
            gameData = JsonUtility.FromJson<Data>(dataToLoad);
        }
    }

    [System.Serializable]
    public class Data
    {
        // The actual data we want to save goes here, for this example we'll only use an integer to represent the level
        public int level = 0;
    }
}
</pre>

Cet exemple devrait suffire pour commencer à enregistrer et à charger des données dans vos projets Unity locaux. Les projets Web sont suffisamment complexes pour que nous n'abordions pas ici les pratiques de gestion des données.

De toute évidence, il y a un peu plus de frais généraux ici qu'avec la PlayerPrefsclasse. Cependant, une fois que vous avez configuré une sauvegarde et un chargement simples, il est presque aussi facile à utiliser dans la pratique. Une chose à noter ici est que les données enregistrées dans vont être facilement lisibles et donc modifiables.GameData.json

Cela signifie que dans son état actuel, il ne serait pas trop difficile pour un utilisateur final de modifier ses données de sauvegarde. Pour rendre cela plus difficile, nous aurions besoin d'examiner différentes méthodes de cryptage de nos données.

Le chiffrement des données de sauvegarde dépasse un peu le cadre de cet article, mais de nombreuses ressources approfondies sont disponibles sur le sujet si vous êtes si enclin à rechercher. Pour l'instant, comme alternative aux PlayerPrefsdonnées locales non sensibles, les opérations simples sur les fichiers décrites ici sont un excellent moyen de commencer à enregistrer les données du jeu.

Exemple de mise en œuvrePlayerPrefs

Alors qu'en est-il PlayerPrefs? Puisqu'il s'agit d'un excellent système pour enregistrer des informations spécifiques à l'ordinateur, nous pouvons modifier notre exemple pour enregistrer également certaines données de paramètres d'une manière qui n'interfère pas avec nos opérations sur les fichiers et persistera entre les utilisateurs sur le même ordinateur.

<pre>
using System.IO;
using UnityEngine;

public class DataManager
{
    private Data gameData;
    private SettingsData settingsData;
    private static string dataFilePath = Path.Combine(Application.persistentDataPath, "GameData.json");

    public DataManager(int level = 0)
    {
        gameData = new Data();
        gameData.level = level;

        settingsData = new SettingsData(0, 1920, 1080);
    }

    // Here we set our level with some sort of GameManager
    public void SetLevel(int level)
    {
        if (gameData == null)
        {
            gameData = new Data();
        }

        gameData.level = level;
    }

    // The method to return the loaded game data when needed
    public Data GetGameData()
    {
        return gameData;
    }

    // This can be used when we change settings values
    public void SetSettings(int quality, int horizontalResolution, int verticalResolution)
    {
        settingsData = new SettingsData(quality, horizontalResolution, verticalResolution);
    }

    public void SaveSettings()
    {
        PlayerPrefs.SetInt("QualityLevel", settingsData.qualityLevel);
        PlayerPrefs.SetInt("HorizontalResolution", settingsData.horizontalResolution);
        PlayerPrefs.SetInt("VerticalResolution", settingsData.verticalResolution);
        PlayerPrefs.Save();
    }

    public void LoadSettings()
    {
        // We can get a default value if there is no settings information, which is what the second parameter
        // in the PlayerPrefs.GetInt(p1, p2) is for
        settingsData = new SettingsData(
                            PlayerPrefs.GetInt("QualityLevel", 0),
                            PlayerPrefs.GetInt("HorizontalResolution", 1920),
                            PlayerPrefs.GetInt("VerticalResolution", 1080)
                        );
    }

    public void Save()
    {
        // This creates a new StreamWriter to write to a specific file path
        using (StreamWriter writer = new StreamWriter(dataFilePath))
        {
            // This will convert our Data object into a string of JSON
            string dataToWrite = JsonUtility.ToJson(gameData);

            // This is where we actually write to the file
            writer.Write(dataToWrite);
        }

        // This doesn't need to be coupled to the Save function, and probably shouldn't be,
        // but for demonstration purposes we'll put this here
        SaveSettings();
    }

    public void Load()
    {
        // This creates a StreamReader, which allows us to read the data from the specified file path
        using (StreamReader reader = new StreamReader(dataFilePath))
        {
            // We read in the file as a string
            string dataToLoad = reader.ReadToEnd();

            // Here we convert the JSON formatted string into an actual Object in memory
            gameData = JsonUtility.FromJson<Data>(dataToLoad);
        }

        LoadSettings();
    }

    public class SettingsData
    {
        public int qualityLevel = 0;
        public int horizontalResolution = 1920;
        public int verticalResolution = 1080;

        public SettingsData(int quality, int hr, int vr)
        {
            this.qualityLevel = quality;
            this.horizontalResolution = hr;
            this.verticalResolution = vr;
        }
    }

    [System.Serializable]
    public class Data
    {
        // The actual data we want to save goes here, for this example we'll only use an integer to represent the level
        public int level = 0;
    }
}

</pre>

Bien que le code présenté ici ne soit pas exactement prêt pour le jeu, nous espérons que les concepts expliqués seront utiles dans le développement de votre projet Unity.

Conclusion

C'est ça! J'espère que les utilisations de PlayerPrefssont un peu plus claires.

C'est un sujet que j'ai trouvé quelque peu déroutant lorsque j'ai commencé à travailler dans Unity. Cependant, en fin de compte, c'est vraiment à vous de décider comment gérer les données dans votre projet. Chaque problème s'accompagne d'un large éventail de solutions potentielles.

J'espère que vous ferez quelque chose de génial !

Source: https://blog.logrocket.com/why-should-shouldnt-save-data-unitys-playerprefs/

#unity