[RESOLU] Rotation Click and go
[RESOLU] Rotation Click and go
Bonjour,
Je fais un jeu dans lequel je déplace mon personnage sur une map dans un style échiquiers. Il y a des cases et j'avance de case en case.
J'ai un chemin qui est defini lorsque je clique sur un endroit de la map, et mon personnage se déplace jusque l'endroit en question.
Je voudrais, en plus de ce déplacement, que le personnage effectue une rotation vers l'endroit ou il va.
Savez vous comment tourner un objet par rapport a un vecteur de base et un de destination ?
Je fais un jeu dans lequel je déplace mon personnage sur une map dans un style échiquiers. Il y a des cases et j'avance de case en case.
J'ai un chemin qui est defini lorsque je clique sur un endroit de la map, et mon personnage se déplace jusque l'endroit en question.
Je voudrais, en plus de ce déplacement, que le personnage effectue une rotation vers l'endroit ou il va.
Savez vous comment tourner un objet par rapport a un vecteur de base et un de destination ?
Dernière édition par DJ-OMZ le 17 Mai 2017 10:53, édité 1 fois.
Re: Rotation Click and go
Salut,
Il suffit d'utiliser la fonction RotateTowards
https://docs.unity3d.com/ScriptReferenc ... wards.html
Il suffit d'utiliser la fonction RotateTowards
https://docs.unity3d.com/ScriptReferenc ... wards.html
“La théorie, c'est quand on sait tout et que rien ne fonctionne. La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : Rien ne fonctionne... et personne ne sait pourquoi !”
Re: Rotation Click and go
D'accord et c'est bien ce que j'ai fait, mais comment faire une comparaison pour savoir quand la rotation est bien complete et qu'il n'y a plus besoin de tourner ?evereal a écrit :Salut,
Il suffit d'utiliser la fonction RotateTowards
https://docs.unity3d.com/ScriptReferenc ... wards.html
Dans mon test j'ai un comportement que je ne comprends pas...
Code : Tout sélectionner
public class Unit : MonoBehaviour
{
public int tileX;
public int tileZ;
public TileMap map;
int compteur = 1;
public bool arrivee = true;
bool rotationTerminee = true;
public List<Node> currentPath = null;
void Update()
{
if (currentPath != null)
{
arrivee = false;
rotationTerminee = false;
MoveToNextTile();
}
}
public void MoveToNextTile() //Cette methode va appeler la rotation a chaque noeud, faire tourner puis deplacer
{
if (!arrivee)
{
//On récupère noeud par noeud
Vector3 destination = map.TileToWorld(currentPath[compteur].x, currentPath[compteur].z) + new Vector3(0, 0, 0);
if (transform.position == destination)
{
compteur++;
rotationTerminee = false;
if (compteur == currentPath.Count)
{
tileX = currentPath[compteur - 1].x;
tileZ = currentPath[compteur - 1].z;
arrivee = true;
rotationTerminee = true;
compteur = 1;
currentPath = null;
}
}
else //En gros, pour chaque noeud, on appelle ce else, et quand on est arrivé a la position, on passe au noeud suivant
{
LookAtNextTile(destination); //Ma super methode de rotation qui marche po
if (rotationTerminee) //On tourne PUIS on avance
{
transform.position = Vector3.MoveTowards(transform.position, destination, 8f * Time.deltaTime);
}
}
}
}
public void LookAtNextTile(Vector3 destination)
{
Vector3 vectorRotation = Vector3.RotateTowards(transform.forward, destination, 0.2f, 0);
transform.rotation = Quaternion.LookRotation(vectorRotation);
if (Quaternion.LookRotation(transform.forward) == Quaternion.LookRotation(destination))
{
rotationTerminee = true;
}
}
}
Re: Rotation Click and go
remplace
par
Code : Tout sélectionner
Vector3 vectorRotation = Vector3.RotateTowards(transform.forward, destination, 0.2f, 0);
Code : Tout sélectionner
Vector3 targetDir = destination - transform.position;
Vector3 vectorRotation = Vector3.RotateTowards(transform.forward, targetDir , 0.2f, 0);
“La théorie, c'est quand on sait tout et que rien ne fonctionne. La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : Rien ne fonctionne... et personne ne sait pourquoi !”
Re: Rotation Click and go
Code : Tout sélectionner
//previousTile est la case actuelle, destination est la case suivante, a chaque fois.
public void LookAtNextTile(Vector3 destination)
{
Debug.Log("Rotation Terminée : " + rotationTerminee);
Debug.Log("PreviousTile : " + previousTile);
Debug.Log("Destination : " + destination);
Vector3 targetRotation = destination - previousTile;
Vector3 vectorRotation = Vector3.RotateTowards(transform.forward, targetRotation, 0.2f, 0);
transform.rotation = Quaternion.LookRotation(vectorRotation);
if (Quaternion.LookRotation(previousTile) == Quaternion.LookRotation(destination)) // C'est ici que je sais pas comment faire...
{
Debug.Log("Rotation finite !");
rotationTerminee = true;
}
}
- boubouk50
- ModoGenereux
- Messages : 6220
- Inscription : 28 Avr 2014 11:57
- Localisation : Saint-Didier-en-Bresse (71)
Re: Rotation Click and go
Alors il ne faut pas comparer strictement les variables. Certaines ne sont pas possibles. Au mieux utiliser un delta pour dire "si c'est très proche on fait pas".
Ici il vaut mieux comparer l'angle entre les deux quaternions pour déterminer l'égalité. Si sa valeur absolue est inférieure au delta que tu te donnes (0.5° par ex) alors tu arrêtes.
Ici il vaut mieux comparer l'angle entre les deux quaternions pour déterminer l'égalité. Si sa valeur absolue est inférieure au delta que tu te donnes (0.5° par ex) alors tu arrêtes.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation
Re: Rotation Click and go
Je suis vraiment désolé mais je ne comprends pas ce qui se passe.... Le Delta me donne des resultats bizarres, et c'est bien a ce niveau la que j'ai mon soucis :
J'ai un comportement que je ne comprend pas :
Si je clique tout a droite : Mon objet tourne, puis une fois qu'il fait face a droite, il y va. Une fois arrivé, je refais un déplacement n'importe ou ailleurs, tant que ce déplacement me demande une rotation, et pouf, ça marche plus....
Si je vais en diagonale (donc d'abord tout droit puis un virage), je vais tourner au niveau du virage et puis hop, j'avance plus.
Dans les 2 cas je suis dans la boucle infinie de la rotation..... Je suis totalement perdu la.
Pourquoi est-ce que ça fonctionne une fois et pas 2 ? Je vois vraiment pas d'ou vient le problème. Et les angles sont bloqués, a 180 dans un cas, et dans d'autres cas, a 71.56, 68, des nombres bizarres comme ça alors que mon objet, visuellement, a fait la rotation exacte...
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Unit : MonoBehaviour
{
public int tileX;
public int tileZ;
public TileMap map;
int compteur = 1;
public bool arrivee = true;
bool rotationTerminee = false;
Vector3 previousTile;
public List<Node> currentPath = null;
void Start()
{
previousTile = transform.position;
}
void Update()
{
if (currentPath != null)
{
//int currNode = 0;
arrivee = false;
//while (currNode < currentPath.Count - 1)
//{
// Vector3 start = map.TileToWorld(currentPath[currNode].x, currentPath[currNode].z) + new Vector3(0, 1, 0);
// Vector3 end = map.TileToWorld(currentPath[currNode + 1].x, currentPath[currNode + 1].z) + new Vector3(0, 0, 0);
// Debug.DrawLine(start, end, Color.red);
// //Debug.Log("Arrivée : " + end);
// currNode++;
//}
MoveToNextTile();
}
}
public void MoveToNextTile()
{
if (!arrivee)
{
Vector3 destination = map.TileToWorld(currentPath[compteur].x, currentPath[compteur].z) + new Vector3(0, 0, 0);
if (transform.position == destination)
{
Debug.Log("Next Tile");
compteur++;
previousTile = destination;
rotationTerminee = false;
if (compteur == currentPath.Count)
{
tileX = currentPath[compteur - 1].x;
tileZ = currentPath[compteur - 1].z;
arrivee = true;
compteur = 1;
currentPath = null;
}
}
else
{
if (rotationTerminee)
{
Debug.Log("On se déplace");
transform.position = Vector3.MoveTowards(transform.position, destination, 8f * Time.deltaTime);
} else
{
LookAtNextTile(destination);
}
}
}
}
public void LookAtNextTile(Vector3 destination)
{
Debug.Log("Rotation Terminée : " + rotationTerminee);
Debug.Log("PreviousTile : " + previousTile);
Debug.Log("Destination : " + destination);
Vector3 targetRotation = destination - previousTile;
Vector3 vectorRotation = Vector3.RotateTowards(transform.forward, targetRotation, 0.2f, 0);
Debug.Log("Delta : " + Quaternion.Angle(Quaternion.LookRotation(vectorRotation), Quaternion.LookRotation(destination)));
transform.rotation = Quaternion.LookRotation(vectorRotation);
if (Quaternion.LookRotation(vectorRotation) == Quaternion.LookRotation(destination))
{
Debug.Log("Rotation finite !");
rotationTerminee = true;
}
}
}
Si je clique tout a droite : Mon objet tourne, puis une fois qu'il fait face a droite, il y va. Une fois arrivé, je refais un déplacement n'importe ou ailleurs, tant que ce déplacement me demande une rotation, et pouf, ça marche plus....
Si je vais en diagonale (donc d'abord tout droit puis un virage), je vais tourner au niveau du virage et puis hop, j'avance plus.
Dans les 2 cas je suis dans la boucle infinie de la rotation..... Je suis totalement perdu la.
Pourquoi est-ce que ça fonctionne une fois et pas 2 ? Je vois vraiment pas d'ou vient le problème. Et les angles sont bloqués, a 180 dans un cas, et dans d'autres cas, a 71.56, 68, des nombres bizarres comme ça alors que mon objet, visuellement, a fait la rotation exacte...
- boubouk50
- ModoGenereux
- Messages : 6220
- Inscription : 28 Avr 2014 11:57
- Localisation : Saint-Didier-en-Bresse (71)
Re: Rotation Click and go
Comme je te l'ai déjà dit, il ne faut pas comparer strictement n'importe quelles variables. Typiquement:
Tu compares 2 Vector3 qui sont composés de floats. Donc tu compares 3x2 floats entre eux. Les floats sont des nombres décimaux approximatifs, les comparer est très risqué puisqu'ils ne sont pas exacts.
Ainsi, ton perso peut être à 0.000001 de son objectif qu'il n'est pas considéré comme arrivé. Il faut donc border tout cela. Comme les quaternions avant où on teste l'angle entre les 2 directions (ou bien le dot product), ici il faut tester la distance entre les deux positions. Si elle est inférieur à un delta (10 cm par exemple) alors tu peux considérer que ton personnage est arrivé.
Toute variable qui est indéfinie ou approximative (dans le sens Pi = 3.14... est un nombre indéfini) ne doit pas être comparée telle quelle avec une autre.
Code : Tout sélectionner
if (transform.position == destination)
Ainsi, ton perso peut être à 0.000001 de son objectif qu'il n'est pas considéré comme arrivé. Il faut donc border tout cela. Comme les quaternions avant où on teste l'angle entre les 2 directions (ou bien le dot product), ici il faut tester la distance entre les deux positions. Si elle est inférieur à un delta (10 cm par exemple) alors tu peux considérer que ton personnage est arrivé.
Toute variable qui est indéfinie ou approximative (dans le sens Pi = 3.14... est un nombre indéfini) ne doit pas être comparée telle quelle avec une autre.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation
Re: Rotation Click and go
Je comprends. En fait j'ai mis un déplacement de 0.2f vers la destination, et chaque case est a 1 de distance des cases voisines. C'est pour ça que ici, la comparaison des Vector3 ne pose pas de problèmes. Mais pour être sûr, je vais suivre ton conseil.
La ou se situe l'erreur, c'est dans la méthode LookAtNextTile.
Quand je fais un premier mouvement, tout roule, ça marche nickel, ça tourne, ça avance. Mais si j'ai une autre rotation a faire après, en faisant un second déplacement par exemple, c'est la que j'ai mon erreur.
J'ai mis un debug qui affiche le delta :
Mais j'obtiens des deltas importants, 63, 78 ect... Et du coup je suis dans la boucle infinie puisque mon booléen rotationTerminee ne passe pas a vrai.
Je ne pige pas car pour le premier mouvement, tout fonctionne nickel...
La ou se situe l'erreur, c'est dans la méthode LookAtNextTile.
Quand je fais un premier mouvement, tout roule, ça marche nickel, ça tourne, ça avance. Mais si j'ai une autre rotation a faire après, en faisant un second déplacement par exemple, c'est la que j'ai mon erreur.
J'ai mis un debug qui affiche le delta :
Code : Tout sélectionner
Debug.Log("Delta : " + Quaternion.Angle(Quaternion.LookRotation(vectorRotation), Quaternion.LookRotation(destination)));
Je ne pige pas car pour le premier mouvement, tout fonctionne nickel...
- boubouk50
- ModoGenereux
- Messages : 6220
- Inscription : 28 Avr 2014 11:57
- Localisation : Saint-Didier-en-Bresse (71)
Re: Rotation Click and go
Tu compares une direction vers un point dans l'espace avec une direction vers un vecteur de direction (ce qui ne veut rien dire). Tu as de la chance que ça marche la première fois, je dirai.
Il faut comparer ta rotation actuelle (this.transform.rotation) avec celle finale (Quaternion.LookRotation(destination)).
Il faut comparer ta rotation actuelle (this.transform.rotation) avec celle finale (Quaternion.LookRotation(destination)).
Code : Tout sélectionner
Debug.Log("Delta : " + Quaternion.Angle(this.transform.rotation, Quaternion.LookRotation(destination)));
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation