Explosionsgenerator & integrierte Farbverlauf-Routine

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Holzchopf

Meisterpacker

Betreff: Explosionsgenerator & integrierte Farbverlauf-Routine

BeitragDi, Jul 20, 2004 21:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Nundenn, da ich bei meinem aktuellen Projekt bei den Grafiken, genauer gesagt bei den Explosionen, hängen blieb, hab ich mir im Handumdrehen (nagut, es dauerte schon ein weilchen Wink ) einen Explosionsgenerator gemacht.
Früher gab ich mich mit Algorithmus-erzeugten Grafiken nicht zufrieden, weil ich einfach zu wenig Farbe einbringen konnte - Und genau da liegt der unterschied bei diesem Explosionsgenerator.

Und so Funktioniert er:
Wichtig ist mal, dass es sich um eine Partikel-Explosion handelt. Jedes Partikel hat seine Grösse, seinen Platz und seine Stärke.
Daraus wird sozusagen ein Schwarzweissbild einer Explosion erzeugt, je weisser, umso stärker der Pixel. Jetzt wird allerdings statt eines Algorithmus, welcher die weissen - schwarzen Pixel einfach linear von weiss nach gelb nach rot (oder gar nur gelb nach rot) umrechnet, ein Algorithmus eingesetzt, welcher die weissen - schwarzen Pixel an einem Farbverlauf anpasst, dh: die Helligkeit des Pixels bestimmt dessen Index vom Farbverlauf.
Durch diese Methode lassen sich dann Explosionen zeugen, die sich gegen Schluss im Rauch auflösen Wink

Ach ja, wer will darf natürlich die Farbverlauf-Funktion aus dem Code übernehmen.
Und, @Kabelbinder: Reiner Zufall, dass ich meinen Code so kurz nach deiner Farbverlauf-Routine veröffentliche. Eigentlich bin ich nur grad ins Forum gekommen um meinen Code zu veröffentlichen und da seh' ich deinen Thread. Sorry. Wenigstens haben unsere Farbverlauf-Routinen nichts gemeinsam Wink

Oooooooookey, dann will ich euch nicht länger warten lassen (lesen kann zwar jeder, so schnell wie er will):

Code: [AUSKLAPPEN]

;*************************************************
;
;   Rauch-& Explosions-Partikelgenerator
;
;      Von Holzchopf
;
;*************************************************


Graphics 400,300, 16, 2

SeedRnd MilliSecs()

; Type für die Partikel
Type Partikel_Type
   Field X#
   Field Y#
   Field Staerke#
   Field Groesse#
   Field Bewegung#
End Type

; Type für den Farbverlauf
Type Farbverlauf_Type
   Field Index
   Field RGB
End Type

; Type für den Grössenverlauf
Type Groessenverlauf_Type
   Field Index
   Field Groesse
End Type


;*************************************************
;
; Die Einstellungen für die Partikel

;=================================================
;
;   Explosionen mit wenig (< 50) Partikeln
;    und tiefen Werten für die Anfangs-Stärke
;    ergeben schwache Explosionen (zB: Mündungs-
;    Feuer).
;   Mittlere Werte ( 100 Partikel, StMax 32,
;    StMin 16 und mittlere Partikelgrössen)
;    ergeben relativ schwache Explosionen.
;   Splitter- /Gas- /Benzin-Explosionen erreicht
;    man, in dem man die Werte der Stärke erhöht
;    und zugleich die Partikelgrössen verringert.
;   Heisse Explosionen erreicht man, in dem man
;    sehr viele Partikel und/oder sehr hohe
;    Werte für die Stärke einstellt.

Global Anzahl_Partikel         = 2000
Global Sprite_Groesse         = 64
Global Partikel_Gr_Max#         = 16
Global Partikel_Gr_Min#         = 2
Global Partikel_StStaerke_Max   = 64
Global Partikel_StStaerke_Min   = 0
Global Partikel_Bewegung#      = 1.0
Global Partikel_Gr_Faktor#      = 0.99

