Je me tourne vers vous, car cela fait maintenant 3 semaines que je galère à essayer de bouger un objet à travers un système de nodes autours d'une sphère, avec un déplacement en courbe donc, entre chaque node rencontré.
Mon idée est la suivante, j'ai une planète qui me sert de carte, et le joueur peut se déplacer dessus d'un point à un autre. Pour cela, j'ai créer mon propre pathfinding. J'avais tenté de mettre en place un dijkstra ou un A*, mais leur fonctionnement m'apparait encore trop complexe. J'en ai donc construit un plus simple, à ma mesure, qui fonctionne parfaitement pour l'utilité que j'en ai. Mon pathfinding fonctionne relativement à des nodes qui détiennent la majorité des informations. L'objet à déplacer, en touchant le collider d'un node, récupère les coordonnées du prochain node sur lequel il va bouger jusqu'à ce qu'il rencontre le node de fin. Tout marche parfaitement, mais j'aimerai que mon objet qui se déplace... mon véhicule... le fasse selon une courbe qui suive la sphère représentant la planète où s’effectue l'action.
Pour cela, j'ai finalement utilisé rotateAround. J'ai essayé le slerp mais ça n'a pas été concluant (je n'ai pas trouvé la bonne formule, mes sauts entre les différents waypoints étaient ultra chaotique), j'ai ensuite tenté les curves quadratiques et cubic, mais c'est encore hors de porté pour moi pour l'instant. La solution devait être simple, du moins suffisamment pour que je la comprenne et l'assimile.
RotateAround sur plusieurs essais, avec sphere, nodes et véhicule bien hiérarchisés, fonctionne bien. Le problème arrive quand j'essaye de l'insérer dans mes scriptes de pathfinding au niveau de ma scène. Et là, je ne comprends pas où peut être mon erreur. J'ai d'abord pensé à une simple étourderie au niveau des hiérarchies, mais non... Puis j'ai essayé d'autres formules, changé au hasard des localPosition en Position et inversement... bref je suis perdu.... aidez moi !
pour vous faire une idée de la hierarchie.
je vous mets mes scriptes, qui marchent parfaitement si on écarte le déplacement relatif à une sphère. Ces scriptes sont au nombre de trois. Le premier est le WaypointScript, à placer sur un empty faisant office de node, que l'on va dupliquer. les nodes sont tous ensemble rangés eux-mêmes dans un empty (le Path) sur lequel on glissera le Pathscript. Cet empty est également rangé dans un autre empty (le PathController, anecdotique ici) qui contient aussi le véhicule sur lequel on glisse l'ObjectToPathScript. Le tout est parenté à une sphère, ma planète, elle-même contenu dans un empty. Pour être rapide, je pense que mon problème se pose à la fin du troisième scripte l'ObjectToPathScript, même si je ne comprend pas pourquoi...
Code : Tout sélectionner
Vector3 targetDir = (nextPosition.localPosition + planetoide.position) - currentPosition.localPosition;
angleToMoveAroundSphere = Vector3.SignedAngle(currentPosition.localPosition, nextPosition.localPosition, planetoide.up);
transform.RotateAround(targetDir, planetoide.up, (angleToMoveAroundSphere * speed) * Time.deltaTime);
Premier scripte, le WaypointScript.
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WaypointScript : MonoBehaviour
{
[Space(5)]
[Header("To Slide")]
[Space(5)]
public List<GameObject> nodesVoisins;
[Space(10)]
[Header("Options")]
[Space(5)]
public bool explored = false; /// if true, le node est opérationnel.
public bool visibleNode = false;
[Space(10)]
[Header("Information")]
[Space(5)]
public bool startNode = false;
public bool endNode = false;
[Space(5)]
public float value;
public Vector3 coordonné;
public Vector3 vecSuivant;
private Color couleur;
void Update()
{
coordonné = gameObject.transform.localPosition;
if (visibleNode == false)
{
explored = false;
}
if (explored == true)
{
if (startNode == true)
{
GetComponentInParent<PathScript>().PositionInitial = gameObject;
}
if (endNode == true)
{
GetComponentInParent<PathScript>().destination = gameObject;
GetComponentInParent<PathScript>().endSelected = true;
vecSuivant = coordonné;
value = 0;
}
if (endNode == false)
{
if (GetComponentInParent<PathScript>().endSelected == true)
{
float distTotal = Vector3.Distance(GetComponentInParent<PathScript>().PositionInitial.transform.localPosition, GetComponentInParent<PathScript>().destination.transform.localPosition);
float distwaypointToEnd = Vector3.Distance(GetComponentInParent<PathScript>().destination.transform.localPosition, coordonné);
value = Mathf.Abs((distTotal * distwaypointToEnd) / 2);
if (nodesVoisins.Count == 1)
{
foreach (var voisin in nodesVoisins)
{
vecSuivant = voisin.GetComponent<WaypointScript>().coordonné;
}
}
if (nodesVoisins.Count == 2)
{
foreach (var voisin in nodesVoisins)
{
if (nodesVoisins[0].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[0].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[1].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[1].GetComponent<WaypointScript>().coordonné;
}
}
}
if (nodesVoisins.Count == 3)
{
foreach (var voisin in nodesVoisins)
{
if (nodesVoisins[0].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[0].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[1].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[1].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[2].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[2].GetComponent<WaypointScript>().coordonné;
}
}
}
if (nodesVoisins.Count == 4)
{
foreach (var voisin in nodesVoisins)
{
if (nodesVoisins[0].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value, nodesVoisins[3].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[0].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[1].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value, nodesVoisins[3].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[1].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[2].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value, nodesVoisins[3].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[2].GetComponent<WaypointScript>().coordonné;
}
if (nodesVoisins[3].GetComponent<WaypointScript>().value == Mathf.Min(nodesVoisins[0].GetComponent<WaypointScript>().value, nodesVoisins[1].GetComponent<WaypointScript>().value, nodesVoisins[2].GetComponent<WaypointScript>().value, nodesVoisins[3].GetComponent<WaypointScript>().value))
{
vecSuivant = nodesVoisins[3].GetComponent<WaypointScript>().coordonné;
}
}
}
}
}
}
if (explored == false)
{
value = float.MaxValue;
}
}
private void OnDrawGizmos()
{
if (nodesVoisins == null)
{
return;
}
Gizmos.color = couleur;
couleur = Color.blue;
Gizmos.DrawWireCube(transform.position, new Vector3(1, 1, 1));
foreach (var nodeConnect in nodesVoisins)
{
if (nodeConnect != null)
Gizmos.DrawLine(transform.position, nodeConnect.transform.position);
}
if (startNode == true)
{
couleur = Color.green;
}
if (endNode == true)
{
couleur = Color.red;
}
}
}
Deuxième scripte, le PathScrit.
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PathScript : MonoBehaviour
{
[Space(5)]
[Header("To Slide")]
[Space(5)]
public GameObject objectToMove;
public List<GameObject> nodes; // place the nodes here
[Space(10)]
[Header("Information")]
[Space(5)]
public bool endSelected = false;
[Space(5)]
public GameObject PositionInitial;
public GameObject destination;
private void Start()
{
if (PositionInitial == null)
{
PositionInitial = nodes[0];
nodes[0].GetComponent<WaypointScript>().startNode = true;
}
foreach (var node in nodes)
{
if (node.GetComponent<WaypointScript>().coordonné == objectToMove.transform.localPosition)
{
objectToMove.GetComponent<ObjectToPathScript>().onPath = true;
}
}
}
}
Le troisième, l'ObjectToPathScript. Le script d'où je pense que le problème provient.
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectToPathScript : MonoBehaviour
{
[Space(5)]
[Header("Move")]
[Space(5)]
public bool moveToPath = false; // move function
[Space(10)]
[Header("Options")]
[Space(5)]
public float speed;
public float speedFacingDirection;
public float alphaLevel = .5f;
[Space(10)]
[Header("To Slide")]
[Space(5)]
public GameObject objectToMove;
public GameObject pathToFollow;
public GameObject planete;
[Space(10)]
[Header("Information")]
[Space(5)]
public bool onPath = false;
[Space(5)]
public Vector3 targetVector;
public Vector3 vehiculePosition;
[Space(5)]
public bool inverseAlpha = false;
public bool decreaseAlpha = false;
private int randomNode;
public float angleToMoveAroundSphere; // variables and objects to turnAround
public Transform planetoide; //
public Transform currentPosition; //
public Transform nextPosition; //
public GameObject nextNode; //
void Update()
{
if (planete != null) //
{
////////////////////////////////// here, just to be able to manipulate my positions effectively
foreach (var node in pathToFollow.GetComponent<PathScript>().nodes)
{
if (targetVector == node.GetComponent<WaypointScript>().coordonné)
{
nextNode = node;
}
}
planetoide = planete.transform;
nextPosition = nextNode.transform;
currentPosition = transform;
////////////////////////////////////////////////////////////////////
}
if (inverseAlpha == true)
{
if (alphaLevel <= 1f)
{
alphaLevel += .05f;
}
}
if (decreaseAlpha == true)
{
if (alphaLevel >= 0)
{
alphaLevel -= .05f;
}
}
objectToMove.GetComponent<Renderer>().material.color = new Color(objectToMove.GetComponent<Renderer>().material.color.r, objectToMove.GetComponent<Renderer>().material.color.g, objectToMove.GetComponent<Renderer>().material.color.b, alphaLevel);
if (onPath != true)
{
vehiculePosition = this.transform.localPosition;
targetVector = pathToFollow.GetComponent<PathScript>().PositionInitial.GetComponent<WaypointScript>().coordonné;
inverseAlpha = false;
decreaseAlpha = true;
}
if (onPath != true && pathToFollow.GetComponent<PathScript>().endSelected == true && moveToPath == true)
{
inverseAlpha = true;
decreaseAlpha = false;
if (planete != null)
{
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
}
transform.localPosition = Vector3.MoveTowards(transform.localPosition, targetVector, speed * Time.deltaTime);
Vector3 vector = targetVector - transform.localPosition;
transform.rotation = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, vector, speedFacingDirection * Time.deltaTime, 0.0f));
}
if (transform.localPosition == targetVector)
{
onPath = true;
}
if (transform.localPosition != targetVector && moveToPath == true && onPath == true)
{
StartCoroutine(MicroTimerBeforeMove());
}
}
void OnTriggerStay(Collider other)
{
if (!other.tag.Equals("moonTarget") == true) // sphere target tag is call moontarget
{
if (planete != null)
{
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
}
if (transform.localPosition == other.transform.localPosition)
{
targetVector = other.GetComponent<WaypointScript>().vecSuivant;
if (other.GetComponent<WaypointScript>().endNode == true && moveToPath == true)
{
if (gameObject.GetComponentInParent<PathController>().pathMode == true && gameObject.GetComponentInParent<PathController>().loopMode == false && gameObject.GetComponentInParent<PathController>().randomLoop == false)
{
moveToPath = false;
inverseAlpha = false;
decreaseAlpha = true;
foreach (var node in pathToFollow.GetComponent<PathScript>().nodes)
{
node.GetComponent<WaypointScript>().startNode = false;
node.GetComponent<WaypointScript>().endNode = false;
other.GetComponent<WaypointScript>().startNode = true;
}
pathToFollow.GetComponent<PathScript>().endSelected = false;
}
if (gameObject.GetComponentInParent<PathController>().loopMode == true && gameObject.GetComponentInParent<PathController>().pathMode == false && gameObject.GetComponentInParent<PathController>().randomLoop == false)
{
foreach (var node in pathToFollow.GetComponent<PathScript>().nodes)
{
if (node.GetComponent<WaypointScript>().startNode == true)
{
node.GetComponent<WaypointScript>().startNode = false;
node.GetComponent<WaypointScript>().endNode = true;
}
other.GetComponent<WaypointScript>().endNode = false;
other.GetComponent<WaypointScript>().startNode = true;
}
}
if (gameObject.GetComponentInParent<PathController>().randomLoop == true && gameObject.GetComponentInParent<PathController>().loopMode == false && gameObject.GetComponentInParent<PathController>().pathMode == false)
{
foreach (var node in pathToFollow.GetComponent<PathScript>().nodes)
{
node.GetComponent<WaypointScript>().startNode = false;
node.GetComponent<WaypointScript>().endNode = false;
}
other.GetComponent<WaypointScript>().startNode = true;
randomNode = Random.Range(0, pathToFollow.GetComponent<PathScript>().nodes.Count);
pathToFollow.GetComponent<PathScript>().nodes[randomNode].GetComponent<WaypointScript>().endNode = true;
}
}
}
}
}
IEnumerator MicroTimerBeforeMove()
{
inverseAlpha = true;
decreaseAlpha = false;
yield return new WaitForFixedUpdate();
//////////////////////////////////////////////// my big trouble begin here
if (planete != null)
{
//foreach(var node in pathToFollow.GetComponent<PathScript>().nodes)
//{
// if (targetVector == node.GetComponent<WaypointScript>().coordonné)
//// {
// nextNode = node;
// }
//}
// planetoide = planete.transform;
//nextPosition = nextNode.transform.localPosition;
//currentPosition = transform.localPosition;
// here, it's the heart of the probleme
Vector3 targetDir = (nextPosition.localPosition + planetoide.position) - currentPosition.localPosition;
angleToMoveAroundSphere = Vector3.SignedAngle(currentPosition.localPosition, nextPosition.localPosition, planetoide.up);
transform.RotateAround(targetDir, planetoide.up, (angleToMoveAroundSphere * speed) * Time.deltaTime);
//Vector3 targetDir = (targetVector + planetoide.position) - vehiculePosition;
//angleToMoveAroundSphere = Vector3.SignedAngle(vehiculePosition, targetVector, planetoide.up);
//transform.RotateAround(targetDir, planetoide.up, (angleToMoveAroundSphere * speed) * Time.deltaTime);
Debug.Log("....angle..." + angleToMoveAroundSphere + "..direction...." + targetDir + "....current position..." + currentPosition.position + "...current local..." + currentPosition.localPosition + "....next position..." + nextPosition.position + "...next local..." + nextPosition.localPosition);
}
////////////////////////////////////////////////////////////////////
if (planete == null)
{
transform.localPosition = Vector3.MoveTowards(transform.localPosition, targetVector, speed * Time.deltaTime);
Vector3 vector = targetVector - transform.localPosition;
transform.rotation = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, vector, speedFacingDirection * Time.deltaTime, 0.0f));
}
}
}
Voilà, je suis à bout, j’arrête de fumer et ma femme est une sorcière, j’espère que vous pourrez m'aider. Pour les débutants, n'hésitez pas à reprendre ces scriptes, je me suis tellement creusé la cervelle à essayer de comprendre comment un pathfinding pouvait fonctionner sans jamais trouver un scripte simple et basique sur lequel me reposer.. et les tutos sont souvent déjà d'un niveau si complexe qu'on marche à l'aveugle sans réellement comprendre ce que l'on code. Bref si ça peut aider l'un d'entre vous à défaut d'une réponse à ma question.
Sinon, pour revenir à mon histoire, je cherche une solution simple et compréhensible pour faire des courbes. En effet, il me tiens à cœur de comprendre ce que je fais et d'avancer pas à pas dans mes tribulations sur unity, notamment en construisant mes outils de A à Z (aussi, nul besoin de me proposer d'utiliser Itween). Si vous avez des questions, des réponses, des optimisations en tête, n'hésitez pas, je prends ! (je poste aussi mon problème sur le forum officiel pour ceux que ça intéresse (dans un anglais très approximatif), vous le trouverez en cherchant sur answers.unity.com : How to rotate object through waypoints on a curved path on sphere).
Passez une bonne journée (nuit), et merci.