Je me lance dans la réalisation d'un jeu de guerre en 2D avec gestion de troupes.
Première étape : les troupes se déplacent (pas très bien) sans se chevaucher.
Le principe : je déplace les soldats les uns après les autres (du plus proche au plus éloigné de la cible) s'ils ne sont pas en collision avec un soldat déjà déplacé.
Si c'est le cas, ils attendent que la place soit libre devant eux pour avancer.
Pour éviter que les soldats restent bloqués trop longtemps j'ai posé une variable qui fait varier l'angle de déplacement en fonction du nombre de soldats bloqués
Je suis déjà bien content du premier code produit qui reste néanmoins pas très performant car les déplacements tremblotent un peu (variation aléatoire du déplacement).
Il faut que je corrige en ne faisant varier l'angle de déplacement uniquement aux soldats bloqués...
Code : Tout sélectionner
InitSprite()
InitMouse()
InitKeyboard()
;----- Ouvre un Screen Plein écran
ExamineDesktops()
ScreenWidth=DesktopWidth(0)
ScreenHeight=DesktopHeight(0)
Global DeltaX.f=ScreenWidth/1024
Global DeltaY.f=ScreenHeight/768
Global FSF0, alea,nbcontact
Global Dim Sx.f(100),Dim Sy.f(100), Dim SoldatCalcul(100), Dim SoldatContact(100), Dim soldattris(100), Dim soldatdistance.f(100)
Global mouseX,mouseY
Procedure mousethread(flag.i) ; souris roccat, razer .....
Static quit.i
If flag
Repeat
If ExamineMouse()
mouseX=MouseX()
mouseY=MouseY()
EndIf
Delay(1)
Until quit
quit=#False
Else
If Not flag
quit=#True
While quit
Delay(1)
Wend
EndIf
EndIf
EndProcedure
; Pause les soldats en rang par 5
nbs=0 ; nombre de soldat
Repeat
x=0
Repeat
nbs+1
Sx(nbs)=x*13+500
Sy(nbs)=y*13+500
x+1
Until x=5 Or nbs=100
y+1
Until nbs=100
OpenScreen(ScreenWidth, ScreenHeight, 32, "")
thread=CreateThread(@mousethread(),#True)
; Sprite des soldats
CreateSprite(0,10,10,#PB_Sprite_AlphaBlending | #PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(0))
Circle(5,5,5,RGB(255,0,0))
StopDrawing()
TransparentSpriteColor(0,RGB(0,0,0))
; sprite de la cible
CreateSprite(1,2,2)
StartDrawing(SpriteOutput(1))
Box(0,0,2,2,RGB(255,255,0))
StopDrawing()
Repeat
ExamineKeyboard()
;ExamineMouse()
ClearScreen(RGB(0,0,0))
; etabli le déplacement pour rejoindre un point de contact
; procede de proche en proche
; recherche déjà le soldat le plus proche et déplace-le dans la bonne direction
; puis le suivant sans qu'il touche les soldats déjà déplacés...
For j=1 To nbs
SoldatCalcul(j)=0 ; les soldats n'ont pas été déplacés
soldattris(j)=0
; soldatdistance(j)=Sqr((sx(j)-MouseX())*(sx(j)-MouseX()) + (sy(j)-MouseY())*(sy(j)-MouseY())) ; calcul les distances
soldatdistance(j)=Sqr((sx(j)-MouseX)*(sx(j)-MouseX) + (sy(j)-MouseY)*(sy(j)-MouseY)) ; calcul les distances
Next
; trie les soldats du plus grand au proche au plus éloigné
nbsoldattris=0
Repeat
nbsoldattris+1
distance.f=9999
For j=1 To nbs
If soldattris(j)=0 And soldatdistance(j)<distance
distance=soldatdistance(j)
proche=j
EndIf
Next
soldattris(proche)=nbsoldattris
Until nbsoldattris=nbs
nbsoldat=0
alea=nbcontact ; ajoute un alea directionnel proportionnel au nombre de soldats bloqués
nbcontact=0
Repeat
nbsoldat+1
soldatproche=0
Repeat
soldatproche+1
Until soldattris(soldatproche)=nbsoldat
; calcul la trajectoire en ligne droite entre le soldat et la cible
x2=MouseX
y2=MouseY
x1=sx(soldatproche)
y1=sy(soldatproche)
soldatcalcul(soldatproche)=1
A.f = x1-x2
b.f = y1-y2
c.f = -Sqr(A*A+b*b)
If Abs(c)>5
If SoldatContact(soldatproche)=1
Angle.f = ACos(A/c)*180/#PI+Random(alea)-alea/2 ; Determine l'angle directionnel du déplacement et ajoute un alea si les troupes sont bloquées
Else
Angle.f = ACos(A/c)*180/#PI ; Determine l'angle directionnel du déplacement et ajoute un alea si les troupes sont bloquées
EndIf
SoldatContact(soldatproche)=0
If y1 < y2 : Angle=360-Angle : EndIf
; test si la place est prise
sx(soldatproche)+2*Cos(Radian(angle)) ; calcul les nouvelles positions x et y du soldat
sy(soldatproche)-2*Sin(Radian(angle))
; test si la place est libre
; => possibilité d'optimiser en mettant tous les soldats déjà déplacés dans un seul sprite pour faire 1 seul test de collision global
contact=0
For i=1 To nbs
If soldatcalcul(i)=1 And i<> soldatproche
If SpritePixelCollision(0,sx(i),sy(i),0,sx(soldatproche),sy(soldatproche))<>0
contact=1
SoldatContact(soldatproche)=1
nbcontact+1
EndIf
EndIf
Next
If contact=1 ; la place n'est pas libre, le soldat reprend sa place d'avant
sx(soldatproche)=x1
sy(soldatproche)=y1
EndIf
;=> à creuser pour que le soldat cherche une autre place (variation d'angle pour contourner celui qui le gene...)
EndIf
DisplayTransparentSprite(0,sx(soldatproche)-5,sy(soldatproche)-5)
Until nbsoldat=nbs
DisplaySprite(1,MouseX-1,MouseY-1)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
KillThread(thread)