; Wie viel an Stärke die Partikel pro Frame
;   verlieren (tiefer = flüssiger)
Global Staerke_Abzug#   = 2

; Der Korrigierungsfaktor der Stärke, wird
;   beim Malen berücksichtigt
Global Staerke_Faktor#   = 1

; Sprite-Bank erstellen (für die Intensität)
Global Sprite_Bank      = CreateBank( Sprite_Groesse * Sprite_Groesse * 2 )

; Anzahl Frames vorbestimmen
Frames = Partikel_StStaerke_Max / Staerke_Abzug

; Image erstellen, in dem die Frames gespeichert werden
Image = CreateImage( Frames * Sprite_Groesse, Sprite_Groesse )

; Buffer zwischenspeichern
B_Buffer = BackBuffer()
I_Buffer = ImageBuffer( Image )

;*************************************************
;
;   Farbverlauf einlesen

Global Farbverlauf.Farbverlauf_Type

Restore Farbverlauf
Repeat
   Read Index, RGB

   Farbverlauf.Farbverlauf_Type = New Farbverlauf_Type
   Farbverlauf\Index = Index
   Farbverlauf\RGB = RGB

   If Index = 255 Then Exit
Forever


;*************************************************
;
;   Groessenverlauf einlesen

Global Groessenverlauf.Groessenverlauf_Type

Restore Groessenverlauf
Repeat
   Read Index, Groesse

   Groessenverlauf.Groessenverlauf_Type = New Groessenverlauf_Type
   Groessenverlauf\Index = Index
   Groessenverlauf\Groesse = Groesse

   If Index = 255 Then Exit
Forever


;*************************************************
;
;   Partikel generieren

Global Partikel.Partikel_Type

For a = 1 To Anzahl_Partikel
   Partikel.Partikel_Type = New Partikel_Type

   Radius = Rand( 0, ( Sprite_Groesse / 2 ) - ( Partikel_Gr_Max / 2 + 1 ) )
   Winkel = Rand( 0, 359 )

   Partikel\X = ( Sprite_Groesse / 2 ) + Cos( Winkel ) * Radius
   Partikel\Y = ( Sprite_Groesse / 2 ) + Sin( Winkel ) * Radius
   Partikel\Staerke = Rand( Partikel_StStaerke_Min, Partikel_StStaerke_Max )
   Partikel\Groesse = Rnd( Partikel_Gr_Min, Partikel_Gr_Max )
   Partikel\Bewegung = Rnd( -Partikel_Bewegung, Partikel_Bewegung )
Next


;*************************************************
;
;   Sprite Generieren und zeichnen

SetBuffer B_Buffer

Repeat

   Cls

   ; Die Partikel berechnen und in eine Bank zeichnen
   PartikelBank( 255.0 / Float(Frames) * Frame )
   ; Die Bank auf den Bildschirm zeichnen
   BankZeichnen
   ; Den Frame in ein Image kopieren
   CopyRect 10, 10, Sprite_Groesse, Sprite_Groesse, Frame * Sprite_Groesse, 0, B_Buffer, I_Buffer

   ; Den Farbverlauf zeichnen
   ZeichneFarbverlauf
   ; Den Grössenverlauf zeichnen
   ZeichneGroessenverlauf

   ; Die Vortschritts-Linie Zeichnen
   Color 0,255,255
   Line 20 + ( 255.0 / Float(Frames) * Frame ) , 220, 20 + ( 255.0 / Float(Frames) * Frame ), 290

   ; Die Framezahl erhöhen, wenn alle Frames gezeichnet
   ;   wurden, Schleife verlassen
   Frame = Frame + 1
   If Frame = Frames Then Exit

   Flip

   If KeyHit(1) Then End

Forever

; Bild speichern
FileName$ = "Explosion " + Frames + "_" + Sprite_Groesse + "x" + Sprite_Groesse + ".bmp"
SaveImage( Image, FileName )

FreeImage Image

;*************************************************
;
;   Endergebnis Zeichnen

