Simulation fluide

Programmation avancée de jeux en PureBasic
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Simulation fluide

Message par G-Rom »

voici un code qui montre comment faire une zone d'eau , cela peu être intégrer facilement dans un jeu de plateforme.
pour des explications plus poussé , regardez la référence dans l'entête du code source :

code :

Code : Tout sélectionner

; ------------------------------------------------------------------------------------------
; Water2D par G-Rom
; 
; Reference :
; http://gamedev.tutsplus.com/tutorials/implementation/make-a-splash-With-2d-water-effects/
;
; ------------------------------------------------------------------------------------------

#DAMPENING            = 0.025
#TENSION              = 0.025
#SPREAD               = 0.25
#FRAME_RATE_RENDERING = 120
#GRAVITY              = 9.8

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Structure sVector2 
  X.f
  Y.f
EndStructure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Structure sParticle
  mPosition.sVector2
  mOldPosition.sVector2
  mOrigin.sVector2
  mAngle.f
  mVitesse.f
  mPhysic_Timer.f
EndStructure

Global NewList particle.sParticle()
; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Structure sWaterColumn
  mTargetHeight.f
  mHeight.f
  mSpeed.f
EndStructure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Structure sWaterZone
  mPositionX.f
  mPositionY.f
  mSizeX.f
  mSizeY.f
  List mColumns.sWaterColumn()
