Particles2D, une vieux code source ressorti du tiroir

Sujets variés concernant le développement en PureBasic
Avatar de l’utilisateur
DjPoke
Messages : 121
Inscription : mar. 02/nov./2010 13:53
Localisation : Corte, Corse, France
Contact :

Particles2D, une vieux code source ressorti du tiroir

Message par DjPoke »

Bonjour,

Ces jours-ci, je viens de retrouver une vieux code que j'avais programmé pour un Pong que j'avais fait.

Il n'y a rien d'exceptionnel dans le code.
C'est un système très rudimentaire, mais qui fonctionne.

Il permet de créer des particules sans utiliser le moteur 3D.
Notez qu'à l'époque, je n'utilisais pas les Structures, et il y a sûrement d'autres petits défauts de ce genre.

J'ai traduit la majorité des commentaires en Anglais, pour faciliter la lecture à la majorité des gens.


Le code source de la librairie, à nommer particles2d.pb (pour le fichier de test qui suit)

Code : Tout sélectionner

;
; particles2d.pbi (particles without the 3D Engine)
; by retro-bruno
;
; (c) 2013-2019, royalty free, and free for freedom of the free french frees :)  (i know, it means nothing)
;
; http://retro-bruno.fr
;
; Version 1.1.1
;

#MaximumEmittersCount = 1000
#MaximumParticlesCountByEmitter = 1000

