Page 1 sur 2

Simulation fluide

Publié : dim. 27/janv./2013 15:45
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 

Re: Simulation fluide

Publié : dim. 27/janv./2013 16:58
par venom
8O
Impressionnant le rendu. Bravo G-Rom 8)







@++

Re: Simulation fluide

Publié : dim. 27/janv./2013 18:31
par flaith
8O Merci pour le code, surtout pour la partie 'particle' :D

Re: Simulation fluide

Publié : dim. 27/janv./2013 19:03
par Ar-S
Excellent, merci pour ce plouf.

Re: Simulation fluide

Publié : dim. 27/janv./2013 21:40
par Cool Dji
Top classe, merci G-Rom :D

Re: Simulation fluide

Publié : dim. 27/janv./2013 21:55
par jbernard13
c'est trop fun

Bravo G-Rom

Re: Simulation fluide

Publié : dim. 27/janv./2013 22:30
par Patrick88
plouf et glou glou sont dans un bateau....

marche impec en window 8 :wink:

bravo

Patrick

Re: Simulation fluide

Publié : lun. 28/janv./2013 17:16
par djes
Super joli ! :)

Re: Simulation fluide

Publié : jeu. 07/févr./2013 20:57
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 ?

Re: Simulation fluide

Publié : ven. 08/févr./2013 18:59
par G-Rom
en 2d ?

Re: Simulation fluide

Publié : jeu. 14/févr./2013 17:56
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)

Re: Simulation fluide

Publié : ven. 15/févr./2013 0:26
par G-Rom
Regarde dans le dossier medias de la partie 3d , la texture "caustic" devrais correspondre à tes besoins

Re: Simulation fluide

Publié : sam. 16/févr./2013 18:51
par Fig
C'est exactement ce que je cherchais !!

Re: Simulation fluide

Publié : lun. 18/mars/2013 0:19
par gildev
Punaise! C'est vraiment bien foutu.

Re: Simulation fluide

Publié : lun. 18/mars/2013 10:33
par Atlante
Oui, c'est vraiment bien ce petit effet.