Image = LoadAnimImage( FileName, Sprite_Groesse, Sprite_Groesse, 0, Frames )
RGB = FarbverlaufFarbe( 255 )
Rot = ( RGB And $FF0000 ) Shr 16
Gruen = ( RGB And $FF00 ) Shr 8
Blau = RGB And $FF

MaskImage Image, Rot, Gruen, Blau

Frame = 0

ClsColor 0,255,0
Color 0,0,0

While Not KeyDown(1)

   Cls

   If MilliSecs() > S_Pause + 2000
      DrawImage Image, 100, 100, Frame

      Frame = Frame + 1
   EndIf

   If Frame = Frames Then
      S_Pause = MilliSecs()
      Frame = 0
   EndIf

   Text 0,0, "Explosion generiert!"
   Text 0,15, "Gespeichert unter: " + FileName
   Text 0,30, "Frames:  " + Frames
   Text 0,45, "Grösse:  " + Sprite_Groesse + "x" + Sprite_Groesse
   Text 0,75, "Aktueller Frame: " + Frame

   Flip

Wend

End



;*************************************************
;
;   Funktionen

; Den Farbverlauf zeichnen
Function ZeichneFarbverlauf( )

   For a = 0 To 255

      RGB = FarbverlaufFarbe( a )
      Rot = ( RGB And $FF0000 ) Shr 16
      Gruen = ( RGB And $FF00 ) Shr 8
      Blau = ( RGB And $FF )

      Color Rot, Gruen, Blau
      Line 20 + a, 200, 20 + a, 210

   Next

End Function

;*************************************************

; Die Farbe vom Farbverlauf ermitteln
;
;=================================================
;   FarbPos ist der Index der zu ermittelnden
;    Farbe.
;   Der Index darf nur von 0 bis 255 reichen!

Function FarbverlaufFarbe( FarbPos )

   For Farbverlauf = Each Farbverlauf_Type
      Index = Farbverlauf\Index
      RGB = Farbverlauf\RGB

      ; Falls der Index und die gewünschte Position
      ;   übereinstimmen, kann direkt die indizierte
      ;   Farbe zurückgegeben werden
      If Index = FarbPos Then

         Return RGB

      ; ... Sonst wird der Farbwert linear interpoliert
      ElseIf FarbPos > Index
         ; Nächstes Farbverlauf-Element ansteuern
         Farbverlauf = After Farbverlauf
         ; Dessen Index ermitteln
         Index2 = Farbverlauf\Index
         ; Reine Fehlerverhinderung; nur Interpolieren
         ;   wenn nächster Index grösser ist
         If FarbPos < Index2
            ; Dessen Farbe ermitteln
            RGB2 = Farbverlauf\RGB

            ; Die Spannweite zwischen den Indizes
            Spanne = Index2 - Index
            ; Die Entfernung zwischen Pos. und Index ermitteln
            Diff1 = Index2 - FarbPos
            Diff2 = FarbPos - Index

            ; Die einzelnen Farbwerte aus dem HEX-Code ermitteln
            Rot1 = ( RGB And $FF0000 ) Shr 16
            Gruen1 = ( RGB And $FF00 ) Shr 8
            Blau1 = ( RGB And $FF )

            Rot2 = ( RGB2 And $FF0000 ) Shr 16
            Gruen2 = ( RGB2 And $FF00 ) Shr 8
            Blau2 = ( RGB2 And $FF )

            ; Farbanteile von Element 1 linear angleichen
            Rot1 = Float( Rot1 ) / Float( Spanne ) * Float( Diff1 )
            Gruen1 = Float( Gruen1 ) / Float( Spanne ) * Float( Diff1 )
            Blau1 = Float( Blau1 ) / Float( Spanne ) * Float( Diff1 )

            ; Farbanteile von Element 2 linear angleichen
            Rot2 = Float( Rot2 ) / Float( Spanne ) * Float( Diff2 )
            Gruen2 = Float( Gruen2 ) / Float( Spanne ) * Float( Diff2 )
            Blau2 = Float( Blau2 ) / Float( Spanne ) * Float( Diff2 )

            ; Farbanteile zusammenrechnen und Überlauf verhindern
            Rot = Rot1 + Rot2
            If Rot > 255 Then Rot = 255
            Gruen = Gruen1 + Gruen2
            If Gruen > 255 Then Gruen = 255
            Blau = Blau1 + Blau2
            If Blau > 255 Then Blau = 255

            ; "HEX-Code" erzeugen
            RGB = ( Rot Shl 16 ) + ( Gruen Shl 8 ) + Blau

            Return RGB

         EndIf
         ; Wieder das aktuelle Element ansteuern (sonst
         ;   überspringt die For-Next Schleife eins)
         Farbverlauf = Before Farbverlauf
      EndIf
   Next

