FAQ Unity 3DConsultez toutes les FAQ

Nombre d'auteurs : 3, nombre de questions : 89, dernière mise à jour : 10 février 2020 

 
OuvrirSommaireScript

Il existe plusieurs possibilités. Une des plus simples est de glisser le script (à partir de la fenêtre « Project ») directement sur le GameObject (fenêtre « Scene »). De la même manière, on peut le glisser vers l'inspector lié au GameObject sélectionné. Il est aussi possible dans la partie inspector de faire une sélection par le bouton « Add Component », sélection « Scripts ».

Créé le 5 juillet 2015  par Greg Latiner

Le script, une fois créé, se présentera comme un squelette d'une classe dérivée de MonoBehaviour et portant le nom du fichier que vous venez de créer. Elle comprend deux méthodes, Start et Update.

Créé le 5 juillet 2015  par Greg Latiner

Pour qu'un script puisse être considéré comme un composant attachable à un GameObject, le nom de la classe et du fichier doivent être identique.

Créé le 5 juillet 2015  par Greg Latiner

Les fonctions Start() et Update() font partie des méthodes héritées de la classe MonoBehaviour. Elles sont incluses par défaut lors de la création d'un nouveau script.

  • La fonction Start() sera exécutée lorsque l'objet est instancié (et si le script est activé), et juste avant les fonctions de type Update(). Elle est exécutée une seule fois.
  • La fonction Update() sera exécutée (si le script est activé) à chaque frame. Si vous avez un rafraichissement de 60 images/seconde, alors la fonction Update() sera exécutée 60 fois/seconde.
Créé le 5 juillet 2015  par Greg Latiner

Vous pouvez changer le modèle de base des fichiers de script. Pour cela, rendez-vous dans le répertoire Unity → Editor → Data → Resources → ScriptTemplates.

Créé le 5 juillet 2015  par Greg Latiner

Rajoutez [HideInInspector] en début de ligne déclarant votre variable.

Créé le 5 juillet 2015  par Greg Latiner

Employez [SerializeField]. Exemple :

 
Sélectionnez
[SerializeField]
private bool hasHealthPotion = true;
Créé le 5 juillet 2015  par Greg Latiner

Utilisez l'attribut [Range(min,max)], qui permet de définir une valeur minimum et maximum pour la valeur à saisir. Exemple:

 
Sélectionnez
[Range(-100, 100)]
public int speed = 0;
Créé le 5 juillet 2015  par Greg Latiner

Par exemple, pour donner un titre à une zone de données, employez [HeaderAttribute]. Vous pouvez afficher un court texte explicatif grâce à [Tooltip("")].

Il est aussi possible d'imposer un espace plus conséquent entre certaines parties grâce à [Space(xx)].

Créé le 5 juillet 2015  par Greg Latiner

En vous rendant dans le menu Edit → ProjectSettings → ScriptExecutionOrder, vous pourrez ajouter une liste de scripts dont l'ordre d'exécution sera alors contrôlé.

Même s'il est possible de choisir l'ordre, cela reste déconseillé. En effet, il y a de grandes possibilités que cette configuration soit oubliée avec le temps et qu'avec des modifications dans les scripts, cela cause des erreurs. De plus, un tel besoin indique certainement que vous avez une trop forte dépendance entre vos scripts et donc, que vous devez changer votre façon de concevoir l'application.

Créé le 5 juillet 2015  par Greg Latiner

En mode éditeur, en utilisant la méthode Break() de la classe Debug :

 
Sélectionnez
Debug.Break();

En mode exécution, une solution consiste à passer la valeur timeScale de la classe Time à zéro.

Créé le 5 juillet 2015  par Greg Latiner

L'ensemble des méthodes événements dérivées de la classe MonoBehaviour sont exécutées dans un ordre bien précis. Connaitre leur ordre d'appel ainsi que leur rôle peut s'avérer très utile. Le diagramme est consultable dans la documention.

Créé le 5 juillet 2015  par Greg Latiner

Lorsque l'on programme des déplacements d'éléments, il est important d'assurer une vitesse apparente identique, quelle que soit la puissance de la machine sur laquelle s'exécute l'application. Pour garder un affichage constant, il faudra avoir recours à la fonction Time.DeltaTime, représentant le temps écoulé entre chaque frame, exemple :

 
Sélectionnez
    void Update() {
        float translation = Time.deltaTime * 10;
        transform.Translate(0, 0, translation);
    }
Créé le 5 juillet 2015  par Greg Latiner

Au sein d'un script que l'on assigne à un GameObject, la méthode GetComponent() va permettre d'accéder aux différents composants de ce GameObject (animation, mesh, material, etc.). Exemple :

 
Sélectionnez
    public HingeJoint hinge;
    void Example() {
        hinge = gameObject.GetComponent<HingeJoint>();
        hinge.useSpring = false;
    }
Créé le 5 juillet 2015  par Greg Latiner