EndStructure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure UpdateWaterColumn(*w.sWaterColumn, dampening.f, tension.f)
  Protected x.f = *w\mTargetHeight - *w\mHeight
  *w\mSpeed + tension * x - *w\mSpeed * dampening
  *w\mHeight + *w\mSpeed
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure.i NewWaterZone(x.f, y.f, width.f, height.f, column.i = 64)
  *w.sWaterZone = AllocateMemory(SizeOf(sWaterZone))
  InitializeStructure(*w,sWaterZone)
  
  If *w
    
    *w\mPositionX = x
    *w\mPositionY = y
    
    *w\mSizeX = width
    *w\mSizeY = height
    
    For i = 0 To column-1
      AddElement(*w\mColumns())
      *w\mColumns()\mHeight       = height
      *w\mColumns()\mTargetHeight = height 
      *w\mColumns()\mSpeed        = 0
    Next 
    
    ProcedureReturn *w
  EndIf
  
  ProcedureReturn #Null 
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure updateWater(*w.sWaterZone)
  If *w
    
    ForEach *w\mColumns()
        UpdateWaterColumn( *w\mColumns(), #DAMPENING , #TENSION)
    Next
    
    Protected Dim lDeltas.f( ListSize(*w\mColumns() ))
    Protected Dim rDeltas.f( ListSize(*w\mColumns() ))
    
    For j = 0 To 7
      For i = 0 To ListSize(*w\mColumns())-1
        If i>0
          *c.sWaterColumn = SelectElement(*w\mColumns(),i)
          *p.sWaterColumn = SelectElement(*w\mColumns(),i-1)
          lDeltas(i) = #SPREAD * (*c\mHeight - *p\mHeight)
          *p\mSpeed + lDeltas(i)
        EndIf
        If i<ListSize(*w\mColumns())-1
          *c.sWaterColumn = SelectElement(*w\mColumns(),i)
          *n.sWaterColumn = SelectElement(*w\mColumns(),i+1)
          rDeltas(i) = #SPREAD * (*c\mHeight - *n\mHeight)
          *n\mSpeed + rDeltas(i)
        EndIf 
      Next
      For i = 0 To ListSize(*w\mColumns())-1
        If i>0
          *p.sWaterColumn = SelectElement(*w\mColumns(),i-1)
          *p\mHeight + lDeltas(i)
        EndIf
        If i<ListSize(*w\mColumns())-1
          *n.sWaterColumn = SelectElement(*w\mColumns(),i+1)
          *n\mHeight + rDeltas(i)
        EndIf 
      Next
    Next 
    
  EndIf
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure drawWater(*w.sWaterZone, output.i)
  
  color.i = RGBA(64,128,255,64)
  
  StartDrawing(output)
  Box(0,0,1024,768,0)
  
  DrawingMode(#PB_2DDrawing_AlphaChannel)
  Box(*w\mPositionX,*w\mPositionY,*w\mSizeX,*w\mSizeY,RGBA(0,0,0,255))
  
  cWidth.f = *w\mSizeX / (ListSize(*w\mColumns())-1)
  
    For i = 0 To ListSize(*w\mColumns())-1
      
      *c.sWaterColumn = SelectElement(*w\mColumns(),i)
      *n.sWaterColumn = SelectElement(*w\mColumns(),i+1)
      
      If *n = 0
        *n = SelectElement(*w\mColumns(),0)
      EndIf
      
      x1.f = *w\mPositionX + (cWidth*i)
      y1.f = *w\mPositionY + (*c\mHeight - *c\mTargetHeight)
      
      x2.f = *w\mPositionX + (cWidth*i) + cWidth
      y2.f = *w\mPositionY + (*n\mHeight - *n\mTargetHeight)

     DrawingMode(#PB_2DDrawing_AlphaBlend)
  
     LineXY(x1,y1,x2,y2,color)
     
     For ep = 0 To 5
        LineXY(x1,y1-ep,x2,y2-ep,RGB(92,192,255))
     Next

    Next 
    
     *c.sWaterColumn = SelectElement(*w\mColumns(),0)
    
     LineXY(*w\mPositionX,*w\mPositionY+(*c\mHeight-*c\mTargetHeight) ,*w\mPositionX,*w\mPositionY + *w\mSizeY,color)
     LineXY(*w\mPositionX+*w\mSizeX,*w\mPositionY+(*c\mHeight-*c\mTargetHeight) ,*w\mPositionX+*w\mSizeX,*w\mPositionY + *w\mSizeY,color)
     LineXY(*w\mPositionX,*w\mPositionY+*w\mSizeY,*w\mPositionX+*w\mSizeX,*w\mPositionY+*w\mSizeY,color)
     
;       FillArea(*w\mPositionX+1,*w\mPositionY+*w\mSizeY - 1 , -1 , color)
     
  StopDrawing()
  
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure drawWater2(*w.sWaterZone, sprite3D.i)
  
  color.i = RGBA(64,128,255,64)
  
  
  cWidth.f = *w\mSizeX / (ListSize(*w\mColumns())-1)
  
    For i = 0 To ListSize(*w\mColumns())-1
      
      *c.sWaterColumn = SelectElement(*w\mColumns(),i)
      *n.sWaterColumn = SelectElement(*w\mColumns(),i+1)
      
      If *n = 0
        *n = SelectElement(*w\mColumns(),0)
      EndIf
      
      x1.f = *w\mPositionX + (cWidth*i)
      y1.f = *w\mPositionY + (*c\mHeight - *c\mTargetHeight)
      
      x2.f = *w\mPositionX + (cWidth*i) + cWidth
      y2.f = *w\mPositionY + (*n\mHeight - *n\mTargetHeight)

      TransformSprite3D(sprite3D,x1,y1,x2,y2,x2,y2+*w\mSizeY-(*n\mHeight - *n\mTargetHeight),x1,y1+*w\mSizeY-(*c\mHeight - *c\mTargetHeight))
      DisplaySprite3D(sprite3D,0,0,128)

    Next 
    

EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure.f getWaterAngle(*w.sWaterZone, x.f)
  If x > *w\mPositionX And x < (*w\mPositionX + *w\mSizeX)-1
    Protected scale.i = *w\mSizeX / ListSize(*w\mColumns())
    Protected index.i = x/scale
    
    If SelectElement(*w\mColumns(),index-1)
     x1.f = x - scale
     y1.f = *w\mPositionY + *w\mColumns()\mHeight 
    EndIf 
    
    If SelectElement(*w\mColumns(),index+1)
     x2.f = x + scale
     y2.f = *w\mPositionY + *w\mColumns()\mHeight 
    EndIf 
    
    ProcedureReturn Degree(ATan2((y2-y1),(x2-x1)))
    
  EndIf 
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure.f getWaterHeight(*w.sWaterZone, x.f)
  If x > *w\mPositionX And x < (*w\mPositionX + *w\mSizeX)-1
    Protected scale.i = *w\mSizeX / ListSize(*w\mColumns())
    If SelectElement(*w\mColumns(),x / scale)
      ProcedureReturn *w\mColumns()\mHeight + (*w\mPositionY - *w\mSizeY)
    EndIf 
    
  EndIf 
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure setMouseWave(*w.sWaterZone, force.f)
  x.i = MouseX()
  If x > *w\mPositionX And x < (*w\mPositionX + *w\mSizeX)-1
    Protected scale.i = *w\mSizeX / ListSize(*w\mColumns())
    If SelectElement(*w\mColumns(),Int(x / scale))
      *w\mColumns()\mHeight + force
    EndIf 
  EndIf 
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure setWave(*w.sWaterZone, x.f, force.f)
  If x > *w\mPositionX And x < (*w\mPositionX + *w\mSizeX)-1
    Protected scale.i = *w\mSizeX / ListSize(*w\mColumns())
    If SelectElement(*w\mColumns(),Int(x / scale))
      *w\mColumns()\mHeight + force
    EndIf 
  EndIf 
EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure createParticle(x.f,y.f,angle.f=90, randomAngle.f = 70,speed.f = 40)
AddElement(particle())

With particle()
  \mOrigin\X = x
  \mOrigin\Y = y
  \mAngle    = angle - Random(randomAngle) + Random(randomAngle)
  \mVitesse  = speed+Random(speed)
EndWith

EndProcedure

; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
Procedure updateParticle(*w.sWaterZone, spriteDrop.i)
  ForEach particle()
    With particle()
      
      \mOldPosition\x = \mPosition\x
      \mOldPosition\y = \mPosition\y
      
      \mPosition\X = \mOrigin\X + (\mVitesse*Cos((360-\mAngle)*#PI/180)*\mPhysic_Timer)
      \mPosition\Y = \mOrigin\Y + (\mVitesse*Sin((360-\mAngle)*#PI/180)*\mPhysic_Timer)+(0.5*#GRAVITY*(\mPhysic_Timer*\mPhysic_Timer))
      \mPhysic_Timer + 0.3

      angle.f = Degree(ATan2((\mPosition\Y - \mOldPosition\y),( \mPosition\X - \mOldPosition\x)))
      
      RotateSprite3D(spriteDrop,-angle+90,0)
      DisplaySprite3D(spriteDrop,\mPosition\X,\mPosition\Y,64)
      
      If \mPosition\X < 0 Or \mPosition\X>4096 Or \mPosition\Y > getWaterHeight(*w,\mPosition\X)
        setWave(*w,\mPosition\X,8)
        DeleteElement(particle(),1)
      EndIf

    EndWith 
  Next
  
EndProcedure



; -----------------------------------------------------------------------------
;
; -----------------------------------------------------------------------------
InitSprite() : InitKeyboard() : InitMouse() : InitSprite3D()
ExamineDesktops()

OpenScreen(DesktopWidth(0),DesktopHeight(0),DesktopDepth(0),"WaterDemo",#PB_Screen_NoSynchronization)


Define Run.b = #True , offset.i = 0
Define Font.i = LoadFont(#PB_Any,"Arial",18,#PB_Font_HighQuality)
Define.i LPS,LPS_C,LPS_T,CheckTime = ElapsedMilliseconds()
Define.i FPS,FPS_C,FPS_T,flag
Define.i SpriteID,Sprite3D,imageID
Define.i SpriteDropID,SpriteDrop3D
Define.i SpriteID_tile,Sprite3D_tile
Define.i nbX=(DesktopWidth(0)/256)+2
Define.i nbY=(DesktopHeight(0)/256)+2


SpriteID      = CreateSprite(#PB_Any,256,256,#PB_Sprite_Texture)
SpriteID_tile = CreateSprite(#PB_Any,256,256)
Sprite3D      = CreateSprite3D(#PB_Any,SpriteID)

SpriteDropID  = CreateSprite(#PB_Any,16,16,#PB_Sprite_Texture | #PB_Sprite_AlphaBlending )
SpriteDrop3D  = CreateSprite3D(#PB_Any,SpriteDropID)

*Water = NewWaterZone(0,DesktopHeight(0)/2,DesktopWidth(0),DesktopHeight(0)/2,256)

ImageID = CreateImage(#PB_Any,256,256)

StartDrawing(ImageOutput(ImageID))
  DrawingMode(#PB_2DDrawing_Gradient)
  BackColor(RGB(64,128,255))
  FrontColor(RGB(8,16,32))
   GradientColor(0.0001,$FFFFFF)
  GradientColor(0.01,RGB(64,128,255))
  LinearGradient(0, 0, 0, 256)    
  Box(0,0,256,256)
StopDrawing()

StartDrawing(SpriteOutput(SpriteID))
  DrawImage(ImageID(ImageID),0,0)
StopDrawing()

StartDrawing(SpriteOutput(SpriteDropID))
    DrawingMode(#PB_2DDrawing_Default)
    Box(0,0,16,16,RGB(0,0,0))
    Circle(8,12,4,RGB(64,128,255))  
    Circle(8,10,2,RGB(64,128,255))  
    Circle(8,8,1, RGB(64,128,255))  
StopDrawing()

TransparentSpriteColor(SpriteDropID,0)

StartDrawing(SpriteOutput(SpriteID_tile))
  Box(0,0,256,256,$0A0A0A)
  For y = 0 To 256 Step 64
    For x = 0 To 256 Step 64
      Box(x,y,32,32,$1A1A1A)
      Box(x+32,y+32,32,32,$1A1A1A)
    Next
  Next
StopDrawing()

While Run
  
  
  If LPS_T < ElapsedMilliseconds()
    LPS_T = ElapsedMilliseconds() + 1000
    LPS = LPS_C
    FPS = FPS_C
    LPS_C = 0
    FPS_C = 0
  Else
    LPS_C + 1
  EndIf
  
  
  ExamineKeyboard()
  ExamineMouse()
  
  If KeyboardPushed(#PB_Key_Escape)
    Run = #False 
  EndIf 
  
    If MouseButton(1) = 1 And flag = 0
    flag = 1
    
    For i = 0 To 49
      For j = - 10 To 10
        createParticle(MouseX()+(j*2) , getWaterHeight(*Water,MouseX()))
      Next
      
    Next 
    
    setMouseWave(*water,500) 

  EndIf 
  
  If MouseButton(1) = 0 And flag = 1
    flag = 0
  EndIf 
  
  
  If (ElapsedMilliseconds() > CheckTime + 1000 / #FRAME_RATE_RENDERING)
  CheckTime = ElapsedMilliseconds() 
     
    FPS_C + 1

    ClearScreen(0)

    updateWater(*Water)
    
    offset + 1
    offset%256
    For y = 0 To nbY
      For x = 0 To nbX
        DisplaySprite(Spriteid_tile,(x*256)-offset,(y*256)-offset)
      Next
    Next 
   
    
    Start3D()
      drawWater2(*Water,Sprite3D)
      updateParticle(*Water,SpriteDrop3D)
    Stop3D()
    
    StartDrawing(ScreenOutput())
    
    Circle(MouseX(),MouseY(),8,$FFFFFF)
    Circle(MouseX(),MouseY(),6,0)
    Circle(MouseX(),MouseY(),2,$FFFFFF)
    
    
      DrawingMode(#PB_2DDrawing_Transparent)
        DrawingFont(FontID(Font))
          DrawText(10,10,"Water Demo by G-Rom",$5A5A5A)
          DrawText(10,50,"Click for make wave",$5A5A5A)
          DrawText(10,90,"Loop per second : "+Str(LPS),$5A5A5A)
          DrawText(10,130,"Frame rate : "+Str(FPS),$5A5A5A)
          DrawText(10,170,"Particles : "+Str(ListSize(particle())),$5A5A5A)
    StopDrawing()
    
    FlipBuffers()
     
   EndIf
  
Wend
  CloseScreen()
End 
Avatar de l’utilisateur
venom
Messages : 3071
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: Simulation fluide

Message par venom »

8O
Impressionnant le rendu. Bravo G-Rom 8)







@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Avatar de l’utilisateur
flaith
Messages : 1487
Inscription : jeu. 07/avr./2005 1:06
Localisation : Rennes
Contact :

Re: Simulation fluide

Message par flaith »

8O Merci pour le code, surtout pour la partie 'particle' :D
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Simulation fluide

Message par Ar-S »

Excellent, merci pour ce plouf.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Re: Simulation fluide

Message par Cool Dji »

Top classe, merci G-Rom :D
Only PureBasic makes it possible
jbernard13
Messages : 1501
Inscription : dim. 18/avr./2004 15:04
Localisation : sud de la france

Re: Simulation fluide

Message par jbernard13 »

c'est trop fun

Bravo G-Rom
Jbernard13
Patrick88
Messages : 1564
Inscription : mer. 21/janv./2004 18:24

Re: Simulation fluide

Message par Patrick88 »

plouf et glou glou sont dans un bateau....

marche impec en window 8 :wink:

bravo

Patrick
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Simulation fluide

Message par djes »

Super joli ! :)
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Simulation fluide

Message par Fig »

Bravo !

Je cherche un moyen de simuler (avec un automate cellulaire peut-être ?) une surface d'eau avec des reflets mouvants (simulant les vaguelettes), quelqu'un a peut être une idée ?
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Simulation fluide

Message par G-Rom »

en 2d ?
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Simulation fluide

Message par Fig »

Oui en 2d bien sûr, le but c'est d'avoir un effet de vaguelette vu de dessus,sans devoir gérer de la 3d. (je ne demande pas de vrais reflets, juste des effets de couleurs mouvantes)
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Simulation fluide

Message par G-Rom »

Regarde dans le dossier medias de la partie 3d , la texture "caustic" devrais correspondre à tes besoins
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Simulation fluide

Message par Fig »

C'est exactement ce que je cherchais !!
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Avatar de l’utilisateur
gildev
Messages : 380
Inscription : mar. 19/juin/2007 10:28
Localisation : Picardie (France)

Re: Simulation fluide

Message par gildev »

Punaise! C'est vraiment bien foutu.
Avatar de l’utilisateur
Atlante
Messages : 337
Inscription : mer. 29/juin/2011 18:35
Localisation : Paris

Re: Simulation fluide

Message par Atlante »

Oui, c'est vraiment bien ce petit effet.
Modérateur
Config : Intel I5 4670K, Nvidia Geforce GTX 1060, 16go RAM, SSD 256go, DD 2000go
Répondre