2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Dagone
Messages : 3
Inscription : 26 Mai 2018 05:00

2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Dagone » 05 Juin 2018 02:42

Bonjour, je suis débutant depuis 6 mois sur Unity et également en programmation.

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.
Image

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);
ce code fonctionne bien dans une scène test simulant la scène sur laquelle je travail. Mais sur cette scène test je n'utilise que des scriptes simplifiés et épurés. La formule ne marche plus une fois implantée dans mon scripte ObjectToPathScript de ma scène de travail, d'où ma détresse...



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;
         }
     }
 }
explications : A placer sur un empty. Cet empty sera dupliqué autant de fois que nécessaire. Il faut alors pour chaque empty, dans l'inspector, glisser les voisins que l'on souhaite connecter à ce node. Il est primordiale qu'un node connecté à son voisin, soit lui-même également connecté chez ce voisin. Il ne peut y avoir que 4 nodes connectés pour chaque node. Les options visible et exploré, sont... optionnelles, et doivent être sur true par défaut.



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;
             }
         }
     }
 }
Explications : Ici, juste placer les différents nodes dans la liste. Le size de la liste dans l'inspector doit être préalablement rempli et correspondre au nombre de nodes faisant parties du path.



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));
         }
     }
 }
Explications : En mettant moveToPath sur true en play mode, l'objet va se déplacer. Dans les options du scripte au niveau de l'inspector, speed et speedFacingDirection doivent etre choisis (genre à 1). Ne touchez pas à l'alphaLevel, il correspond à des options au niveau du PathController que je ne vous ai pas donné (ce que je ferai au besoin). L'objectToMove correspond à un model de mesh optionnel que l'on peut glisser ici, servant de véhicule. Dans le pathToFollow, glisser l'empty Path (celui contenant les nodes). Dans le gameobject planète, se glisse la sphère servant de terrain sur lequel le véhicule circule, et autour duquel les rotations en relation au rotatAround s’effectuent.



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.

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Alesk » 05 Juin 2018 10:43

Salut,

Pourrais-tu nous faire un petit unitypackage contenant déjà une scène d'exemple toute prête stp ? ce serait beaucoup plus simple pour tester... et reproduire ton bug.

Dagone
Messages : 3
Inscription : 26 Mai 2018 05:00

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Dagone » 05 Juin 2018 13:28

Le package de la scène : https://www.dropbox.com/s/yoym4wlv486q2 ... ckage?dl=0

J'y est mis également mon test. il suffit d'activer les scriptes essais, ainsi que les deux sphères essais dans le path.
Merci!

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Alesk » 05 Juin 2018 14:20

ok je matte ça ce soir après le taf et je te répond dans la foulée ... sauf si je suis devancé par quelqu'un :p

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Alesk » 06 Juin 2018 11:41

Bon... là y'a un souci avec le package : les scripts ne sont pas associés sur les gameobjects, donc ça ne fonctionne pas...
Je l'ai importé avec unity 2018.

Dagone
Messages : 3
Inscription : 26 Mai 2018 05:00

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Dagone » 06 Juin 2018 15:45

Arf... J'avais vérifié le package avant, mais bon, c'est mon premier post et mon premier package export... donc ça m'étonne pas de m'y être pris comme un manche. Je retente un package... Merci et désolé du temps perdu. (je l'ai vérifié sur un nouveau projet, celui-ci semble avoir ses scriptes, j'utilise aussi Unity 2018 mais le mien bug de temps à autres.. Si ça ne fonctionne pas, c'est que y'a un truc que j'ai pas compris lors de l'export)

Nouveau Package : Nouvau Package

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Alesk » 06 Juin 2018 17:12

ok merci je retente ce soir :p

Avatar de l’utilisateur
Alesk
Messages : 2303
Inscription : 13 Mars 2012 09:09
Localisation : Bordeaux - France
Contact :

Re: 2018 Unity 3D (C#) pathfinding avec courbes, autours d'une sphère

Message par Alesk » 07 Juin 2018 10:39

Yo !

Bon, j'suis pas pote avec RotateAround, du coup je t'ai fait une autre version plus "simple", uniquement avec des opérations de base sur les vecteurs.

ça donne ça :

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class essai00001 : MonoBehaviour {


	public GameObject planetoide;
	public Transform startPoint;
	public Transform endPoint;

	public float speed = 10;

    Transform _transform;
    Transform _planetTransform;
    Vector3 destination;
    float planetRadius = 1;

    void Start() {

        _transform = this.transform;
        _planetTransform = planetoide.transform;
        destination = endPoint.transform.position;

        planetRadius = _planetTransform.localScale.x * 0.5f;
    }

	void Update()
	{

	
            // récupération de la position actuelle
            Vector3 position = _transform.position;
           
            // calcul de la direction vers le point d'arrivée
            Vector3 direction = (destination - position).normalized;

            float distance = speed * Time.deltaTime;

            // déplacement dans la direction voulue selon la vitesse actuelle
            position += direction * distance;

            // calcul de la verticale sur la sphère à la nouvelle position calculée
            Vector3 up = (position - _planetTransform.position).normalized;

            // recalage de la position pour s'assurer que l'on se trouve bien au niveau du sol
            position = _planetTransform.position + up * planetRadius;

            // pas obligatoire : ajustement de la position si la nouvelle position calculée est trop éloignée de la position théorique exacte
            if (distance > 0.05f)
            {
                Vector3 offsetVector = (position - _transform.position);
                float checkDistance = offsetVector.magnitude;

                if (Mathf.Abs(checkDistance - distance) > 0.01f)
                {
                    position = _transform.position + offsetVector.normalized * distance;
                    up = (position - _planetTransform.position).normalized;
                    position = _planetTransform.position + up * planetRadius;
                }
            }
            // orientation vers la nouvelle position
            transform.LookAt(position , up);

            // mise à jour de la position
            transform.position = position;
                    
	}
}
Au lieu de pivoter autour du centre de la planète, je fais un déplacement en ligne droite vers le point d'arrivée et je recale à chaque fois pour que ça se situe toujours à la surface de la sphere (en utilisant son rayon).
Si jamais tu veux faire la même chose avec un terrain accidenté (donc une sphère irrégulière), il suffit de faire un raycast pour trouver le bon rayon au nouvel emplacement.

Le bloc concernant l'ajustement de la position n'est intéressant que si la vitesse de déplacement est vraiment élevée.

Si tu as des questions...

Répondre

Revenir vers « Scripting »