La méthode GetComponent() va permettre d'accéder à des données d'un script (pour peu qu'elles soient publiques) d'un autre GameObject (un script représentant un composant d'un GameObject), exemple :

 
Sélectionnez
MyScriptA sc = otherGameObject.GetComponent<MyScriptA>();
sc.value1 = this.refvalue;
Créé le 5 juillet 2015  par Greg Latiner
 
Sélectionnez
foreach (Transform t in transform)
{
    Debug.Log("Child: " + t.name);
}
Créé le 5 juillet 2015  par Greg Latiner

La fonction Instanciate() permet de créer facilement tous les types d'objets. Par exemple, pour créer un autre GameObject, basé sur un modèle déjà présent dans la scène, on pourra écrire :

 
Sélectionnez
public GameObject enemy;
...
void Start() {
    Instantiate(enemy);
}
Créé le 5 juillet 2015  par Greg Latiner

Il existe plusieurs possibilités pour arriver à partager des données entre les différentes scènes :

  • avec un GameObjet (comme celui du joueur par exemple) qui, une fois créé dans la première scène, ne sera pas détruit lors du chargement des scènes suivantes. La fonction DontDestroyOnLoad permettra une persistance du GameObjet entre les différentes scènes ;
  • avec la classe PlayerPrefs, qui permet de sauvegarder facilement certaines données de base et de les réimporter après le chargement de scènes suivantes.
Créé le 5 juillet 2015  par Greg Latiner

Le fonctionnement de certains scripts nécessite la présence de composants bien particuliers au niveau du GameObject. Pour éviter d'affecter à un GameObject un script alors que le(s) composant(s) nécessaire(s) à son fonctionnement ne sont pas présents, on peut conditionner son attribution. Exemple :

 
Sélectionnez
[RequireComponent(typeof(RigidBody))]
 public class SomeBehaviorScript : MonoBehaviour
 {
 }
Créé le 5 juillet 2015  par Greg Latiner

Tout est basé sur l'ordre de compilation des scripts. En particulier, si un script en C# souhaite accéder à un script en UnityScript, alors il faudra que celui-ci soit placé dans un des répertoires dont la compilation se fera en premier, notamment les répertoires Standard Assets ou Plugins (les créer s'ils n'existent pas).

Créé le 5 juillet 2015  par Greg Latiner

Désactiver un script dans l'inspector ne signifie pas qu'il soit complètement hors service pour autant. La fonction MonoBehaviour.Awake sera exécutée, même avec un script désactivé.

Créé le 5 juillet 2015  par Greg Latiner

Le code suivant permet d'ajouter des primitives dans les scènes :

 
Sélectionnez
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(0, 1.0f, 0);
Créé le 5 juillet 2015  par Greg Latiner

L'API permet d'orienter un objet vers un autre. Si target est le Transform d'un objet cible, on écrira pour le GameObject à orienter :

 
Sélectionnez
transform.LookAt(target);
Créé le 5 juillet 2015  par Greg Latiner

Si mytexture est une Texture, et que mon GameObject possède un material, alors :

 
Sélectionnez
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = mytexture;
Créé le 5 juillet 2015  par Greg Latiner

L'ajout d'un RigidBody pourra se faire comme suit :

 
Sélectionnez
gameObject.AddComponent<Rigidbody>();
Créé le 5 juillet 2015  par Greg Latiner

Si mon GameObject possède un material, alors :

 
Sélectionnez
Renderer renderer = GetComponent<Renderer>();
renderer.material.color = new Color(0f, 1.0f, 0);    // couleur verte
Créé le 5 juillet 2015  par Greg Latiner

La classe Mesh permet d'accéder à la géométrie d'un GameObject. Par exemple, pour changer les valeurs sur l'axe des Y de chaque sommet du mesh, on pourra écrire :

 
Sélectionnez
void Update() {
    Mesh mesh = GetComponent<MeshFilter>().mesh;
    Vector3[] vertices = mesh.vertices;
    int i = 0;
    while (i < vertices.Length) {
        vertices[i] += Vector3.up * Time.deltaTime;
        i++;
    }
    mesh.vertices = vertices;
    mesh.RecalculateBounds();
}
Créé le 5 juillet 2015  par Greg Latiner

À partir d'un GameObject vide, on pourra lui assigner un script permettant une génération procédurale, par exemple :

 
Sélectionnez
Vector3[] newVertices = new Vector3[]
{
    new Vector3( 1, 0,  1),     new Vector3( 1, 0, -1),
    new Vector3(-1, 0,  1),     new Vector3(-1, 0, -1)  };
Vector2[] newUV = new Vector2[]
{
    new Vector2(1, 1),      new Vector2(1, 0),
    new Vector2(0, 1),      new Vector2(0, 0) };
int[] newTriangles = new int[]
{
    0, 1, 2,
    2, 1, 3 };
void Start() {
    gameObject.AddComponent<MeshFilter>();
    gameObject.AddComponent<MeshRenderer>();
    Mesh mesh = new Mesh();
    GetComponent<MeshFilter>().mesh = mesh;
    mesh.vertices = newVertices;
    mesh.uv = newUV;
    mesh.triangles = newTriangles;
    mesh.RecalculateBounds();
}
Créé le 5 juillet 2015  par Greg Latiner

Une des solutions est de créer des classes de données. Exemple :

 
Sélectionnez
using UnityEngine;
using System.Collections;
[System.Serializable]
public class PlayerData {
    public int lifePoints;
    public float altitude;
    public GameObject go;
    public Transform weapoon;
}
public class ThePlayer : MonoBehaviour {
    public PlayerData myPlayer;
    void Start() {
    }
    void Update() {
    }
}
Créé le 5 juillet 2015  par Greg Latiner

Pour récupérer l'ensemble des colliders (et donc aussi les GameObject associés) présents dans une scène, on écrira :

 
Sélectionnez
Collider[] cols = Object.FindObjectsOfType<Collider>();
Créé le 5 juillet 2015  par Greg Latiner

Pour récupérer l'ensemble des GameObjects ayant le même tag, on pourra utiliser la fonction FindGameObjectsWithTag:

 
Sélectionnez
GameObject[] obets = GameObject.FindGameObjectsWithTag("NomTag");
Créé le 5 juillet 2015  par Greg Latiner

Au-delà des bonnes pratiques habituellement conseillées au niveau de l'écriture du code, il y a un certain nombre de choses à éviter en ce qui concerne la mise en œuvre de l'API d'Unity. En voici quelques-unes :

  • ne pas utiliser de fonctions Find en dehors des fonctions d'initialisation (comme dans Start() par exemple) ;
  • limiter les appels aux fonctions GetComponent (plus particulièrement au sein de la boucle de jeu), et ne pas hésiter à mémoriser les références des composants utiles ;
  • ne pas nommer ses classes avec des noms de classes ou de composants existant dans l'API d'Unity ;
  • éviter les instanciations « massives » dans la boucle de jeu, comme dans le cas de création de projectiles. Cela provoque un appel fréquent au ramasse-miettes (Garbage Collector) pouvant être pénalisant. Il faut privilégier l'emploi d'une technique alternative, comme le « pooling » ;
  • éviter l'utilisation abusive de MeshCollider, privilégier les primitives, quitte à les assembler pour obtenir grossièrement la forme souhaitée ;
  • ne pas effectuer de changement d'attitude (par l'emploi de fonctions de transformation) sur des objets gérés dynamiquement par la physique ;
  • éviter l'emploi des fonctions de gestion de la physique en dehors de la fonction FixedUpdate().
Créé le 5 juillet 2015  par Greg Latiner

Une des solutions les plus communément employées est celle qui consiste à créer un script de gestion, que l'on pourra par exemple nommer « GameManager ». Elle s'appuie sur la technique du Singleton, et sera créée de telle sorte qu'elle puisse survivre aux différents changements de scène. Voici un exemple de base, à assigner sur un GameObject vide :

 
Sélectionnez
using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {
    public static GameManager instance = null;
    // vos données globales de jeux:
    // ...
    //
    void Awake()
    {
        // Vérifie si l'instance existe déjà.
        // Si c'est le cas, détruit l'objet.
        if(instance)
        {
            Destroy(gameObject);
            return;
        }
        // définit l'instance.
        instance = this;
        // Définit l'objet comme non destructible entre les scènes
        DontDestroyOnLoad(gameObject);
        // Appelle une fonction d'initialisation du jeu (exemple)
        InitGame();
    }
    // Update est appelée à chaque image.
    void Update()
    {
        //...
    }
    // Initialisations diverses pour le jeu.
    void InitGame()
    {
        //...
    }
}
Créé le 5 juillet 2015  par Greg Latiner

Nous supposons que les deux objets sont sur le même plan (par exemple : la coordonnées y est à 0 pour les deux objets). Sinon, vous pouvez toujours forcer la coordonnée en question à 0 dans votre fonction. La première étape est d'obtenir un vecteur (normalisé) partant de l'objet A et allant vers l'objet B. Ensuite, grâce à la fonction Mathf.Atan2 vous pouvez obtenir l'angle en utilisant comme paramètre les coordonnées z et x. Sachant que Atan2 retourne un angle en radians, il suffit de multiplier le résultat avec Mathf.Rad2Deg et de lui ajouter 180. Voici la fonction :

 
Sélectionnez
float getAngle(Transform A, Transform B)
{
    var posA = A.position;
    var posB = B.position;

    // Forçons les deux objets sur le même plan
    posA.y = posB.y = 0;

    Vector3 direction = (posA - posB).normalized;

    return Mathf.Atan2(direction.z, direction.x) * Mathf.Rad2Deg + 180;
}
Créé le 11 mars 2016  par Alexandre Laurent
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Developpez LLC et al. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.