Page 3 sur 3

Re: [jeu] chargement des sprites

Publié : mar. 28/juin/2011 5:48
par Thyphoon
je suis un peu la conversation depuis quelques temps, sans intervenir. J'ai moi même commencé un jeu dans le genre ... pas aussi abouti que celui de blendman
Mais mon système de déplacement fonctionne; Et pour un deplacement plus humain j'utilise une courbe Catmull-Rom entre les différents point qui trace le parcourt
mon code est un peu gros a mettre mais je vais essayer de vous expliquer comment je fais
j'ai essayé de commenté mon code... j'éspère qu'il est assez intuitif et que je ne suis pas hors sujet !

Code : Tout sélectionner

Procedure CatmullRomSpline(t.f,*result.POINT,*p0.Point,*p1.Point,*p2.point,*p3.point)
  t2.f = t * t
  t3.f = t2 * t
  *result\x= 0.5 * ( ( 2.0 * *p1\x ) + ( -*p0\x + *p2\x ) * t + ( 2.0 * *p0\x - 5.0 * *p1\x + 4 * *p2\x - *p3\x ) * t2 + ( -*p0\x + 3.0 * *p1\x - 3.0 * *p2\x + *p3\x ) * t3 )
  *result\y= 0.5 * ( ( 2.0 * *p1\y ) + ( -*p0\y + *p2\y ) * t + ( 2.0 * *p0\y - 5.0 * *p1\y + 4 * *p2\y - *p3\y ) * t2 + ( -*p0\y + 3.0 * *p1\y - 3.0 * *p2\y + *p3\y ) * t3 )
EndProcedure


faudrait que je nettoie le code avant de le publier ici
mais voici ma fonction principal pour le déplacement

Code : Tout sélectionner

