deplacement dans une map tout en souplesse
Publié : mar. 28/juin/2011 8:30
Voici un code qui montre la façon dont je deplace un perso dans une map en suivant un chemin.
j'ai posté ce code au départ pour Blendman et graph100 dans un sujet sur le chargement des sprites qui a un peu dévié. Comme Je pense que ce code pourrait intéressé d'autre personne je le met ici pour plus de visibilité.
j'ai posté ce code au départ pour Blendman et graph100 dans un sujet sur le chargement des sprites qui a un peu dévié. Comme Je pense que ce code pourrait intéressé d'autre personne je le met ici pour plus de visibilité.
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