End Function

;*************************************************

; Den Grössenverlauf zeichnen
Function ZeichneGroessenverlauf( )

   alt_y = 0

   Color 0,0,255
   Line 20, 230, 20, 290
   Line 10, 280, 275, 280

   For a = 0 To 255

      y = GroessenverlaufGroesse( a ) * 50

      If a = 0 Then alt_y = y

      Color 0, 255, 0
      Line 20 + a - 1, 280 - alt_y, 20 + a, 280 - y

      alt_y = y

   Next

End Function

;*************************************************

; Die Grösse vom Grössenverlauf ermitteln
;
;=================================================
;   GrPos ist der Index des zu ermittelnden
;    Grössenfaktors (Rückgabewert 0 - 1 ).
;   Der Index darf nur von 0 bis 255 reichen!

Function GroessenverlaufGroesse#( GrPos )

   For Groessenverlauf = Each Groessenverlauf_Type
      ; Index und Grösse des aktiven Elementes ermitteln
      Index = Groessenverlauf\Index
      Groesse = Groessenverlauf\Groesse

      ; Falls die gewünschte Position mit dem Index über-
      ;   einstimmt, den Grössenfaktor zurückgeben
      If Index = GrPos Then

         Return Float( Groesse / 255.0 )

      ; ... Sonst wird der Grössenfaktor linear interpoliert
      ElseIf GrPos > Index
         ; Nächstes Element ansteuern
         Groessenverlauf = After Groessenverlauf
         ; Dessen Index ermitteln
         Index2 = Groessenverlauf\Index
         If GrPos < Index2
            ; Dessen Grösse ermitteln
            Groesse2 = Groessenverlauf\Groesse

            ; Die Spannweite zwischen den Indizes ermitteln
            Spanne = Index2 - Index
            ; Die Entfernung von Pos. zu Index ermitteln
            Diff1 = Index2 - GrPos
            Diff2 = GrPos - Index

            ; Grösse von Element 1 und 2 linear angleichen
            Groesse1 = Float( Groesse ) / Float( Spanne ) * Float( Diff1 )
            Groesse2 = Float( Groesse2 ) / Float( Spanne ) * Float( Diff2 )

            ; Die Grössen zusammenrechnen und Überlauf verhindern
            Groesse = Groesse1 + Groesse2
            If Groesse > 255 Then Groesse = 255

            ; Den Grössenfaktor zurückgeben
            Return Float( Groesse / 255.0 )

         EndIf
         ; Wieder das aktuelle Element ansteuern
         Groessenverlauf = Before Groessenverlauf
      EndIf
   Next

End Function

;*************************************************

