Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
We use cookies to ensure that we provide you with the best possible experience on our site.
Votre source incontournable sur Unity et le développement web
Votre source incontournable sur Unity et le développement web
Dans le monde de Unity, la fonction Instantiate se présente comme un outil indispensable, nous permettant de copier un gameObject ou divers objets Unity sur notre scène active.
La méthode Instantiate est statique et émane de la classe UnityEngine.Object.
On peut voir cette méthode comme une duplication; prenant, comme paramètre principal, un objet Unity (une classe héritant de UnityEngine.Object), le dupliquant, puis l’initialisant dans votre scène.
Table des matières
Pour instancier ou cloner un gameObject, nous passons par un script, en utilisant la fonction statique « Instantiate« .
Cette fonction renvoie le clone instancié.
Utilisons un exemple simple où nous invoquons un gameObject déjà présent dans notre scène depuis un MonoBehaviour :
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public GameObject referenceGameObject;
private void Start()
{
GameObject instance = Instantiate(referenceGameObject);
// Actions avec l'instance
}
}
Info : Étant donné que notre classe est un MonoBehaviour héritant de Object, nous pouvons utiliser directement la méthode statique sans le préfixe.
Nous utilisons l’Inspecteur pour définir notre gameObject par référence :
Comme on peut le voir dans l’image ci-dessus, une copie de notre gameObject a été créée.
Il est à noter qu’un suffixe « (Clone) » est ajouté par défaut.
Vous pouvez modifier directement le nom d’un gameObject via le code en utilisant la propriété ‘name‘.
Il y a plusieurs choses intéressantes à propos de la fonction « Instantiate« , tout d’abord l’objet dupliqué est détaché de l’objet de référence.
Toutes les modifications apportées à la copie ne se répercutent pas sur l’objet de référence.
Instantiate peut être utilisé en dehors d’une classe Unity ; son application n’est pas limitée.
using UnityEngine;
public class Invoker
{
public void Invoke(GameObject gameObject)
{
Object.Instantiate(gameObject);
}
}
Il est crucial de souligner qu’Instantiate fonctionne parfaitement avec n’importe quel élément héritant de Object.
Lorsque vous passez un MonoBehaviour en tant que paramètre, l’élément retourné sera également un Monobehaviour, éliminant ainsi le besoin de conversion ou de GetComponent.
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
// Player est un MonoBehaviour
public Player player;
private void Start()
{
Player instance = Instantiate(player);
// Actions avec l'instance
}
}
Il convient de noter l’ajout, depuis la version 2022.3.11 d’Unity, d’une nouvelle méthode spécialement conçue pour les GameObjects.
Pour en savoir plus, consultez mon article dédié à InstantiateGameObjects.
Il est possible d’instancier un gameObject en tant qu’enfant (ajout d’un parent) en utilisant la méthode Instantiate, en associant un deuxième paramètre, un Transform, indiquant le parent.
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public GameObject referenceGameObject;
private void Start()
{
// L'instance devient l'enfant de notre MonoBehaviour
GameObject instance = Instantiate(referenceGameObject, transform);
}
}
On peut ajouter un troisième paramètre après notre transform ; il s’agit d’un booléen, « instantiateInWorldSpace« .
Par défaut, sa valeur est false.
Lorsqu’un parent est ajouté, la position, l’échelle et la rotation du nouvel objet deviennent relatives au parent.
Pour positionner votre gameObject par rapport à l’espace mondial (y compris la rotation et l’échelle), vous devez indiquer true.
GameObject instance = Instantiate(referenceGameObject, transform, true);
Exemple avec des positions :
instantiateInWorldSpace | World position référence GameObject | World position parent | World position duplicate | Position locale duplicate |
---|---|---|---|---|
false | Vector3(1, 0, 0) | Vector3(5, 5, 5) | Vector3(6, 5, 5) | Vector3(1, 0, 0) |
true | Vector3(1, 0, 0) | Vector3(5, 5, 5) | Vector3(1, 0, 0) | Vector3(-4, -5, -5) |
Il est essentiel de noter que lorsque « instantiateInWorldSpace » est true, la position mondiale du duplicate est identique à celle de l’objet de référence.
Avec false, elle change et devient relative à celle du parent.
Cela s’applique également à l’échelle et à la rotation.
Vous avez la possibilité de modifier directement la position et la rotation de vos GameObjects instanciés en associant des paramètres supplémentaires à la fonction « Instantiate« .
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public GameObject referenceGameObject;
private void Start()
{
// Instancier à Vector3(5, 0, 0) et sans rotation
GameObject instance = Instantiate(referenceGameObject, Vector3.right * 5f, Quaternion.identity);
}
}
Si vous souhaitez ne pas avoir de rotation, vous pouvez associer « Quaternion.identity » avec le troisième paramètre.
Vous pouvez également associer directement un parent tout en spécifiant la position et la rotation en ajoutant un dernier, quatrième paramètre de type Transform.
Notez que les valeurs ajoutées restent en coordonnées mondiales (world) même avec un parent spécifié.
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public GameObject referenceGameObject;
private void Start()
{
// Instancier à Vector3(5, 0, 0) et sans rotation
GameObject instance = Instantiate(referenceGameObject, Vector3.right * 5f, Quaternion.identity, transform);
}
}
Qu’est-ce qu’un prefab ?
Le système Prefab Unity vous permet de créer, configurer et enregistrer un GameObject avec tous ses composants, valeurs de propriétés ainsi que ses GameObjects enfants, formant alors un asset réutilisable.
L’asset Prefab sert de modèle à partir duquel vous pouvez générer de nouvelles instances dans la scène.
Sur Unity, les prefabs sont représentés avec une couleur bleuâtre sur le cube et l’écriture.
Vous pouvez créer un prefab en faisant glisser et déposer un GameObject de votre scène dans un dossier de votre projet.
Sur Unity, pour instancier un prefab, nous nous appuyons toujours sur un script C#. Instancier notre prefab est identique à instancier un GameObject déjà présent dans notre scène.
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public GameObject referencePrefab;
private void Start()
{
GameObject instance = Instantiate(referencePrefab);
}
}
Pendant une instantiation standard d’un prefab, vous avez peut-être remarqué que le lien entre le prefab et l’objet dupliqué est rompu.
Nous avons perdu la couleur bleuâtre
En utilisant la méthode « PrefabUtility.InstantiatePrefab« , la connexion entre le prefab et l’objet dupliqué est préservée.
Cela reflète le comportement lorsque vous faites glisser et déposez votre prefab dans la scène.
using UnityEngine;
using UnityEditor;
public class EditorHelper
{
[MenuItem("Window/Instantiate")]
private static void InstantiatePrefab()
{
// Chargez le prefab hello depuis Resources
GameObject gameObject = Resources.Load<GameObject>("hello");
Object instance = PrefabUtility.InstantiatePrefab(gameObject);
}
}
Revenons sur ce qu’est un ScriptableObject.
Un ScriptableObject sert de conteneur de données, capable non seulement de stocker des quantités importantes de données, mais aussi de fonctionner comme intermédiaire (très pratique pour les events)…
Il permet le stockage de quantités importantes de données indépendamment des instances de classe.
Un des cas d’utilisation principaux des ScriptableObjects est de réduire l’utilisation de la mémoire dans votre projet en évitant la duplication de valeurs.
Pour instancier (ou dans ce cas, dupliquer) un ScriptableObject, la méthode Instantiate peut être utilisée.
Cependant, si vous souhaitez créer un ScriptableObject vide, « ScriptableObject.CreateInstance » peut être utilisé.
Pour une utilisation dans l’environnement de l’éditeur, il doit être associé à « AssetDatabase.CreateAsset » pour créer l’asset dans votre projet.
using UnityEngine;
using UnityEditor;
public class EditorHelper
{
[MenuItem("Window/Scriptable")]
private static void CreateScriptable()
{
// Data est un ScriptableObject
Data data = ScriptableObject.CreateInstance<Data>();
AssetDatabase.CreateAsset(data, "Assets/data.asset");
// Écrit tous les changements d'actifs non enregistrés sur le disque.
AssetDatabase.SaveAssets();
}
}
Cette méthode peut également être utilisée en temps réel. Cependant, personnellement, je trouve son utilisation assez situationnelle.
La possibilité de modifier les données directement dans l’inspecteur peut être séduisante, seulement dans de nombreux cas, une classe ou une structure C# vous permet d’obtenir le même résultat avec de meilleures performances.
Dans un contexte multi-scène, où vous avez une scène active (principale) ainsi qu’une ou plusieurs scènes additives, l’appel de la méthode « Instantiate » entraînera toujours le clonage du gameObject dans la scène active, quel que soit l’origine de l’appel.
Vous pouvez définir votre scène active via l’éditeur en faisant un clic droit sur votre scène dans la hiérarchie des scènes et en sélectionnant « Set Active Scene.«
L’activation en temps réel est également possible en utilisant la méthode « SceneManager.SetActiveScene« .
De plus, il est possible de déplacer un gameObject d’une scène à une autre grâce à la méthode statique « SceneManager.MoveGameObjectToScene.«
using UnityEngine;
using UnityEngine.SceneManagement;
public class InvokeBehaviour : MonoBehaviour
{
public void MoveScene()
{
SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetSceneByName("scene1"));
}
}
De plus, à partir de Unity 2022.3.11, la méthode « SceneManager.MoveGameObjectsToScene » permet le déplacement de plusieurs gameObjects en utilisant leurs instanceIds.
Pour instancier un objet vide, il n’est pas nécessaire d’utiliser la fonction « Instantiate« .
À la place, vous pouvez créer une instance de la classe GameObject dans un script.
Vous pouvez associer directement un nom en utilisant le premier paramètre du constructeur.
Pour ajouter des composants pendant la création du gameObject :
private void EmptyGameObject()
{
// GameObject vide avec defaultName
var gameObjectWithoutName = new GameObject();
// GameObject vide avec un nom personnalisé
var gameObjectWithName = new GameObject("Nom du GameObject");
// GameObject vide créé avec un tableau de types de composants
var gameObjectWithComponent = new GameObject("Nom du GameObject", new System.Type[] { typeof(BoxCollider2D), typeof(Rigidbody2D) });
// Alternative, passer les paramètres de type de composant un par un
var alternativeGameObjectWithComponent = new GameObject("Nom du GameObject", typeof(BoxCollider2D), typeof(Rigidbody2D));
}
Il est également possible d’ajouter un GameObject vide via l’éditeur : faites un clic droit dans la hiérarchie de la scène et cliquez sur « Create Empty. »
Vous pouvez également utiliser le raccourci « Ctrl+Shift+N. » Pour faire du gameObject un enfant de l’objet actuellement sélectionné, utilisez « Alt+Shift+N.«
Pour instancier un cube ou toute autre primitive, nous utilisons la méthode statique GameObject.CreatePrimitive
.
Comme premier argument, nous passons le PrimitiveType
désiré.
Unity propose six types :
private void CreatePrimitive()
{
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
Une note importante de la documentation (traduit) :
CreatePrimitive peut échouer à l’exécution si votre projet ne fait pas référence aux composants suivants : MeshFilter, MeshRenderer, et BoxCollider ou SphereCollider à l’exécution.
La meilleure façon d’éviter ce crash est de déclarer des propriétés privées de ces types. Le système de stripping reconnaîtra leur utilisation, les inclura dans la build, donc il ne supprimera pas ces composants.
Vous pouvez également créer un cube directement dans l’éditeur Unity : faites un clic droit dans la hiérarchie de la scène -> « 3D Object » -> « Cube.«
Si vous souhaitez instancier et appliquer des paramètres, comme avec AddComponent
, il n’est pas possible de le faire directement.
Il est préférable de créer une fonction séparée, par exemple ‘SetParameters’, à appeler après la création du composant.
using UnityEngine;
public class TorsoEquip : MonoBehaviour
{
public int Defense { get; private set; }
public int Resilience { get; private set; }
public void SetParameters(int defense, int resilience)
{
Defense = defense;
Resilience = resilience;
}
}
using UnityEngine;
public class InvokeBehaviour : MonoBehaviour
{
public TorsoEquip prefabTorsoEquip;
private void InvokeWithParameters()
{
var torsoEquip = Instantiate(prefabTorsoEquip);
torsoEquip.SetParameters(20, 30);
}
}
Pour rendre le code plus réutilisable, il peut être plus judicieux de passer un objet de configuration au lieu de passer des paramètres un par un.
Cet objet de configuration peut être une classe, une structure ou même un ScriptableObject, selon vos besoins :
using UnityEngine;
public class TorsoEquip : MonoBehaviour
{
public class EquipmentStat
{
public int Defense { get; set; }
public int Resilience { get; set; }
}
public EquipmentStat EquipmentConfiguration { get; private set; }
public void AddConfiguration(EquipmentStat equipmentConfiguration)
{
EquipmentConfiguration = equipmentConfiguration;
// Maintenant, vous pouvez accéder à
// EquipmentConfiguration.Defense
// ou EquipmentConfiguration.Resilience
}
}
Lors de l’instanciation de nombreux GameObjects, je vous recommande vivement l’utilisation d’un système de pooling
.
Ce système vous permet de réutiliser des GameObjects précédemment créés au lieu d’en créer de nouveaux.
L’instanciation et la destruction de GameObjects peuvent être coûteuses.
Astuce supplémentaire : Dans un contexte d’éditeur, si vous vous retrouvez à instancier des GameObjects, n’oubliez pas d’appeler la méthode EditorUtility.SetDirty
sur votre GameObject.
Sinon, la scène ne reconnaîtra pas qu’il y a de nouveaux changements, et peu importe combien de fois vous appuirez sur Ctrl+S, rien ne sera enregistré.
Tout au long de cette exploration, nous avons vu divers aspects de la méthode Instantiate, de son utilisation de base pour dupliquer des gameObjects jusqu’à des scénarios plus avancés tels que l’instanciation de prefabs, de scriptable objects et son comportment avec plusieurs scènes.
Nous avons également découvert des techniques telles que l’instanciation en tant qu’enfant, le réglage des positions et rotations, et la création de GameObjects vides.
Merci d’avoir lu. Bon codage !