Bon, bah maintenant il suffit de combiner les code ^^, ce qui ne devrais pas être trop compliqué puisque tu fonctionnes par liste !
Code : Tout sélectionner
;######################################
; programme : PathFinding exemple de déplacement
#VERSION = "1.00"
; description : - déplacement d'un joueur par Click'n GO
;
; détails : [echape] : quitte le programme
; [flèches de directions] : dirige le joueur (disque rouge)
; [A/Z] : Ajout/Suppression de bloc
; [W/X] : Augmentation/Diminution de la vitesse de déplacement
; [S] : Sauvegarder la carte actuelle (elle est chargée automatiquement au lancement)
;
; ajouts prévus :
;
; auteur : graph100 alias Kriek106
;
; Si vous utilisez ce code, ou partie de ce code, faites en mention dans votre projet ;)
;######################################
; #########
; Remarques :
; - Il est à mon avis prévérable de mettre le déplacement avec les touches en relation
; avec le Click'n Go : comme ceci, le déplacement est toujours régulier, et non par cases
;
; - Lors du déplacement la position du joueur n'est pas vérifiée. Il est donc possible de faire
; arriver le joueur dans une case non accessible, pourvu que cette case soit entourée de cases accessibles.
; Pour palier à cela, j'ai bloqué la posibilité de mettre la cible du Click'n Go sur une case non accessible.
; #########
;{ Structure, variables globales, variables du code principal
Structure size_d
cx.d
cy.d
EndStructure
Structure POINT_d
x.d
y.d
EndStructure
carte.SIZE\cx = 64
carte\cy = 32
#taille_case = 600/32
; explication sur la carte :
; cette carte représente la possibilité de marcher ou non sur chaque case.
; on prend comme hypothèse qu'on ne peux se déplacer que horizontalement et verticalement (bien sur ça n'est pas limité à cela, suffit de le coder)
; 1 : obstacle sur la case
; 0 : case libre
; autre chose : aucune signification pour le moment
;{ init de la carte
; si il y a un ficher CarteMap.byte, on le charge
If ReadFile(0, "CarteMap.byte")
carte\cx = ReadWord(0)
carte\cy = ReadWord(0)
Dim CarteMap.l(carte\cx - 1, carte\cy - 1)
For a = 0 To carte\cx - 1
For b = 0 To carte\cy - 1
CarteMap(a, b) = ReadByte(0)
Next
Next
CloseFile(0)
Else
Dim CarteMap.l(carte\cx - 1, carte\cy - 1)
; on rempli la carte d'objet aléatoires :
For a = 0 To carte\cx * carte\cy / 25
x = Random(carte\cx - 1)
y = Random(carte\cy - 1)
If CarteMap(x, y) = 1
a - 1
Else
CarteMap(x, y) = 1
EndIf
Next
; on ajoute une zone fermée pour tester
For a = 0 To 20
CarteMap(20, a) = 1
CarteMap(a, 20) = 1
Next
EndIf
;}
w = #taille_case * carte\cx
h = #taille_case * carte\cy
NewList Path.POINT()
; dimensions des cases
casesize.size_d\cx = (w - 1) / carte\cx
casesize\cy = (h - 1) / carte\cy
; arrive voulue dans le pathfinding (déclaration de la variable)
arrive.POINT\x = Random(carte\cx - 1)
arrive\y = Random(carte\cy - 1)
If ReadFile(0, "CarteMap.byte")
FileSeek(0, Lof(0) - 8)
joueur.POINT\x = ReadWord(0)
joueur\y = ReadWord(0)
arrive\x = ReadWord(0)
arrive\y = ReadWord(0)
CloseFile(0)
Else
; position du joueur
joueur.POINT\x = Random(carte\cx - 1)
joueur\y = Random(carte\cy - 1)
CarteMap(joueur\x, joueur\y) = 0
EndIf
Define refaire_le_path_finding.b, IS_Click_n_GO.b, IS_positionnement_force.b
vitesse.d = casesize\cx / 2
joueur_pos_ecran.POINT_d\x = (joueur\x + 0.5) * casesize\cx
joueur_pos_ecran\y = (joueur\y + 0.5) * casesize\cy
;}
;{ procedures
Global Dim ZCarte(ArraySize(CarteMap(), 1), ArraySize(CarteMap(), 2)) ; DEBUG ONLY
;{ initialisation d'un tableau en dehors de la procedure pour aller plus vite
Global Dim _map_.POINT(7)
_map_(0)\x = 0
_map_(0)\y = -1
_map_(1)\x = -1
_map_(1)\y = 0
_map_(2)\x = 0
_map_(2)\y = 1
_map_(3)\x = 1
_map_(3)\y = 0
_map_(4)\x = -1
_map_(4)\y = -1
_map_(5)\x = 1
_map_(5)\y = -1
_map_(6)\x = 1
_map_(6)\y = 1
_map_(7)\x = -1
_map_(7)\y = 1
Global NewList _tmp_(), NewList _tmp2_()
AddElement(_tmp_())
_tmp_() = 0
AddElement(_tmp_())
_tmp_() = 1
AddElement(_tmp_())
_tmp_() = 2
AddElement(_tmp_())
_tmp_() = 3
AddElement(_tmp_())
_tmp_() = 4
AddElement(_tmp_())
_tmp_() = 5
AddElement(_tmp_())
_tmp_() = 6
AddElement(_tmp_())
_tmp_() = 7
;}
;{ pathfinding avec linked list
Procedure PathFinding(*pos_joueur.POINT, *pos_arrive.POINT, Array carte.l(2), List chemin.POINT())
Protected w.l, h.l, a.l, b.l, ok.b, temp.POINT, *tmp.point, *cur.POINT, *old.POINT
;{ initialisation
; on met à zéro la liste de chemin
ClearList(chemin())
w = ArraySize(carte(), 1)
h = ArraySize(carte(), 2)
; on créé le tableau de travail
; Protected Dim ZCarte(w, h)
Dim ZCarte(w, h)
; on créé la liste de travail
Protected NewList ZCase.POINT()
;}
;{ écriture du nombre de pas mini pour arriver à la case voulue
; initialisation
ZCarte(*pos_arrive\x, *pos_arrive\y) = w * h ; le nombre de pas maximum ne peux pas être plus grand que le nombre de case total
AddElement(ZCase())
CopyStructure(*pos_arrive, ZCase(), POINT)
Repeat
; FirstElement(ZCase())
CopyStructure(ZCase(), @temp, POINT)
LastElement(ZCase())
If temp\x > 0 And carte(temp\x - 1, temp\y) <> 1 And ZCarte(temp\x - 1, temp\y) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x - 1
ZCase()\y = temp\y
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 1
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\x > 0 And temp\y > 0 And carte(temp\x - 1, temp\y - 1) <> 1 And ZCarte(temp\x - 1, temp\y - 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x - 1
ZCase()\y = temp\y - 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 2
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\y > 0 And carte(temp\x, temp\y - 1) <> 1 And ZCarte(temp\x, temp\y - 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x
ZCase()\y = temp\y - 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 1
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\y > 0 And temp\x < w And carte(temp\x + 1, temp\y - 1) <> 1 And ZCarte(temp\x + 1, temp\y - 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x + 1
ZCase()\y = temp\y - 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 2
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\x < w And carte(temp\x + 1, temp\y) <> 1 And ZCarte(temp\x + 1, temp\y) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x + 1
ZCase()\y = temp\y
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 1
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\x < w And temp\y < h And carte(temp\x + 1, temp\y + 1) <> 1 And ZCarte(temp\x + 1, temp\y + 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x + 1
ZCase()\y = temp\y + 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 2
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\y < h And carte(temp\x, temp\y + 1) <> 1 And ZCarte(temp\x, temp\y + 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x
ZCase()\y = temp\y + 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 1
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
If temp\y < h And temp\x > 0 And carte(temp\x - 1, temp\y + 1) <> 1 And ZCarte(temp\x - 1, temp\y + 1) < ZCarte(temp\x, temp\y) - 1
AddElement(ZCase())
ZCase()\x = temp\x - 1
ZCase()\y = temp\y + 1
ZCarte(ZCase()\x, ZCase()\y) = ZCarte(temp\x, temp\y) - 2
If ZCase()\x = *pos_joueur\x And ZCase()\y = *pos_joueur\y
Break
EndIf
EndIf
FirstElement(ZCase())
DeleteElement(ZCase(), 1)
Until ListSize(ZCase()) = 0
FreeList(ZCase())
;}
;{ on en déduie le chemin à prendre en allant toujours dans la case de valeur plus petite que celle actuelle
; initialisation
a = *pos_joueur\x
b = *pos_joueur\y
a1 = 0
b1 = 0
While ZCarte(a, b) <> 1
CopyList(_tmp_(), _tmp2_())
ok.b = #False
; pour une sélection aléatoire de la case à tester. Pour augmenter la vitesse virer ce code et mettre celui des commentaires
; simplement, il choisira toujours en premier la même case à tester, et donc privilégieras certaine direction. (ici : à gauche, puis en haut, puis a droite, enfin en bas
first.b = #True
For c = 0 To 7
SelectElement(_tmp2_(), Random(ListSize(_tmp2_()) - 1))
If a + _map_(_tmp2_())\x >= 0 And b + _map_(_tmp2_())\y >= 0 And a + _map_(_tmp2_())\x =< w And b + _map_(_tmp2_())\y =< h
If ZCarte(a + _map_(_tmp2_())\x, b + _map_(_tmp2_())\y) > ZCarte(a, b)
If first = #True Or ZCarte(a + _map_(_tmp2_())\x, b + _map_(_tmp2_())\y) > ZCarte(a1, b1)
a1 = a + _map_(_tmp2_())\x
b1 = b + _map_(_tmp2_())\y
first = #False
ok = #True
EndIf
; Break
; If a > 0 And ZCarte(a - 1, b) <> 0 And ZCarte(a - 1, b) < ZCarte(a, b)
; a - 1
; ElseIf b > 0 And ZCarte(a, b - 1) <> 0 And ZCarte(a, b - 1) < ZCarte(a, b)
; b - 1
; ElseIf a < w And ZCarte(a + 1, b) <> 0 And ZCarte(a + 1, b) < ZCarte(a, b)
; a + 1
; ElseIf b < h And ZCarte(a, b + 1) <> 0 And ZCarte(a, b + 1) < ZCarte(a, b)
; b + 1
; Else
; coordonnée inacessibles demandée
; ProcedureReturn
EndIf
EndIf
DeleteElement(_tmp2_())
Next
If ok = #False
Break
EndIf
a = a1
b = b1
AddElement(chemin())
chemin()\x = a
chemin()\y = b
Wend
;}
;{ on simplifie le chemin pour n'avoir plus que les checkpoints
If ListSize(chemin()) <= 3
ProcedureReturn
EndIf
*tmp = FirstElement(chemin())
*cur = NextElement(chemin())
Repeat
; If ListIndex(chemin()) = 0
; NextElement(chemin())
; EndIf
;
; PreviousElement(chemin())
*old = NextElement(chemin())
If Sign(*tmp\x - *cur\x) = Sign(*cur\x - chemin()\x) And Sign(*tmp\y - *cur\y) = Sign(*cur\y - chemin()\y)
PreviousElement(chemin())
DeleteElement(chemin()) ; positionne le curseur sur l'element précédent !!
*cur = NextElement(chemin())
Else
*tmp = *cur
*cur = *old
EndIf
Until ListIndex(chemin()) = ListSize(chemin()) - 1
;}
EndProcedure
;}
;}
;{ initialisation (Decoder image, sprite, keyboard)
UsePNGImageDecoder()
If InitSprite() = 0 Or InitKeyboard() = 0
End
EndIf
;}
;{ ouverture de la fenetre
If OpenWindow(0, 0, 0, w, h, "PathFinding sur une carte", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
If OpenWindowedScreen(WindowID(0), 0, 0, w, h, 0, 0, 0)
; on passe le clavier en mode courant de l'utilisateur (azerty ou qwerty)
KeyboardMode(#PB_Keyboard_International)
Else
End
EndIf
Else
End
EndIf
LoadSprite(0, "arbre.png")
TransparentSpriteColor(0, #White)
;}
;{ boucle principale
Repeat
event = WaitWindowEvent(10)
ExamineKeyboard()
;{ clavier
If KeyboardReleased(#PB_Key_Escape) : event = #PB_Event_CloseWindow : EndIf
;{ déplacements au clavier du joueur
If KeyboardPushed(#PB_Key_Left)
If joueur\x > 0 And CarteMap(joueur\x - 1, joueur\y) = 0 : joueur\x - 1 : EndIf
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
If KeyboardPushed(#PB_Key_Right)
If joueur\x < carte\cx - 1 And CarteMap(joueur\x + 1, joueur\y) = 0 : joueur\x + 1 : EndIf
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
If KeyboardPushed(#PB_Key_Up)
If joueur\y > 0 And CarteMap(joueur\x, joueur\y - 1) = 0 : joueur\y - 1 : EndIf
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
If KeyboardPushed(#PB_Key_Down)
If joueur\y < carte\cy - 1 And CarteMap(joueur\x, joueur\y + 1) = 0 : joueur\y + 1 : EndIf
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
;}
;{ sauvegarde de la carte
If KeyboardReleased(#PB_Key_S)
If CreateFile(0, "CarteMap.byte")
WriteWord(0, carte\cx)
WriteWord(0, carte\cy)
For a = 0 To carte\cx - 1
For b = 0 To carte\cy - 1
WriteByte(0, CarteMap(a, b))
Next
Next
WriteWord(0, joueur\x)
WriteWord(0, joueur\y)
WriteWord(0, arrive\x)
WriteWord(0, arrive\y)
CloseFile(0)
MessageRequester("", "Fichier 'CarteMap.byte' ecrit avec succés")
EndIf
EndIf
;}
;{ gestion des ajouts / suppression de bloc
; ajout de bloc
If KeyboardPushed(#PB_Key_A)
x = Round(WindowMouseX(0) / casesize\cx, #PB_Round_Down)
y = Round(WindowMouseY(0) / casesize\cy, #PB_Round_Down)
If (Not (x < 0 Or x > carte\cx - 1 Or y < 0 Or y > carte\cy - 1)) And CarteMap(x, y) <> 1
CarteMap(x, y) = 1
refaire_le_path_finding = #True
EndIf
EndIf
; suppression de bloc
If KeyboardPushed(#PB_Key_Z)
x = Round(WindowMouseX(0) / casesize\cx, #PB_Round_Down)
y = Round(WindowMouseY(0) / casesize\cy, #PB_Round_Down)
If (Not (x < 0 Or x > carte\cx - 1 Or y < 0 Or y > carte\cy - 1)) And CarteMap(x, y) <> 0
CarteMap(x, y) = 0
refaire_le_path_finding = #True
EndIf
EndIf
;}
;{ gestion accélération / deccélération
; accélération
If KeyboardPushed(#PB_Key_W)
vitesse - 0.1
If vitesse <= 0 : vitesse = 0.1 : EndIf
EndIf
; deccélération
If KeyboardPushed(#PB_Key_X)
vitesse + 0.1
If vitesse <= 0 : vitesse = 0.1 : EndIf
EndIf
;}
;}
;{ evenement souris
If event = #WM_LBUTTONDOWN
x = Round(WindowMouseX(0) / casesize\cx, #PB_Round_Down)
y = Round(WindowMouseY(0) / casesize\cy, #PB_Round_Down)
If (Not (x < 0 Or x > carte\cx - 1 Or y < 0 Or y > carte\cy - 1)) And CarteMap(x, y) <> 1
arrive\x = x
arrive\y = y
refaire_le_path_finding = #True
IS_Click_n_GO = #True
IS_positionnement_force = #True
EndIf
EndIf
If event = #WM_RBUTTONDOWN ; on déplace le personnage carrément avec le boutton droit de la souris
x = Round(WindowMouseX(0) / casesize\cx, #PB_Round_Down)
y = Round(WindowMouseY(0) / casesize\cy, #PB_Round_Down)
If (Not (x < 0 Or x > carte\cx - 1 Or y < 0 Or y > carte\cy - 1)) And CarteMap(x, y) <> 1
joueur\x = x
joueur\y = y
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
EndIf
;}
;{ si refaire_le_path_finding = #True, on exécute PathFinding
If refaire_le_path_finding = #True
PathFinding(joueur, arrive, CarteMap(), Path())
refaire_le_path_finding = #False
EndIf
;}
;{ Déplacment du joueur si IS_Click_n_GO = #True, et mise à jour de joueur_pos_ecran
If IS_positionnement_force = #True
joueur_pos_ecran\x = (joueur\x + 0.5) * casesize\cx
joueur_pos_ecran\y = (joueur\y + 0.5) * casesize\cy
IS_positionnement_force = #False
EndIf
If IS_Click_n_GO = #True
If ListSize(Path()) > 0
FirstElement(Path())
joueur_pos_ecran\x = joueur_pos_ecran\x + Sign(Path()\x - joueur\x) * vitesse
joueur_pos_ecran\y = joueur_pos_ecran\y + Sign(Path()\y - joueur\y) * vitesse
If Path()\x < joueur\x
joueur\x = Round((joueur_pos_ecran\x / casesize\cx - 0.5), #PB_Round_Up)
Else
joueur\x = Round((joueur_pos_ecran\x / casesize\cx - 0.5), #PB_Round_Down)
EndIf
If Path()\y < joueur\y
joueur\y = Round((joueur_pos_ecran\y / casesize\cy - 0.5), #PB_Round_Up)
Else
joueur\y = Round((joueur_pos_ecran\y / casesize\cy - 0.5), #PB_Round_Down)
EndIf
If joueur\x = Path()\x And joueur\y = Path()\y
DeleteElement(Path())
EndIf
EndIf
If ListSize(Path()) = 0
IS_Click_n_GO = #False
IS_positionnement_force = #True
EndIf
EndIf
;}
;{ graphismes
ClearScreen(0)
If StartDrawing(ScreenOutput())
Circle(joueur_pos_ecran\x, joueur_pos_ecran\y, casesize\cx / 2, #Red)
If IS_Click_n_GO = #True
Circle((arrive\x + 0.5) * casesize\cx, (arrive\y + 0.5) * casesize\cy, casesize\cx / 3, #Blue)
EndIf
StopDrawing()
EndIf
; affichage des arbres
For a = 0 To carte\cx - 1
For b = 0 To carte\cy - 1
If CarteMap(a, b) = 1
; dessin obstacle
DisplayTransparentSprite(0, a * casesize\cx, (b + 1) * casesize\cy - SpriteHeight(0))
EndIf
Next
Next
FlipBuffers()
;}
Until event = #PB_Event_CloseWindow
;}
End