; Die Partikel in eine Bank zeichnen (so kann auf
;   die ReadPixel-Befehle verzichtet werden)
Function PartikelBank( GR_Index )

   For Partikel = Each Partikel_Type

      ; X- Und Y-Position ermitteln
      X# = Partikel\X
      Y# = Partikel\Y
      ; Stärke und Grösse ermitteln
      Staerke# = Partikel\Staerke
      Groesse# = Partikel\Groesse
      ; Radius ausrechnen
      Radius# = Groesse / 2.0

      ; Arbeits-Radius und -Grösse errechnen
      ;   (muss aufgerundet werden, damit alle
      ;   Pixel berücksichtigt werden)
      A_Radius = Ceil( Radius )
      A_Groesse = A_Radius * 2

      ; Die Distanz vom Partikel zum Spritemittelpunkt ermitteln
      XDiff# = X - Sprite_Groesse / 2
      YDiff# = Y - Sprite_Groesse / 2
      Rad# = Sqr( XDiff * XDiff + YDiff * YDiff )
      ; Den Winkel vom Partikel zum Spritemittelpunkt ermitteln
      Winkel# = ( ATan2 ( Y - Sprite_Groesse / 2, X - Sprite_Groesse / 2 ) + 360 ) Mod 360

      ; Den Grössenfaktor für die ganze Explosion aus dem Grössenfaktor ermitteln
      VerlGroesse# = GroessenverlaufGroesse#( GR_Index )
      ; Die Partikelposition mit dem Grössenfaktor angleichen
      X = Sprite_Groesse / 2 + Cos( Winkel ) * Rad * VerlGroesse
      Y = Sprite_Groesse / 2 + Sin( Winkel ) * Rad * VerlGroesse

      ; Die Bildpunkte, in denen das Partikel liegt
      ;   abarbeiten
      For a_y = 0 To A_Groesse
         For a_x = 0 To A_Groesse

            ; Zwischenvariable für die Intensität
            ;   des einzelnen Pixels
            Intens = 0

            ; Die effektive Position vom Pixel zum
            ;   Sprite-Nullpunkt
            Eff_X = Int(X) - Int(A_Radius) + a_x
            Eff_Y = Int(Y) - Int(A_Radius) + a_y
            ; Nur Pixel im Sprite abarbeiten
            If Eff_X < Sprite_Groesse And Eff_Y < Sprite_Groesse

               ; Jeden Bildpunkt Vierteln und von
               ;   jedem Teil abfragen, ob dieser im
               ;   Kreis liegt
               For h_y = 1 To 10 Step 5
                  For h_x = 1 To 10 Step 5

                     ; Distanz des Pixelviertels ermitteln
                     Abfrage_X# = a_x - A_Radius + ( h_x / 10.0 ) - 0.05
                     Abfrage_Y# = a_y - A_Radius + ( h_y / 10.0 ) - 0.05
                     Abfrage_Dist# = Sqr( Abfrage_X * Abfrage_X + Abfrage_Y * Abfrage_Y )

                     ; Liegt der Pixelviertel im Kreis, wird die Intensität
                     ;   des ganzen Pixels erhöt
                     If Abfrage_Dist <= Radius Then Intens = Intens + 1
                  Next
               Next

               ; Die neue Stärke des Pixels wird berechnet, in dem die Alte Intensität zur neuen addiert wird
               Akt_Staerke = PeekShort( Sprite_Bank, Eff_Y * Sprite_Groesse * 2 + Eff_X * 2 ) + Staerke / 4.0 * Intens
            
               ; Die neue Intensität des Pixels wird gespeichert
               PokeShort Sprite_Bank, Eff_Y * Sprite_Groesse * 2 + Eff_X * 2, Akt_Staerke

            EndIf

         Next
      Next

      ; Die Stärke des Partikels wird vermindert
      Staerke = Staerke - Staerke_Abzug
      If Staerke < 0 Then Staerke = 0
      Partikel\Staerke = Staerke

      ; Die Grösse des Partikels wird geändert
      Partikel\Groesse = Groesse * Partikel_Gr_Faktor

      ; Das Partikel wird um den Spritemittelpunkt bewegt
      Winkel# = Winkel + Partikel\Bewegung
      Partikel\X = Sprite_Groesse / 2 + Cos( Winkel ) * Rad
      Partikel\Y = Sprite_Groesse / 2 + Sin( Winkel ) * Rad

   Next

End Function

;*************************************************

