Ça fait quelque temps que j'me demande comment je m'y prendrais si j’étais amené à devoir faire un générateur de niveau pour un jeux de type rogue like... J'ai donc décidé de me lancer la dedans.
Je sais que ce n'est surement pas le meilleur moyen d'approche mais c'est celui qui m'est venu en tête quand j'ai tenté de réfléchir à l'algo.
Loin d'être complet il à au moins l'air fonctionnel...
Code : Tout sélectionner
EnableExplicit
InitSprite()
Global Dim Mape(50,50)
Enumeration
#Empty
#Floor
#Wall
#Dore
EndEnumeration
Global *Wall, Room, Time
Declare FullArray(x,y)
Declare FirstRoom(MaxWidth,MinWidht,MaxHeight,MinHeight)
Declare FindDore(MaxWidth,MinWidht,MaxHeight,MinHeight,CouloirMax,CouloirMin)
Declare TestDirection(x,y,sizex,sizey)
Declare AddRoom(x,y,sizex,sizey)
Declare Generate(width,height,RoomMaxWidth,RoomMinWidth,RoomMaxHeight,RoomMinHeight,CouloirMax,CouloirMin,RoomAmontMin)
Procedure Generate(width,height,RoomMaxWidth,RoomMinWidth,RoomMaxHeight,RoomMinHeight,CouloirMax,CouloirMin,RoomAmontMin)
FullArray(width,height)
*Wall = FirstRoom(RoomMaxWidth,RoomMinWidth+1,RoomMaxHeight,RoomMinHeight+1) : Room = 1
Repeat
If FindDore(RoomMaxWidth,RoomMinWidth+1,RoomMaxHeight,RoomMinHeight+1,CouloirMax,CouloirMin) = #False
Break
EndIf
Room + 1
ForEver
If Room >= RoomAmontMin
Debug Str(Room)+" salles généré en "+Str(ElapsedMilliseconds() - Time) + "ms."
ProcedureReturn #True
Else
Generate(width,height,RoomMaxWidth,RoomMinWidth,RoomMaxHeight,RoomMinHeight,CouloirMax,CouloirMin,RoomAmontMin)
EndIf
EndProcedure
Procedure FirstRoom(MaxWidth,MinWidht,MaxHeight,MinHeight)
Protected Loopx, Loopy, ResultX, ResultY,Width,Height, *Return = AllocateMemory(SizeOf(word)*4)
Width = Random(MaxWidth,MinWidht)
Height = Random(MaxHeight,MinHeight)
ResultX = Random(ArraySize(Mape(),1)-Width)
ResultY = Random(ArraySize(Mape(),2)-Height)
PokeW(*return,ResultX) : PokeW(*return+SizeOf(word),ResultY):PokeW(*return+SizeOf(word)*2,Width):PokeW(*return+SizeOf(word)*3,Height)
For Loopx = ResultX To ResultX + Width
For Loopy = ResultY To ResultY + Height
If Loopx = ResultX Or Loopx = ResultX + Width Or Loopy = ResultY Or Loopy = ResultY +Height
Mape(Loopx,Loopy) = #Wall
Else
Mape(Loopx,Loopy) = #Floor
EndIf
Next Loopy
Next Loopx
ProcedureReturn *return
EndProcedure
Procedure FullArray(x,y)
Global Dim Mape(x,y)
Protected Loopx, Loopy
For Loopx = 0 To x
For Loopy = 0 To y
Mape(Loopx,Loopy) = #Empty
Next Loopy
Next Loopx
EndProcedure
Procedure FindDore(MaxWidth,MinWidht,MaxHeight,MinHeight,CouloirMax,CouloirMin)
Protected shift, shift2, shifty, shifty2, couloir,sizex,sizey, loopx, loopy
shift = Random(PeekW(*Wall+SizeOf(word)*3)-1,1)
shifty = Random(PeekW(*Wall+SizeOf(word)*2)-1,1)
couloir = Random(CouloirMax,CouloirMin)
sizex = Random(MaxWidth,MinWidht) : sizey = Random(MaxHeight,MinHeight)
shift2 = Random(sizey-1,1)
shifty2 = Random(sizex-1,1)
If TestDirection(PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2)+couloir,PeekW(*Wall+SizeOf(word))+shift-shift2,sizex,sizey)
Mape(PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2),PeekW(*Wall+SizeOf(word))+shift) = #Dore
For loopx = PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2)+1 To PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2)+couloir-1
For loopy = PeekW(*Wall+SizeOf(word))+shift-1 To PeekW(*Wall+SizeOf(word))+shift +1
If loopy = PeekW(*Wall+SizeOf(word))+shift
Mape(loopx,loopy) = #Floor
Else
Mape(loopx,loopy) = #Wall
EndIf
Next loopy
Next loopx
AddRoom(PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2)+couloir,PeekW(*Wall+SizeOf(word))+shift-shift2,sizex,sizey)
Mape(PeekW(*Wall),PeekW(*Wall+SizeOf(word))+shift2) = #Dore
ElseIf TestDirection(PeekW(*Wall)-couloir-sizex,PeekW(*Wall+SizeOf(word))+shift-shift2,sizex,sizey)
Mape(PeekW(*Wall),PeekW(*Wall+SizeOf(word))+shift) = #Dore
For loopx = PeekW(*Wall)-couloir+1 To PeekW(*Wall)-1
For loopy = PeekW(*Wall+SizeOf(word))+shift-1 To PeekW(*Wall+SizeOf(word))+shift +1
If loopy = PeekW(*Wall+SizeOf(word))+shift
Mape(loopx,loopy) = #Floor
Else
Mape(loopx,loopy) = #Wall
EndIf
Next loopy
Next loopx
AddRoom(PeekW(*Wall)-couloir-sizex,PeekW(*Wall+SizeOf(word))+shift-shift2,sizex,sizey)
Mape(PeekW(*Wall)+PeekW(*Wall+SizeOf(word)*2),PeekW(*Wall+SizeOf(word))+shift2) = #Dore
ElseIf TestDirection(PeekW(*Wall)+shifty-shifty2,PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3)+couloir,sizex,sizey)
Mape(PeekW(*Wall)+shifty,PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3)) = #Dore
For loopx = PeekW(*Wall)+shifty-1 To PeekW(*Wall)+shifty +1
For loopy = PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3)+1 To PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3) + couloir-1
If loopx = PeekW(*Wall)+shifty
Mape(loopx,loopy) = #floor
Else
Mape(loopx,loopy) = #Wall
EndIf
Next loopy
Next loopx
AddRoom(PeekW(*Wall)+shifty-shifty2,PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3)+couloir,sizex,sizey)
Mape(PeekW(*Wall)+shifty2,PeekW(*Wall+SizeOf(word))) = #Dore
ElseIf TestDirection(PeekW(*Wall)+shifty-shifty2,PeekW(*Wall+SizeOf(word))-couloir-sizey,sizex,sizey)
Mape(PeekW(*Wall)+shifty,PeekW(*Wall+SizeOf(word))) = #Dore
For loopx = PeekW(*Wall)+shifty-1 To PeekW(*Wall)+shifty+1
For loopy = PeekW(*Wall+SizeOf(word))-couloir To PeekW(*Wall+SizeOf(word))-1
If loopx = PeekW(*Wall)+shifty
Mape(loopx,loopy) = #Floor
Else
Mape(loopx,loopy) = #Wall
EndIf
Next loopy
Next loopx
AddRoom(PeekW(*Wall)+shifty-shifty2,PeekW(*Wall+SizeOf(word))-couloir-sizey,sizex,sizey)
Mape(PeekW(*Wall)+shifty2,PeekW(*Wall+SizeOf(word))+PeekW(*Wall+SizeOf(word)*3)) = #Dore
Else
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Procedure TestDirection(x,y,sizex,sizey)
Protected Loopx, Loopy, result
For Loopx = x To x+sizex
For Loopy = y To y+sizey
If Loopx >= 0 And Loopx <= ArraySize(Mape(),1) And Loopy >= 0 And Loopy <= ArraySize(Mape(),2)
If Not Mape(Loopx,Loopy) = #Empty
ProcedureReturn #False
EndIf
Else
ProcedureReturn #False
EndIf
Next Loopy
Next Loopx
ProcedureReturn #True
EndProcedure
Procedure AddRoom(x,y,sizex,sizey)
Protected loopx, loopy
For loopx = x To x+sizex
For loopy = y To y+sizey
If Loopx = x Or Loopx = x + sizex Or Loopy = y Or Loopy = y + sizey
Mape(Loopx,Loopy) = #Wall
Else
Mape(Loopx,Loopy) = #Floor
EndIf
Next loopy
Next loopx
PokeW(*Wall,x) : PokeW(*Wall+SizeOf(word),y):PokeW(*Wall+SizeOf(word)*2,sizex):PokeW(*Wall+SizeOf(word)*3,sizey)
EndProcedure
;Exemple d'utilisation de l'algo
Declare Init()
Declare Display()
Declare Handler_Generate()
Init()
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Procedure Display()
ClearScreen($000000)
Protected Loopx, Loopy
For Loopx = 0 To ArraySize(Mape(),1)
For Loopy = 0 To ArraySize(Mape(),2)
DisplaySprite(Mape(Loopx,Loopy),Loopx*10,Loopy*10)
Next Loopy
Next Loopx
FlipBuffers()
EndProcedure
Procedure Init()
Protected loop
OpenWindow(0,0,0,800,600,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ButtonGadget(0,610,10,80,20,"Generate !")
TextGadget(#PB_Any,610,40,100,20,"Width")
TextGadget(#PB_Any,610,70,100,20,"Height")
TextGadget(#PB_Any,610,100,100,20,"Room min width")
TextGadget(#PB_Any,610,130,100,20,"Room max width")
TextGadget(#PB_Any,610,160,100,20,"Room min height")
TextGadget(#PB_Any,610,190,100,20,"Room max height")
TextGadget(#PB_Any,610,220,100,20,"Couloir min")
TextGadget(#PB_Any,610,250,100,20,"Couloir max")
TextGadget(#PB_Any,610,280,100,20,"Room amont min")
SpinGadget(1,700,40,90,20,10,100,#PB_Spin_Numeric) : SetGadgetState(1,50)
SpinGadget(2,700,70,90,20,10,100,#PB_Spin_Numeric) : SetGadgetState(2,50)
SpinGadget(3,700,100,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(3,2)
SpinGadget(4,700,130,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(4,20)
SpinGadget(5,700,160,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(5,2)
SpinGadget(6,700,190,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(6,20)
SpinGadget(7,700,220,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(7,2)
SpinGadget(8,700,250,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(8,5)
SpinGadget(9,700,280,90,20,1,50,#PB_Spin_Numeric) : SetGadgetState(9,5)
BindGadgetEvent(0,@Handler_Generate())
OpenWindowedScreen(WindowID(0),0,0,600,600)
CreateSprite(#Floor,10,10)
StartDrawing(SpriteOutput(#floor))
Box(0,0,10,10,$0000FF)
StopDrawing()
CreateSprite(#Empty,10,10)
StartDrawing(SpriteOutput(#Empty))
Box(0,0,10,10,$000000)
StopDrawing()
CreateSprite(#Wall,10,10)
StartDrawing(SpriteOutput(#Wall))
Box(0,0,10,10,$00FF00)
StopDrawing()
CreateSprite(#Dore,10,10)
StartDrawing(SpriteOutput(#Dore))
Box(0,0,10,10,$CC00CC)
StopDrawing()
EndProcedure
Procedure Handler_Generate()
Time = ElapsedMilliseconds()
Generate(GetGadgetState(1),GetGadgetState(2),GetGadgetState(4),GetGadgetState(3),GetGadgetState(6),GetGadgetState(5),GetGadgetState(8),GetGadgetState(7),GetGadgetState(9))
Display()
EndProcedure