Comment fermer une fenêtre dans Unity3D ?

Aujourd’hui nous allons essayer de fermer une fenêtre ouverte dans Unity3D. Pour cela il faut une fenêtre ouverte (panel) dans un Canvas.

Problématique :

  • Nous ne voulons pas fermer cette fenêtre (InventoryWindows) d’une quelconque manière mais en appuyant simplement en dehors de celle-ci.
  • Il faut que la fermeture de la fenêtre puisse s’exécuter aussi sur mobile (soit sans curseur de souris).

Dans un premier temps je n’ai pas pensé à adapter cette fonctionnalité à l’utilisation d’un écran tactile. Or, mon premier réflexe a été d’ajouter un contrôle sur un booléen (mouseIsOut), si mouseIsOut vrai alors fermer la fenêtre, sinon ne rien faire. J’ai mis le tout dans la fonction LateUpdate() de la classe définissant la gestion de ma fenêtre. Quand la souris sors du Panel (Event Trigger –  PointerOut) alors on met mouseIsOut à vrai. Au contraire, à l’ouverture du panel ou l’entrée de la souris dans le panel on met mouseIsOut à faux.

Avec cette méthode qui marche très bien sur PC on rencontre bien vite un problème quand on passe sur un écran tactile. En effet, l’écran tactile ne considère pas de curseur tant que notre doit n’est pas en contact avec la surface. On ne peut donc pas détecter la sortie du curseur du Panel à l’aide de l’Event Trigger en mode PointerExit… (Sauf si l’utilisateur déplace son doigt sans le lever de l’intérieur à l’extérieur du panel.

Recherche d’une autre solution :

Pour palier à ce problème j’ai trouvé une solution facile à mettre en œuvre.

  • Faire d’un panel un bouton quitter géant et situé à l’arrière de notre fenêtre.

En bleu (écran + objet actif) vous pouvez voir le panel sur lequel j’ai ajouté un Event Trigger et le script permettant de mettre mouseIsOut à True si il y a détection de clic sur ce panel.

Il vous suffit alors de mettre mouseIsOut à false quand vous ouvrez la fenêtre (ici l’inventaire) et le tour est joué.

Note : vous pouvez aussi détecter si votre fenêtre est active (isActive = true) pour économiser l’utilisation d’un booléen.

Unity3D : gestion des bords de l’écran

Définition du problème

J’ai passé quelques temps à comprendre comment gérer la détection des bords de l’écran pour ne pas que mon gameobject en sorte.

Dans mon cas le gameobject dirigé par le joueur est un cube auquel on ajoute un BoxCollider, la caméra est fixe.

Dans Unity on gère la position d’un objet par son attribut position (un Vector3 donnant le positionnement du centre de l’objet).

Malheureusement pour moi le composant camera de Unity permet seulement de trouver la taille en pixels de l’écran (maCamera.pixelHeight et maCamera.pixelWidth) et donc je me suis mis à chercher un moyen de déterminer en pixel l’endroit où se trouve mon cube afin de savoir si celui-ci est en dehors ou en dedans de l’écran. En gros si mon cube est entièrement visible ou non !

De l’intérêt d’utiliser un BoxCollider

Pour déterminer le centre de mon cube ainsi que sa taille j’utilise les valeurs récupérables dans l’attribut bounds du composant :

//dans start()
joueurX = this.GetComponent<Collider>().bounds.size.x/2;
joueurY = this.GetComponent<Collider>().bounds.size.y/2;

//dans update()  centreJoueurX = this.GetComponent<Collider> ().bounds.center.x; centreJoueurY = this.GetComponent<Collider> ().bounds.center.y; 

Aux tests à effectuer

if (maCamera.WorldToScreenPoint(new Vector3(0,(centreJoueurY+joueurY),0)).y > pixelHeight) {
//on stop le déplacement
directionJoueur = 0;
this.gameObject.transform.localPosition += (-mouvementY * speed * Time.deltaTime);
} 
else if (maCamera.WorldToScreenPoint(new Vector3(0,(centreJoueurY-joueurY),0)).y  < 0) {
directionJoueur = 0;            this.gameObject.transform.localPosition += (mouvementY * speed * Time.deltaTime);
} 
else if (maCamera.WorldToScreenPoint(new Vector3((centreJoueurX+joueurX),0,0)).x > pixelWidth) {
directionJoueur = 0;             this.gameObject.transform.localPosition += (-mouvementX * speed * Time.deltaTime);
}
else if (maCamera.WorldToScreenPoint(new Vector3((centreJoueurX-joueurX),0,0)).x < 0) {
directionJoueur = 0;                                           this.gameObject.transform.localPosition += (mouvementX * speed  * Time.deltaTime);
}


Voilà pour le système utilisé actuellement, on peut bien entendu imaginer un système pour ne pas refaire les tests à chaque update() mais uniquement au moment voulu.

Blender : Modifier le centre d’un objet (version avant 2.80)

La problématique est la suivante : comment modifier le centre d’un objet 3D dans Blender ?

Cas pratique : Dans l’utilisation des modélisations faite dans Blender dans un moteur de jeu comme Unity, sa position est définie par le centre de l’objet et ses coordonnées (x=0,y=0,z=0).

Dans le cas présent nous voulons pouvoir placer des arbres de différentes tailles sur des blocs de sol à une position donnée. Le centre de l’objet doit donc être placé au bas de ceux si et le socle de l’arbre rapproché le plus possible de l’origine de l’axe perpendiculaire à l’axe de pousse de l’arbre dans le cas présent.

Place aux images et aux explications !

  1. Ouvrez votre objet et passez en « Edit Mode » en appuyant sur Tabulation par exemple, sélectionnez le Vertex (le sommet) clic droit, puis appuyez sur la touche Espace et écrivez « Snap « , une liste devrez apparaître dans laquelle vous sélectionnerez « Snap Cursor To Selected » (Je vous laisse essayer les autres options pour les découvrir par vous même)SnapCursorTo
  2. Ensuite repassez en Object Mode en ré-appuyant sur Tabulation. Une fois fait allez sur votre droite dans l’onglet « Tools » et sélectionnez « Set Origin », « Origin to 3D Cursor »OriginTo3DCursor
  3. Maintenant passez en vue de côté en appuyant sur 1 ou 3 et déplacez votre objet sur l’axe voulu jusqu’à la limite voulue !ToTheAxe
  4. Voilà vous avez déplacer l’Origine de l’objet en un point voulu :)
    Astuce si vous voulez déplacer plus au centre (ici du tronc) votre origine vous pouvez dupliquer un vertex seul, le placer au centre et refaire la manipulation