4 réflexions au sujet de “Pathfinding fait maison sauce C#”
Salut Marama,
utilises-tu des fonctions récursives pour faire ce genre de truc ?
Coucou Syllius,
Je ne connaît pas trop bien le concept de recursivité , je ne penses pas en utiliser. J’emploie un système d’aller retour entre deux fonctions :
par exemple une première fonction va sonder les cases adjacentes
ensuite une deuxième fonction va immédiatement mémoriser et traiter l’information (par exemple comparer la nouvelle valeur avec l’ancienne mémorisée et décider si oui ou non on la conserve ou on l’oublie)
En gros à chaque cellule sondées, je traite l’information immédiatement jusqu’à la fin.
voici le bout de code de mon PathFindeEngine
` public void PathfinderEngine(int i_value, int j_value)
// i_value et j_value correspondent aux coordonnées de la cellule mère à traiter
// nous devons traiter toute ses cellules filles adjacentes
{
if (begin_pathfinding ) // autorise le calcul du Pathfinding
{
int memorized_value = open_map[i_value, j_value, 0]; // c’est la valeur H+G de la cellule mère
int best_minimum_value = memorized_value; // on initialise un première mémoire tampon
int current_value_scanning = memorized_value; // on initialise une deuxième mémoire tampon
// prélever les coordonnées
int i_memorized = i_value; // j’enregistre l’abcsisse de la cellule mère
int j_memorized = j_value; // j’enregistre l’ordonnées de la cellule mère
// je prépare mes valeurs tampon pour le traitement des cases adjacentes
int _i_moins = i_value – 1; // à gauche
int _i_plus = i_value + 1; // à droite
int _j_moins = j_value – 1; // en haut
int _j_plus = j_value + 1; // en bas
// je place mes mouchards (lisible dans SORTIE) : voir menu Affichage
Console.WriteLine(« current i,j dans le moteur de pathfinding : » + i_value.ToString() + » / » + j_value.ToString());
Console.WriteLine(« au début old_values i,j » + old_path_node_i_value.ToString() + » / » + old_path_node_j_value.ToString());
// je vérifie que la cible n’est pas égal au point de départ
// point de départ : (old_path_node_i_value , old_path_node_j_value)
if (i_value == old_path_node_i_value && j_value == old_path_node_j_value)
{
// si OUI : je créé une alerte et je lance mon compteur debug_path
// son rôle : éjecter du programme et tout remettre par défaut pour éviter les boucles infinies
Console.WriteLine(« alerte debug!!! « );
debug_path += 1;
}
// je vérifie que la cible n’est pas égal au point de départ
// point de départ : (old_path_node_i_value , old_path_node_j_value)
if (old_path_node_i_value != i_value || old_path_node_j_value != j_value)
{
// si NON : la cible n’est pas le point de départ
// en haut
if (_j_moins >= 0 // vérifier que je reste dans l’index de ma tilemap
&& map[i_value, _j_moins] > 0
&& open_map[i_value, _j_moins, 0] >= 0)
{
// je prélève la valeur enregistrée dans mon tableau
current_value_scanning = open_map[i_value, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
// en bas + ** vérifier si c'est un mur
if (_j_plus 0
&& open_map[i_value, _j_plus, 0] >= 0)
{
current_value_scanning = open_map[i_value, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0// vérifier que je reste dans l’index de ma tilemap
&& _j_moins >= 0
&& map[_i_moins, _j_moins] > 0
&& open_map[_i_moins, _j_moins, 0] >= 0)
{
current_value_scanning = open_map[_i_moins, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0// vérifier que je reste dans l’index de ma tilemap
&& map[_i_moins, j_value] > 0
&& open_map[_i_moins, j_value, 0] >= 0)
{
current_value_scanning = open_map[_i_moins, j_value, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0 /// à gauche // vérifier que je reste dans l’index de ma tilemap
&& _j_plus 0 /// ne contient pas de mur
&& open_map[_i_moins, _j_plus, 0] >= 0) /// contient une valeur traitée dans open_map()
{
current_value_scanning = open_map[_i_moins, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
//en haut à droite + ** vérifier si c'est un mur
if (_i_plus = 0 // vérifier que je reste dans l’index de ma tilemap
&& map[_i_plus, _j_moins] > 0
&& open_map[_i_plus, _j_moins, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = _i_plus;
j_memorized = _j_moins;
}
}
//à droite + ** vérifier si c'est un mur
if (_i_plus 0 // vérifier que je reste dans l’index de ma tilemap
&& open_map[_i_plus, j_value, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, j_value, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = _i_plus;
j_memorized = j_value;
}
}
//en bas à droite + ** vérifier si c'est un mur
if (_i_plus < limit_i_value // vérifier que je reste dans l'index de ma tilemap
&& _j_plus 0
&& open_map[_i_plus, _j_plus, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning 80)
{
begin_pathfinding = false; // je cloture le programme
stop_pathfinding = true;
move_the_sprite = false;
force_eject = true;
Console.WriteLine(« le moteur de pathfinding a rencontré une erreur, nous l’avons forcé à s’arrêter »);
item.IsHidden = true; // je cache l’icone de recherche
// mon programme est bouclé
}
// je met à jour les valeurs à controler
i_path_value = i_memorized;
j_path_value = j_memorized;
// je sécurise la méthode pour pouvoir y mettre fin en cas de PB
old_path_node_i_value = i_value; // l’abscisse de la cellule mère est enregistrée et sera comparée ultrieurement
old_path_node_j_value = j_value; // l’ordonées de la cellule mère est enregistrée et sera comparés ultrieurement
// old_path_node_i_value et old_path_node_j_value sont des variables déclarées au début de la classe
}
}’
Une fonction récursive est une fonction qui s’appelle d’elle-même, c’est ce que j’ai utilisé dans l’atelier sur IA où j’ai programmé un monstre qui pourchasse le héro dans un labyrinthe (.
Ca permet de condenser considérablement le code également. Je te link le lien de la fonction récursive utilisée : .
Il est important d’avoir une condition d’arrêt sinon on pourrait se retrouver avec des appels de fonctions à l’infini. Dans mon cas la profondeur de recherche était limité à 5 cases.
4 réflexions au sujet de “Pathfinding fait maison sauce C#”
Salut Marama,
utilises-tu des fonctions récursives pour faire ce genre de truc ?
Coucou Syllius,
Je ne connaît pas trop bien le concept de recursivité , je ne penses pas en utiliser. J’emploie un système d’aller retour entre deux fonctions :
par exemple une première fonction va sonder les cases adjacentes
ensuite une deuxième fonction va immédiatement mémoriser et traiter l’information (par exemple comparer la nouvelle valeur avec l’ancienne mémorisée et décider si oui ou non on la conserve ou on l’oublie)
En gros à chaque cellule sondées, je traite l’information immédiatement jusqu’à la fin.
voici le bout de code de mon PathFindeEngine
` public void PathfinderEngine(int i_value, int j_value)
// i_value et j_value correspondent aux coordonnées de la cellule mère à traiter
// nous devons traiter toute ses cellules filles adjacentes
{
if (begin_pathfinding ) // autorise le calcul du Pathfinding
{
int memorized_value = open_map[i_value, j_value, 0]; // c’est la valeur H+G de la cellule mère
int best_minimum_value = memorized_value; // on initialise un première mémoire tampon
int current_value_scanning = memorized_value; // on initialise une deuxième mémoire tampon
// prélever les coordonnées
int i_memorized = i_value; // j’enregistre l’abcsisse de la cellule mère
int j_memorized = j_value; // j’enregistre l’ordonnées de la cellule mère
// je prépare mes valeurs tampon pour le traitement des cases adjacentes
int _i_moins = i_value – 1; // à gauche
int _i_plus = i_value + 1; // à droite
int _j_moins = j_value – 1; // en haut
int _j_plus = j_value + 1; // en bas
// je place mes mouchards (lisible dans SORTIE) : voir menu Affichage
Console.WriteLine(« current i,j dans le moteur de pathfinding : » + i_value.ToString() + » / » + j_value.ToString());
Console.WriteLine(« au début old_values i,j » + old_path_node_i_value.ToString() + » / » + old_path_node_j_value.ToString());
// je vérifie que la cible n’est pas égal au point de départ
// point de départ : (old_path_node_i_value , old_path_node_j_value)
if (i_value == old_path_node_i_value && j_value == old_path_node_j_value)
{
// si OUI : je créé une alerte et je lance mon compteur debug_path
// son rôle : éjecter du programme et tout remettre par défaut pour éviter les boucles infinies
Console.WriteLine(« alerte debug!!! « );
debug_path += 1;
}
// je vérifie que la cible n’est pas égal au point de départ
// point de départ : (old_path_node_i_value , old_path_node_j_value)
if (old_path_node_i_value != i_value || old_path_node_j_value != j_value)
{
// si NON : la cible n’est pas le point de départ
// en haut
if (_j_moins >= 0 // vérifier que je reste dans l’index de ma tilemap
&& map[i_value, _j_moins] > 0
&& open_map[i_value, _j_moins, 0] >= 0)
{
// je prélève la valeur enregistrée dans mon tableau
current_value_scanning = open_map[i_value, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = i_value;
j_memorized = _j_moins;
}
}
// en bas + ** vérifier si c'est un mur
if (_j_plus 0
&& open_map[i_value, _j_plus, 0] >= 0)
{
current_value_scanning = open_map[i_value, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0// vérifier que je reste dans l’index de ma tilemap
&& _j_moins >= 0
&& map[_i_moins, _j_moins] > 0
&& open_map[_i_moins, _j_moins, 0] >= 0)
{
current_value_scanning = open_map[_i_moins, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0// vérifier que je reste dans l’index de ma tilemap
&& map[_i_moins, j_value] > 0
&& open_map[_i_moins, j_value, 0] >= 0)
{
current_value_scanning = open_map[_i_moins, j_value, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning = 0 /// à gauche // vérifier que je reste dans l’index de ma tilemap
&& _j_plus 0 /// ne contient pas de mur
&& open_map[_i_moins, _j_plus, 0] >= 0) /// contient une valeur traitée dans open_map()
{
current_value_scanning = open_map[_i_moins, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = _i_moins;
j_memorized = _j_plus;
}
}
//en haut à droite + ** vérifier si c'est un mur
if (_i_plus = 0 // vérifier que je reste dans l’index de ma tilemap
&& map[_i_plus, _j_moins] > 0
&& open_map[_i_plus, _j_moins, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, _j_moins, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = _i_plus;
j_memorized = _j_moins;
}
}
//à droite + ** vérifier si c'est un mur
if (_i_plus 0 // vérifier que je reste dans l’index de ma tilemap
&& open_map[_i_plus, j_value, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, j_value, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning < best_minimum_value)
{
best_minimum_value = current_value_scanning;
// je prélève les coordonnées et les range dans une mémoire tampon
i_memorized = _i_plus;
j_memorized = j_value;
}
}
//en bas à droite + ** vérifier si c'est un mur
if (_i_plus < limit_i_value // vérifier que je reste dans l'index de ma tilemap
&& _j_plus 0
&& open_map[_i_plus, _j_plus, 0] >= 0)
{
current_value_scanning = open_map[_i_plus, _j_plus, 0];
// je teste la valeur et si elle est plus petite que l’ancienne,
// j’efface l’ancienne par la nouvelle
if (current_value_scanning 80)
{
begin_pathfinding = false; // je cloture le programme
stop_pathfinding = true;
move_the_sprite = false;
force_eject = true;
Console.WriteLine(« le moteur de pathfinding a rencontré une erreur, nous l’avons forcé à s’arrêter »);
item.IsHidden = true; // je cache l’icone de recherche
// mon programme est bouclé
}
// je met à jour les valeurs à controler
i_path_value = i_memorized;
j_path_value = j_memorized;
// je sécurise la méthode pour pouvoir y mettre fin en cas de PB
old_path_node_i_value = i_value; // l’abscisse de la cellule mère est enregistrée et sera comparée ultrieurement
old_path_node_j_value = j_value; // l’ordonées de la cellule mère est enregistrée et sera comparés ultrieurement
// old_path_node_i_value et old_path_node_j_value sont des variables déclarées au début de la classe
}
}’
lol j’ai pas réussi à bien coller mon code 🙁
comment çà marche?
tu peux le poster sur https://pastebin.com/ et linker le lien obtenu.
Une fonction récursive est une fonction qui s’appelle d’elle-même, c’est ce que j’ai utilisé dans l’atelier sur IA où j’ai programmé un monstre qui pourchasse le héro dans un labyrinthe (.
Ca permet de condenser considérablement le code également. Je te link le lien de la fonction récursive utilisée : .
Il est important d’avoir une condition d’arrêt sinon on pourrait se retrouver avec des appels de fonctions à l’infini. Dans mon cas la profondeur de recherche était limité à 5 cases.