Procedure checkCharacter(*chara.characters)
;en gros si mon point de depart et d'arrivé est différent faut trouver un chemin
  If (*chara\ToWorldPixelX<>*chara\worldPixelX Or *chara\ToWorldPixelY<>*chara\worldPixelY) And *chara\pathSize=0
    Debug "Nouveau chemin"
    tileX=Int(*chara\worldPixelX/#tileWidth)
    tileY=Int(*chara\worldPixelY/#tileWidth)
    toTileX=Int(*chara\ToWorldPixelX/#tileWidth)
    toTileY=Int(*chara\ToWorldPixelY/#tileWidth)
    *chara\path=get_path(tileX,tileY,toTileX,toTileY,pf) ;<= la ma fonction pathinfinding 
    *chara\pathSize=path_get_size(character(0)\path) ;le nombre de case pour le deplacement
    *chara\startTime=ElapsedMilliseconds() ;on initialise le temps pour le debut du deplacement
*chara\num=-1 ;    j'initialise mon "pointeur" dans le chemin établit part le pathfinding
*chara\startWorldPixelX=*chara\worldPixelX ; et je memorise mon point de depart
    *chara\startWorldPixelY=*chara\worldPixelY ;
    ;End
  EndIf   
  
  
  ;si on a déjà un chemin alors hop on avance  
  If *chara\pathSize>0
    t.f=(ElapsedMilliseconds()-*chara\startTime)/1000 ;t doit varier de 0 a 1.0 étant le depart d'une case, le 1 etant l'arrivé de la case suivante
    move=1 ;on doit se depalcer
    ;si on arrive a la case suivante
    If t=>1:
      *chara\num+1:;on avance d'une case sur mon chemin
      If *chara\num>*chara\pathSize-2 ;là on est arrivé
        Debug "FIN";
        FreeMemory(*chara\path) ;j'efface mon chemin effectué
        move=0 ;plus besoin de bougé
        *chara\pathSize=0
        *chara\num=0
        *chara\worldPixelX=*chara\ToWorldPixelX ;on est bien arrivé au point qu'on voulait
        *chara\worldPixelY=*chara\ToWorldPixelY
      EndIf
      *chara\startTime=ElapsedMilliseconds(): ;je memorise le temps
    EndIf
  EndIf
  
  If move=1  ; si on doit se depalcer
    Dim p.point(3) ;et pour faire ma route d'un tile a un autre j'ai besoin de connaitre 4 points (catmull rom)
    For z=0 To 3
      num=*chara\num+z-1
      If num<0:
        num=-1
      EndIf
      If num>*chara\pathSize-1
        num=*chara\pathSize-1
      EndIf
      Select num
        Case -1
          p(z)\x=*chara\startWorldPixelX
          p(z)\y=*chara\startWorldPixelY
        Case *chara\pathSize-1
          p(z)\x= *chara\ToWorldPixelX
          p(z)\y= *chara\ToWorldPixelY
        Default
          p(z)\x=path_get_x(*chara\path,num)*#tileWidth+#tileWidth/2
          p(z)\y=path_get_y(*chara\path,num)*#tileWidth+#tileWidth/2
      EndSelect
    Next
    result.point
    CatmullRomSpline(t,result,p(0),p(1),p(2),p(3))
    ;Debug "x:"+Str(result\x)+" y:"+Str(result\y)
    *chara\worldPixelX=result\x
    *chara\worldPixelY=result\y
    
    
  EndIf
  
EndProcedure

Re: [jeu] chargement des sprites

Publié : mar. 28/juin/2011 8:24
par Thyphoon
ce matin j'avais pas eu le temps de vous faire un truc fonctionnel !
Vous remercirez mon RER qui une fois de plus est resté en rade, car du coup j'ai profiter de ce temps pour vous faire un exemple de déplacement dans mon jeu, tout en souplesse !! :P

Code : Tout sélectionner

Procedure CatmullRomSpline(t.f,*result.POINT,*p0.Point,*p1.Point,*p2.point,*p3.point)
  t2.f = t * t
  t3.f = t2 * t
  *result\x= 0.5 * ( ( 2.0 * *p1\x ) + ( -*p0\x + *p2\x ) * t + ( 2.0 * *p0\x - 5.0 * *p1\x + 4 * *p2\x - *p3\x ) * t2 + ( -*p0\x + 3.0 * *p1\x - 3.0 * *p2\x + *p3\x ) * t3 )
  *result\y= 0.5 * ( ( 2.0 * *p1\y ) + ( -*p0\y + *p2\y ) * t + ( 2.0 * *p0\y - 5.0 * *p1\y + 4 * *p2\y - *p3\y ) * t2 + ( -*p0\y + 3.0 * *p1\y - 3.0 * *p2\y + *p3\y ) * t3 )
EndProcedure

#tileWidth=48; taille d'un tile
;-Le personnage
Structure chara
  ;position acutel du personnage (coordonée reel en pixel)
  worldPixelX.l 
  worldPixelY.l
  ;position ou veut aller le personnage (coordonée reel en pixel)
  ToWorldPixelX.l
  ToWorldPixelY.l
  
  pathSize.l;Nombre de case dans le chemin
  num.l ; notre prosition sur le chemin
  startTime.l ; gestion du temps du deplacement
  startWorldPixelX.l; pour le deplacement j'ai besoin de mémorisé le point de depart
  startWorldPixelY.l
EndStructure

chara.chara
;je initialise la position de mon personnage
chara\worldPixelX=10
chara\worldPixelY=10

;je fais comme si on voulait aller a un autre endroit
;c'est pas tres loin du point de depart, mais le faux pathfinding
;un peu plus loin fera un detour
chara\ToWorldPixelX=10
chara\ToWorldPixelY=42

;-Le chemin
Structure chemin
  x.l
  y.l
EndStructure

NewList chemin.chemin()


If InitSprite() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 800, 600, "A screen in a window...", #PB_Window_SystemMenu |  #PB_Window_ScreenCentered)
  CreateStatusBar(0, WindowID(0))
  AddStatusBarField(320)
  
  If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 1, 0, 20)
    
    
    
    Repeat
      ; It's very important to process all the events remaining in the queue at each frame
      ;
      Repeat
        Event = WaitWindowEvent(10)
        
        If Event = #PB_Event_CloseWindow
          End
        EndIf
      Until Event = 0
      ;-Deplacement
      ;en gros si mon point de depart et d'arrivé est différent et qu'on a pas de chemin faut trouver un chemin
      If (chara\ToWorldPixelX<>chara\worldPixelX Or chara\ToWorldPixelY<>chara\worldPixelY) And chara\pathSize=0
        ;ici on utilise un pathfinding normalement
        
        tileX=Int(chara\worldPixelX/#tileWidth)
        tileY=Int(chara\worldPixelY/#tileWidth)
        toTileX=Int(chara\ToWorldPixelX/#tileWidth)
        toTileY=Int(chara\ToWorldPixelY/#tileWidth)
        ;mais ici c'est pas le pathfinding qui nous interesse donc voici un chemin au format list
        AddElement(chemin()):chemin()\x=1:chemin()\y=0
        AddElement(chemin()):chemin()\x=1:chemin()\y=1
        AddElement(chemin()):chemin()\x=2:chemin()\y=1
        AddElement(chemin()):chemin()\x=3:chemin()\y=1
        AddElement(chemin()):chemin()\x=4:chemin()\y=1
        AddElement(chemin()):chemin()\x=5:chemin()\y=2
        AddElement(chemin()):chemin()\x=6:chemin()\y=3
        AddElement(chemin()):chemin()\x=6:chemin()\y=4
        AddElement(chemin()):chemin()\x=6:chemin()\y=5
        AddElement(chemin()):chemin()\x=6:chemin()\y=6
        AddElement(chemin()):chemin()\x=7:chemin()\y=6
        AddElement(chemin()):chemin()\x=8:chemin()\y=6
        AddElement(chemin()):chemin()\x=9:chemin()\y=7
        AddElement(chemin()):chemin()\x=9:chemin()\y=8
        AddElement(chemin()):chemin()\x=8:chemin()\y=9
        AddElement(chemin()):chemin()\x=7:chemin()\y=10
        AddElement(chemin()):chemin()\x=6:chemin()\y=10
        AddElement(chemin()):chemin()\x=5:chemin()\y=10
        AddElement(chemin()):chemin()\x=5:chemin()\y=9
        AddElement(chemin()):chemin()\x=4:chemin()\y=8
        AddElement(chemin()):chemin()\x=3:chemin()\y=7
        AddElement(chemin()):chemin()\x=3:chemin()\y=6
        AddElement(chemin()):chemin()\x=3:chemin()\y=5
        AddElement(chemin()):chemin()\x=3:chemin()\y=4
        AddElement(chemin()):chemin()\x=3:chemin()\y=3
        AddElement(chemin()):chemin()\x=2:chemin()\y=2
        AddElement(chemin()):chemin()\x=1:chemin()\y=1
        AddElement(chemin()):chemin()\x=0:chemin()\y=1
        chara\pathSize=ListSize(chemin()) ;le nombre de case pour le deplacement
        chara\startTime=ElapsedMilliseconds() ;on initialise le temps pour le debut du deplacement
        chara\num=-1 ;    j'initialise mon "pointeur" dans le chemin établit part le pathfinding
        chara\startWorldPixelX=chara\worldPixelX ; et je memorise mon point de depart
        chara\startWorldPixelY=chara\worldPixelY ;
        ;End
      EndIf   
      
      
      ;si on a un chemin alors hop on avance 
      If chara\pathSize>0
        
        t.f=(ElapsedMilliseconds()-chara\startTime)/1000 ;t doit varier de 0 a 1.0 étant le depart d'une case, le 1 etant l'arrivé de la case suivante
        
        move=1 ;on doit se depalcer
        ;si on arrive a la case suivante
        If t>=1
          t=1
          
          If chara\num>chara\pathSize-2 ;là on est arrivé
            Debug "FIN";
            ;j'efface mon chemin effectué
            ClearList(chemin())
            move=0 ;plus besoin de bougé
            chara\pathSize=0
            chara\num=0
            chara\worldPixelX=chara\ToWorldPixelX ;on est bien arrivé au point qu'on voulait
            chara\worldPixelY=chara\ToWorldPixelY
          EndIf
          chara\startTime=ElapsedMilliseconds(): ;je memorise le temps
        EndIf
      EndIf
      
      If move=1  ; si on doit se depalcer
        Dim p.point(3) ;et pour faire ma route d'un tile a un autre j'ai besoin de connaitre 4 points (catmull rom)
        For z=0 To 3
          num=chara\num+z-1
          If num<0:
            num=-1
          EndIf
          If num>chara\pathSize-1
            num=chara\pathSize-1
          EndIf
          Select num
            Case -1
              p(z)\x=chara\startWorldPixelX
              p(z)\y=chara\startWorldPixelY
            Case chara\pathSize-1
              p(z)\x= chara\ToWorldPixelX
              p(z)\y= chara\ToWorldPixelY
            Default
              SelectElement(chemin(),num)
              p(z)\x=chemin()\x*#tileWidth+#tileWidth/2
              p(z)\y=chemin()\y*#tileWidth+#tileWidth/2
          EndSelect
        Next
        result.point
        
        CatmullRomSpline(t,result,p(0),p(1),p(2),p(3))
        
        If t>=1 ;On est arrivé a la nouvelle case
          chara\num+1:;on avance d'une case sur mon chemin
        EndIf

        ;les nouvelles coordonées de notre personnage
        chara\worldPixelX=result\x
        chara\worldPixelY=result\y
        
        
      EndIf
      
      FlipBuffers()
      ClearScreen(0) ; A blue background
      StartDrawing(ScreenOutput())
      For x=1 To 20
        LineXY(x*#tileWidth,0,x*#tileWidth,600,#White)
      Next
      For y=0 To 20
        LineXY(0,y*#tileWidth,800,y*#tileWidth,#White)
      Next
      ForEach chemin()
        Box(chemin()\x*#tileWidth,chemin()\y*#tileWidth,#tileWidth,#tileWidth,RGB(50,50,50))
      Next
       
      Circle(chara\worldPixelX,chara\worldPixelY,5,#Red)
      StopDrawing()
    ForEver
    
  Else
    MessageRequester("Error", "Can't open windowed screen!", 0)
  EndIf
EndIf

Re: [jeu] chargement des sprites

Publié : mar. 28/juin/2011 8:36
par SPH
Tres bon ! :idea:

Re: [jeu] chargement des sprites

Publié : mar. 28/juin/2011 15:20
par graph100
Bon, bah maintenant il suffit de combiner les code ^^, ce qui ne devrais pas être trop compliqué puisque tu fonctionnes par liste !

il faut utiliser l'image suivante
Image

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

Re: [jeu] chargement des sprites

Publié : mar. 28/juin/2011 20:48
par Thyphoon
sympa !! :mrgreen:

Re: [jeu] chargement des sprites

Publié : mer. 29/juin/2011 16:25
par blendman
salut

J'ai regardé ton dernier exemple et le résultat a l'air pas mal du tout, c'est rapide et ça ne bug pas :D.
Mais par contre, comment dire, le code est assez ... imperméable je trouve :).
Bref, en l'état, je ne le comprends pas trop, j'ai beaucoup de difficultés à m'y retrouver et je ne vois pas du tout comment je pourrais l'intégrer, c'est dommage car le résultat fonctionne vraiment bien.
Je vais essayer de le comprendre, mais ça ne me semble pas du tout gagner :p.

Re: [jeu] chargement des sprites

Publié : mer. 29/juin/2011 18:37
par graph100
tu parles du code de qui ?
(normalement j'ai bcp commenté, (j'ai essayé))

Re: [jeu] chargement des sprites

Publié : mer. 29/juin/2011 19:01
par Thyphoon
tu parles du mien ?

Re: [jeu] chargement des sprites

Publié : mer. 29/juin/2011 22:35
par blendman
Graph100 : je parlais du tiens ;). Excuse-moi si j'ai peut être eu des mots maladroits. Ce que je voulais dire, c'est que l'exemple fonctionne super bien, mais à mettre en oeuvre c'est un petit peu compliqué pour moi :P. car je ne peux pas faire un copier-coller, il faut que je l'adapte à mon code et là c'est délicat.
J'ai bien regardé tous les commentaires, mais comme il y a beaucoup de choses, je ne sais pas encore comment je peux l'intégrer à mon code qui est assez "rigide" car très structuré (trop sans doute :D)).
Mais bon, je continue à regarder ça ;).


Typhoon : j'ai regardé ton exemple et c'est aussi sympathique. Par contre, je ne crois pas que l'on va utiliser des courbes "smoothées", car vu qu'on est en iso, je ne sais pas si ça ne ferait pas bizarre. On va voir ça, et faire des tests :)

Merci en tout cas pour vos exemples :)

Re: [jeu] chargement des sprites

Publié : mer. 29/juin/2011 22:40
par graph100
Normalement tu pourrais utiliser mon procédure de récupération du chemin, car elle est utilisable seule (avec son header d'initialisation des map)
Mais pour le déplacement, comme j'ai pas d'idée de la façon dont tu procède dans ton code, j'ai du totalement improviser, et faire un truc simple pour coller à mon exemple ^^

A partir de maintenant, je ne peux plus trop d'aider sans voir le code. Bonne chance ^^
(juste pour savoir, actuellement dans la version de ton jeu, tu peux déplacer les persos ? ou bien ça n'est pas encore implémenté ?)

Re: [jeu] chargement des sprites

Publié : ven. 01/juil./2011 17:03
par blendman
graph100 a écrit :Normalement tu pourrais utiliser mon procédure de récupération du chemin, car elle est utilisable seule (avec son header d'initialisation des map)
Mais pour le déplacement, comme j'ai pas d'idée de la façon dont tu procède dans ton code, j'ai du totalement improvisé, et faire un truc simple pour collé à mon exemple ^^
en fait, le personnage se déplace simplement d'un point A (son départ) à un point B (arrivée).
ça ressemble à :

Code : Tout sélectionner

if depart_x < arrivee_x
x+1
endif
if depart_x > arrivee_x
x-1
endif
if depart_y < arrivee_
y+1
endif
if depart_y > arrivee_y
y-1
endif
on ne peut pas faire pus simple :).
L'indéal serait de pouvoir récupérer les checkpoint, et chaque départ serait le check point précédent et chaque arrivée serait le suivant, par exemple.

Les cases des maps sont en 32*16
(juste pour savoir, actuellement dans la version de ton jeu, tu peux déplacer les persos ? ou bien ça n'est pas encore implémenté ?)
je les déplace avec le code mis plus haut, mais ils n'évitent pas les cases interdites pour l'instant.

On a essayé de mettre en place un pathfinding avec stombretrooper, mais on a encore quelques petits bugs pour que ça marche nickel :P

Re: [jeu] chargement des sprites

Publié : ven. 08/juil./2011 10:01
par graph100
blendman a écrit :

Code : Tout sélectionner

if depart_x < arrivee_x
x+1
endif
if depart_x > arrivee_x
x-1
endif
if depart_y < arrivee_
y+1
endif
if depart_y > arrivee_y
y-1
endif
Donc le perso se téléporte sur l'écran de case en case. C'est ça ?
Le problème ici est qu'il y a 2 modes de coordonnées différentes : les coordonnées des cases du tableau de la carte, et les coordonnées graphiques d'affichage en (x,y), qui permettent d'avoir un affichage continu.

Si le code de déplacement est très fermé, c'est parce que je n'ai pas trop d'idée pour permettre un déplacement 'fin' du joueur. L'idéal serais qu'il puisse se déplacer sur une même case de 32x16. (Un peu comme dans Age of empire, et tout les jeux qui utilisent des cartes composées de tuile).

Re: [jeu] chargement des sprites

Publié : ven. 08/juil./2011 10:17
par Thyphoon
graph100 a écrit : Si le code de déplacement est très fermé, c'est parce que je n'ai pas trop d'idée pour permettre un déplacement 'fin' du joueur. L'idéal serais qu'il puisse se déplacer sur une même case de 32x16. (Un peu comme dans Age of empire, et tout les jeux qui utilisent des cartes composées de tuile).
c'est ce que je fais dans le code que j'ai donné plus haut ! tu peux t'en inspirer ;)

Re: [jeu] chargement des sprites

Publié : dim. 10/juil./2011 15:29
par graph100
oui effectivement :oops: je vais y jeter un grand coup d'oeil ^^