Global Dim Emitter2d.f(17, #MaximumEmittersCount) ; x, y, w, h, sprite, rate, count, maxlife, startwidth, startheight, growspeed, colorfilter, active( 1 / 0 )
Global Dim Particles2D(4, #MaximumParticlesCountByEmitter, #MaximumEmittersCount) ; x, y, life (from 1 to n, or 0 for disabled), angle
Global Dim FilteredSprite(#MaximumEmittersCount)

; create a new particles emitter, and return its handle number, else, return -1 (in case of error)
;
; *** ! DO NOT create a particle emitter in a startdrawing/stopdrawing block ! ***
Procedure CreateParticlesEmitter2D(x, y, w, h, spr, rate, count, maxlife, startwidth, startheight, growspeed.f, colorfilter, rayspeed.f = 0, roundspeed.f = 0, dirangle1 = 0, dirangle2 = 359)
  
  ; Sprite utilisé par l'émétteur
  If IsSprite(spr) = 0
    ProcedureReturn -1
  EndIf
     
  ; x, y, w, h = emission area
  ; rate = appearing speed of the new particles
  ; count = maximum amout of particles that coexist together
  ; maxlife = maximum life length of a particle
  ; startwidth et startheight = start size, or '0' to keep the sprite size
  ; growspeed = growing speed (or ingrowing speed, with a negative value)
  ; colorfilter = if different of '0', apply a color filter and an alpha transparency (colorfilter = RGBA(r, g, b, a))
  ; rayspeed is the speed the particles use to get out of their source center (must be superior or equal to '0')
  ; roundspeed is the gravity speed aroud their source center (positive, negative or '0')
  ; dirangle1 and dirangle2 = angles d'ouverture du champs de propagation des particules (par défaut de 0 à 359) : TRANSLATE ME !!! :)
  If w <= 0 Or h <= 0 Or rate <= 0 Or count <= 0 Or maxlife <= 0 Or startwidth < 0 Or startheight < 0 Or rayspeed < 0
    ProcedureReturn -1
  EndIf
  
  ; get the default sprite size
  If startwidth = 0
    startwidth = SpriteWidth(spr)
  EndIf
  If startheight = 0
    startheight = SpriteHeight(spr)
  EndIf
  
  For i = 1 To #MaximumEmittersCount
    If Emitter2D(17, i) = 0               
      Emitter2D(17, i) = 1
      Emitter2D(1, i) = x
      Emitter2D(2, i) = y
      Emitter2D(3, i) = w
      Emitter2D(4, i) = h
      Emitter2D(5, i) = spr
      Emitter2D(6, i) = rate
      Emitter2D(7, i) = count
      Emitter2D(8, i) = maxlife
      Emitter2D(9, i) = startwidth
      Emitter2D(10, i) = startheight
      Emitter2D(11, i) = growspeed
      Emitter2D(12, i) = colorfilter
      Emitter2D(13, i) = rayspeed
      Emitter2D(14, i) = roundspeed
      a1 = Mod(dirangle1, 360)
      a2 = Mod(dirangle2, 360)
      Emitter2D(15, i) = a1
      Emitter2D(16, i) = a2
      FilteredSprite(i) = CopySprite(spr, #PB_Any, #PB_Sprite_AlphaBlending)
      If colorfilter > 0
        StartDrawing(SpriteOutput(FilteredSprite(i)))
        DrawingMode(#PB_2DDrawing_AllChannels)
        For y = 0 To SpriteHeight(FilteredSprite(i)) - 1
          For x = 0 To SpriteWidth(FilteredSprite(i)) - 1
            col = Point(x,y)
            r = (Red(col) * Red(colorfilter)) / 255
            g = (Green(col) * Green(colorfilter)) / 255
            b = (Blue(col) * Blue(colorfilter)) / 255
            a = Alpha(col)
            ;a = (Alpha(col) * Alpha(colorfilter)) / 255 ?
            Plot(x, y, RGBA(r, g, b, a))
          Next
        Next
        StopDrawing()
      EndIf
      For j = 1 To #MaximumParticlesCountByEmitter
        Particles2D(3, j, i) = 0
      Next
      ProcedureReturn i
    EndIf
  Next
  
  ProcedureReturn -1
      
EndProcedure

; particles update procedure
Procedure Update2DParticles()
  
  ; is this needed ?
  RandomSeed(ElapsedMilliseconds())
  
  ; creation, life and destruction of particles
  For i = 1 To #MaximumEmittersCount
    If Emitter2D(17, i) = 1
      rate = Emitter2D(6, i)
      x1 = Emitter2D(1, i)
      y1 = Emitter2D(2, i)
      x2 = x1 + Emitter2D(3, i) - 1
      y2 = y1 + Emitter2D(4, i) - 1
      ; update the life of particle + create and destroy them
      count = Emitter2D(7, i)
      For j = 1 To #MaximumParticlesCountByEmitter
        If Particles2D(3, j, i) > 0
          Particles2D(3, j, i) + 1
          If Particles2D(3, j, i) = Emitter2D(8, i)
            Particles2D(3, j, i) = 0
          EndIf
        EndIf
        If Particles2D(3, j, i) = 0 And rate > 0
          Particles2D(3, j, i) = 1
          vx = 0
          If x1 < 0
            vx = Abs(x1)
          EndIf
          If x2 + vx < 0
            vx + Abs(x2 + vx)
          EndIf
          vy = 0
          If y1 < 0
            vy = Abs(y1)
          EndIf
          If y2 + vy < 0
            vy + Abs(y2 + vy)
          EndIf
          Particles2D(1, j, i) = Random(x2 + vx, x1 + vx) - vx
          Particles2D(2, j, i) = Random(y2 + vy, y1 + vy) - vy
          If Emitter2D(15, i) < 0 Or Emitter2D(16, i) < 0
            Emitter2d(15, i) + 360
            Emitter2d(16, i) + 360
          EndIf  
          Particles2D(4, j, i) = Mod(Random(Emitter2D(16, i),Emitter2D(15, i)), 360)
          rate - 1
        EndIf
        ; show the particles
        If Particles2D(3, j, i) > 0
          w = Emitter2D(9, i) + (Emitter2D(11, i) * Particles2D(3, j, i))
          h = Emitter2D(10, i) + (Emitter2D(11, i) * Particles2D(3, j, i))
          If w <= 0 Or h <= 0
            Particles2D(3, j, i) = 0
          Else
            If count > 0
              x = Particles2D(1, j, i) - Int(w / 2)
              y = Particles2D(2, j, i) - Int(h / 2)
              tmpspr = CopySprite(FilteredSprite(i), #PB_Any, #PB_Sprite_AlphaBlending)
              ZoomSprite(tmpspr, w, h)
              roundspeed = Mod(Emitter2D(14, i) * Particles2D(3, j, i), 360)
              rayspeed = Emitter2D(13, i) * Particles2D(3, j, i)
              angle = Mod(roundspeed + Particles2D(4, j, i), 360)
              DisplayTransparentSprite(tmpspr, x + (rayspeed * Cos(Radian(angle))), y + (rayspeed * Sin(Radian(angle))), Alpha(Emitter2D(12, i)))
              FreeSprite(tmpspr)
              count - 1
            EndIf
          EndIf
        EndIf
      Next
    EndIf
  Next
  
EndProcedure

; move an emitter
Procedure MoveEmitter2d(n, x, y)
  
  Emitter2D(1, n) = x
  Emitter2D(2, n) = y

EndProcedure

; free an emitter
Procedure FreeEmitter2d(n)
  
  Emitter2d(17,n) = 0
    
EndProcedure
Le code source de test, à nommer particles2d_test.pb

Code : Tout sélectionner

;
; particles2d_test.pb
;

IncludeFile "particles2d.pbi"

; frame speed of the particles system
#FPS = 30

If InitSprite() = 0
  End
EndIf

If InitMouse() = 0
  End
EndIf

If InitKeyboard() = 0
  End
EndIf

; open the screen
If OpenScreen(800, 600, 32, "2D  Particles Test") = 0
  MessageRequester("Error","Can't open the screen !", #PB_MessageRequester_Error)
  End
EndIf

; create demo sprite1
sprite = CreateSprite(#PB_Any, 128, 128, #PB_Sprite_AlphaBlending)
StartDrawing(SpriteOutput(sprite))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(0, 0, 128, 128, RGBA(0, 0, 0, 0))
DrawingMode(#PB_2DDrawing_AlphaBlend | #PB_2DDrawing_Gradient)
CircularGradient(80,48,46)
FrontColor(RGBA(255,255,255,255))
BackColor(RGBA(127,127,127,255))
Circle(64,64,63)
StopDrawing()

; create demo sprite2
sprite2 = CreateSprite(#PB_Any, 128, 128, #PB_Sprite_AlphaBlending)
StartDrawing(SpriteOutput(sprite2))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(0, 0, 128, 128, RGBA(0, 0, 0, 0))
DrawingMode(#PB_2DDrawing_AlphaBlend | #PB_2DDrawing_Gradient)
CircularGradient(80,48,46)
FrontColor(RGBA(255,64,0,255))
BackColor(RGBA(255,255,0,255))
Circle(64,64,63)
StopDrawing()

screen = CreateSprite(#PB_Any, 800, 600, #PB_Sprite_AlphaBlending)

angle = 0
angle2 = 0

pe1 = CreateParticlesEmitter2D(400 + (100 * Cos(Radian(angle))), 295 + (100 * Sin(Radian(angle))), 1, 10, sprite, 4, 64, 24, 8, 4, 1.0, RGBA(0,128,0,20), 7, 0, 260, 280)
If pe1 = 0
  CloseScreen()
  MessageRequester("Erreur","Particles not created !")
  End
EndIf

pe2 = CreateParticlesEmitter2D(440, 320, 10, 1, sprite, 4, 64, 20, 1, 1, 0.5, RGBA(0,128,255,20), 7, 5, -10, 10)
If pe2 = 0
  CloseScreen()
  MessageRequester("Erreur","Particles not created !")
  End
EndIf

pe3 = CreateParticlesEmitter2D(360, 320, 10, 1, sprite, 4, 64, 20, 1, 1, 0.5, RGBA(0,128,255,20), 7, -5, 170, 190)
If pe3 = 0
  CloseScreen()
  MessageRequester("Erreur","Particles not created !")
  End
EndIf

pe4 = CreateParticlesEmitter2D(395, 295, 10, 10, sprite2, 8, 128, 16, 4, 1, 4, RGBA(255,255,255,70), 10, 0, 250, 290)
If pe4 = 0
  CloseScreen()
  MessageRequester("Erreur","Particles not created !")
  End
EndIf

; left click to quit (or push escape key)
testEnd = #False
While testEnd = #False
  
  t = ElapsedMilliseconds()
  
  ClearScreen(RGB(0, 0, 0))
  DisplaySprite(screen, 0 ,0)
  
  ; update the created particles
  Update2DParticles()
  
  ; we move an emitter
  angle2 + 10
  angle + Int(10.00 * Sin(Radian(angle2))) - 5
  angle = Mod(angle, 360)
  angle2 = Mod(angle2, 360)
  
  ; move the green emittor
  MoveEmitter2d(pe1, 400 + (100 * Cos(Radian(angle))), 295 + (100 * Sin(Radian(angle))))
  
  FlipBuffers()
  
  ; slow down the frame rate
  While ElapsedMilliseconds() - t < 1000 / #FPS
    ExamineKeyboard()
    ExamineMouse()
    
    If MouseButton(#PB_MouseButton_Left) Or KeyboardPushed(#PB_Key_Escape)
      testEnd = #True
      
      ; quit immediatly
      Break(2)
    EndIf
    
    Delay(1)
  Wend
Wend

FreeEmitter2d(pe1)
FreeEmitter2d(pe2)
FreeEmitter2d(pe3)
FreeEmitter2d(pe4)

CloseScreen()

End
Avatar de l’utilisateur
Mindphazer
Messages : 639
Inscription : mer. 24/août/2005 10:42

Re: Particles2D, une vieux code source ressorti du tiroir

Message par Mindphazer »

Sympa, merci du partage

A noter, ton code fonctionne très bien sur MacOS :wink:
Bureau : Win10 64bits
Maison : Macbook Pro M1 14" SSD 512 Go / Ram 16 Go - iPad Pro 32 Go (pour madame) - iPhone 15 Pro Max 256 Go
Avatar de l’utilisateur
DjPoke
Messages : 121
Inscription : mar. 02/nov./2010 13:53
Localisation : Corte, Corse, France
Contact :

Re: Particles2D, une vieux code source ressorti du tiroir

Message par DjPoke »

Merci pour l'info. :) J'avais testé sur Windows 10.

Par contre, je ne l'ai pas testé sur Ubuntu. Je regarderai. J'ai VMWare Player avec la version 18.04 installée dessus.

EDIT:
Dans VMWare Workstation Player 15 + Ubuntu 18.04.03 (x64) + Hyper-V activé (Windows 10 Pro), ça tourne très lentement.
De plus, la souris et le clavier ne répondent pas.

Je l'utilise pourtant avec un gros PC en hôte : Procresseur i7 980x avec 12Go de ram, Nvidia GTX 650 TI, etc.

Je pense que je gère mal ma boucle de test des entrées clavier et souris. Je tenterai d'optimiser ce code dès que possible.
Répondre