http://www.unity3d-france.com/unity/php ... 12&t=16068
C'est un jeu de puzzle 3D dans lequel le perso doit déclencher des interrupteurs, on va les appeler comme ça, pour générer une impulsion dans un circuit électrique (d'où le nom) pour ouvrir des portails afin de libérer le passage vers la sortie.
Pour déplacer le perso que j'appelle Mimi il faut cliquer sur le chemin, et il va vers l'endroit où on a cliqué en suivant le chemin le plus court.
J'ai bien sûr fait un script pour cela que je vais vous présenter afin que vous puissiez me dire votre avis et comment améliorer les choses si nécessaire.
Il comprend une petite classe qui me permet d'éviter "Dictionary" que j'aime pas trop :
Code : Tout sélectionner
public class DataChemin
{
public int Key;
public List<GameObject> Chemin;
public DataChemin() { }
public DataChemin(int key, List<GameObject> chemin)
{
Key = key;
Chemin = chemin;
}
}
On peut voir aussi une fonction publique qui permet l'initialisation qui peut être et même doit être exécutée dès que le niveau est en place, sauf s'il est sujet à des modifications en cours de jeu:
Code : Tout sélectionner
[SerializeField]
List<GameObject> Cellules;
/// <summary>
/// Liste les cellules du jeu
/// Il vaut mieux appeler cette fonction dès que le niveau est créé
/// si les celules restent fixes, pour éviter qu'elle soit appelée
/// à chaque clic pour déplacer le player.
/// </summary>
public void DefinitCellulesEtVoisins()
{
Cellules = new List<GameObject>();
foreach (var item in GameObject.FindGameObjectsWithTag("Cellule"))
{
Cellules.Add(item);
}
DefinitLesVoisins();
}
/// <summary>
/// Parcours toutes les celules et ajoute à Voisins de chacune les cellules
/// qui sont à 1 case de décalage dans chaque direction
/// </summary>
private void DefinitLesVoisins()
{
//Definit les voisins
foreach (var item1 in Cellules)
{
foreach (var item2 in Cellules)
{
if (item1 != item2)
{
if (item1.transform.position + Vector3.forward == item2.transform.position ||
item1.transform.position + Vector3.back == item2.transform.position ||
item1.transform.position + Vector3.right == item2.transform.position ||
item1.transform.position + Vector3.left == item2.transform.position)
{
if (!item1.GetComponent<Tile>().Voisins.Contains(item2))
item1.GetComponent<Tile>().Voisins.Add(item2);
if (!item2.GetComponent<Tile>().Voisins.Contains(item1))
item2.GetComponent<Tile>().Voisins.Add(item1);
}
}
}
}
}
Code : Tout sélectionner
[SerializeField]
GameObject start;
[SerializeField]
GameObject end;
[SerializeField]
List<DataChemin> Paths;
[SerializeField]
public List<GameObject> Path;
[SerializeField]
GameObject EnCours;
/// <summary>
/// L'appel de la fonction
/// </summary>
/// <param name="depart">La cellule de départ de Mimi</param>
/// <param name="arrivee">La cellule ou elle doit arriver</param>
internal void DefinitCheminMimi(GameObject depart, GameObject arrivee)
{
//si on veut initialiser les cellules à chaque fois
DefinitCellulesEtVoisins();
start = depart;
end = arrivee;
RechercheChemin();
}
/// <summary>
/// On recherche le chemin le plus court qui pourra être utilise
/// Path contiendra le chemin à utiliser
/// </summary>
void RechercheChemin()
{
InitCellules();
int c = 0;
Paths = new List<DataChemin>();
retour:
Path = new List<GameObject>();
EnCours = start;
Path.Add(EnCours);
EnCours.GetComponent<Tile>().Visite = true;
RechercheCheminPossible(); //dans Path, le résultat de la recherche
//si la longueur du chemin est courte on sort
if (Path.Count > 0 && Path.Count < 5)
return;
//sinon on stoque le chemin
if (Path.Count > 1)
Paths.Add(new DataChemin(c, Path));
c++;
//on repart au départ
EnCours = start;
//on va au premier carrefour et on recherche un autre chemin
if (RechercheCarrefour(EnCours))
goto retour;
//s'il n'y a pas de carrefour, ou que tout a été visité
if (Paths.Count > 0)
//on recherche le chemin le plus court et on sort
RechercheLePlusCourt();
}
/// <summary>
/// Met la valeur Visite de toutes les cellules à false
/// </summary>
void InitCellules()
{
foreach (GameObject item in Cellules)
{
if (item != null)
item.GetComponent<Tile>().Visite = false;
}
}
void RechercheCheminPossible()
{
retour:
//s'il y a une cellule voisine à de la cellule en cours
if (RechercheCarrefour(EnCours))
{
//on l'ajoute au chemin
Path.Add(EnCours);
EnCours.GetComponent<Tile>().Visite = true;
//si on est arrivé
if (EnCours == end)
{
//on demarque visité de la dernière cellule en cas de recherche supplémentaire et on sort
end.GetComponent<Tile>().Visite = false;
return;
}
//sinon on continue
goto retour;
}
//il n'y a pas de cellule accessible autour de la cellule en cours
for (int i = Path.Count - 1; i > -1; i--)
{
//on remonte le chemin à la recherche d'un carrefour
if (!RechercheCarrefour(Path[i]))
{
Path.Remove(Path[i]);
}
else
{
//on reprend à partir du carrefour
EnCours = Path[i];
goto retour;
}
}
return;
}
/// <summary>
/// Recherche une cellule libre autour de la cellule donnée.
/// </summary>
/// <param name="cellule"></param>
/// <returns>retourne true si il y a une cellule libre et EnCours contient la cellule libre trouvée</returns>
bool RechercheCarrefour(GameObject cellule)
{
foreach (var item in cellule.GetComponent<Tile>().Voisins)
{
if (item != null && item.gameObject.activeSelf)
if (!item.GetComponent<Tile>().Visite)
{
EnCours = item;
return true;
}
}
return false;
}
/// <summary>
/// "Chemin" sera égal au chemin le plus petit entre plusieurs chemins contenus dans "Chemins"
/// </summary>
private void RechercheLePlusCourt()
{
Path = Paths[0].Chemin;
foreach (DataChemin item in Paths)
{
if (item.Chemin.Count < Path.Count)
Path = item.Chemin;
}
}
S'il y a des félicitations vous pouvez aussi, ça fait toujours plaisir,
et si ça peut aider certains je serais ravi de le savoir
A bientôt...