; Die Bank auslesen und zeichnen
Function BankZeichnen()

   LockBuffer

   For y = 0 To Sprite_Groesse - 1
      For x = 0 To Sprite_Groesse - 1

         ; Stärke ermitteln und um den Stärkefaktor korrigieren
         Staerke = 255 - PeekShort( Sprite_Bank, y * Sprite_Groesse * 2 + x * 2 ) * Staerke_Faktor
         If Staerke < 0 Then Staerke = 0

         ; Die Farbe für den Pixel aus dem Farbverlauf
         ;   auslesen, die Stärke dient hier als Index
         RGB = FarbverlaufFarbe( Staerke )

         ; Pixel zeichnen
         WritePixelFast 10 + x, 10 + y, RGB

         ; Bei der Gelegenheit die Bank leeren
         PokeShort Sprite_Bank, ( y * Sprite_Groesse + x ) * 2, 0
      Next
   Next

   UnlockBuffer

End Function



;*************************************************
;
;   Farbverlauf

.Farbverlauf
;=================================================
;
;       .- Position / Index ( 0...255 )
;       |  Wichtig: Index 0 und 255 müssen
;       |    belegt sein!
;       |
;       |       .- HEX-Farbcode
;       |       |
;      /¯\   /¯¯¯¯¯\
Data   0   , $FFFFFF
Data   16   , $FFFF00
Data   96   , $FF8000
Data   128   , $FF0000
Data   180   , $800000
Data   254   , $808080
Data   255   , $0000FF   ; Hintergrundfarbe


;*************************************************
;
;   Grössenverlauf

.Groessenverlauf
;=================================================
;
;       .- Position / Index ( 0...255 )
;       |  Wichtig: Index 0 und 255 müssen
;       |    belegt sein!
;       |
;       |     .- Grösse der Explosion
;       |     |
;      /¯\   /¯\
Data   0   , 64
Data   12   , 180
Data   24   , 230
Data   48   , 255
Data   128   , 255
Data   255   , 192


Ich hoffe ihr könnt damit was Anfangen, ich hab den Code schliesslich mühsam auskommentiert - und das nur für euch Wink

MfG

PS: Hach, dieses dumme Forum, wandelt Tabs in 3 Leerschläge um, damit geht natürlich die ganze Formatierung flöten (ist aber nicht schlimm, nur unten bei den Verläufen wärs mit perfekter Formatierung schöner Rolling Eyes ).
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm
  • Zuletzt bearbeitet von Holzchopf am So, Feb 06, 2005 21:37, insgesamt einmal bearbeitet

Blatolo

BeitragDi, Jul 20, 2004 22:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Schönes Programm.
Allerdings treten bei mir Fehler auf sobald die SPritegröße 128 oder mehr beträgt.
Das generieren funzt noch einwandfrei und wird korrekt angezeigt nur sobald es dann als Bild gespeichert wird treten Grafik Fehler auf

Holzchopf

Meisterpacker

BeitragDi, Jul 20, 2004 22:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm, was für Grafikfehler???

Habs eben nochmal getestet, bei 128 und 256 als Spritegrösse gibts keine Fehler, auch mit was schrägem wie 155 gehts....

Probiers sonst mal mit 32Bit Farbtiefe...
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

Blatolo

BeitragMi, Jul 21, 2004 7:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei 32 bit passiert das gleiche.
Beim generieren ist noch alles richtig aber das gespeicherte Bild ist fast komplett schwarz mit irgendwelchen Grafikfehlern drauf

edit:
http://blatolo.tim-koepsel.de/explosion.GIF
Sowas kommt dabei raus.
Bei 127 funzt noch alles einwandfrei.

jungle

BeitragDo, Jul 22, 2004 11:59
Antworten mit Zitat
Benutzer-Profile anzeigen
wow,
ich bin froh hier im forum gelandet zu sein.

bei mir funktioniert der soure einwandfrei - 16 und 32bit.
288x288 wunderbar ; alles was größer wird ist beschnitten.
599x599 lief auch OHNE bildfehler durch.

@holzchopf, als (noch) b3d rookie lerne ich natürlich am anfang
viel aus offenen sourcen. dein rauch-& explosions-partikelgenerator
kommt mir da sehr gelegen Very Happy thanks for knowhow share !!!

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group