Die Effekte

Folgende Effekte sind mit dieser Engine möglich:

Falls Fragen zu den Effekten bestehen, können diese direkt an Richard Schubert gestellt werden.


PartikelEffekte (Explosionen, Feuer, Rauch)

Ob Explosionen jeglicher Art, Feuer, oder Rauch mit dieser Engine ist die Implementierung eines neuen PartikelEffekts kinderleicht.
Ein PartikelEffekt kann durch folgende Einstellungsmöglichkeiten modifiziert werden.

Public Type TEffect

    Draw 

As Boolean

Draw gibt an ob der Effekt überhaupt gezeichnet werden muss.
    InfiniteSpread As Boolean Hier fällt die Entscheidung, ob es ein endloser Effekt sein soll. Also ein Feuer oder Qualm.
    CurrentParticle  As Long Diese Variable ist für den User der EffectEngine uninteressant, da diese komplett von der Engine behandelt wird.
    CurAddParticle  As Single Diese Variable ist auch nur eine Zwischenvariable für die Engine.
    ParticleCount As Long Die Gesamtanzahl der Partikel die der Effekt haben soll, beinhaltet die Variable ParticleCount.
    X
    Y
As Single
As Single
X, Y geben die Position und somit die Quelle des Effekts an.
    VelX 
    VelY 
As Single
As Single
Mit VelX und VelY kann man dem Effekt eine Geschwindigkeit geben. Bei Explosionen kann das die Geschwindigkeit des Explodierenden Körpers (Zum Beispiel ein Raumschiff) sein um mehr Realismus zu simulieren. Oder Wind kann somit bei Feuer oder Rauch für mehr Realismus sorgen.
    AccX 
    AccY 
As Single
As Single
AccX und AccY sind Beschleunigungsvariablen. Mit ihnen verändert sich die Geschwindigkeit des Effekts. So kann man Anziehungskräfte simulieren.
    StartMinRadius As Single Die Mindestentfernung von X,Y der Partikel beim Start des Effekts.
    StartMaxRadius As Single Die Maximalentfernung von X,Y der Partikel beim Start des Effekts. Die Partikel werden beim Start zwischen Min- und MaxRadius gesetzt.
    EndRadius As Single Die Zielentfernung an dem die Partikel ankommen sollen.
    SpreadRangeOffset
    SpreadRange
As Single
As Single
Ausbreitungsrichtung des Effekts im Bogenmaß von 0 bis 2PI. Hier als Beispiel in blau. SpreadRange gibt den Bereich an, hier im Beispiel rot.
    VMinIncreasing
    VMaxIncreasing
As Single
As Single
Der Bereich zischen den beiden Variablen kann den Partikeln sehr verschiedene Startgeschwindigkeiten geben. Dadurch kann man jedem Effekt ein individuelles Outfit verpassen. Wenn die beiden Variablen 0 beinhalten, haben alle Partikel die gleiche Startgeschwindigkeit.
    VDivIncreasing As Boolean Durch diese Einstellung kann man extremere Geschwindigkeitsunterschiede zwischen unterschiedlichen Partikeln erzeugen.
    AttenuationStartRange  As Single Jeder Partikel hat ein Alter (Intensität). Der Bereich geht dabei von 0.0 bis 1.0. Das Alter gibt die Intensität des Partikels an. Mit dieser Variable kann man also unterschiedliche Startalter bestimmen.
    AttenuationSpeed  As Single Die Geschwindigkeit der Alterszuname (Intensitätsabnahme).
    AttenuationExpMode  As Boolean Ob die Intensität exponentiell abnehmen soll.
    VDeceleration As Single Gibt die Geschwindigkeitsabnahme der Partikel an.
    VDecelThreshold As Single Die Altersschwelle ab wann die Geschwindigkeitsabnahme beginnen soll.
    ColorMode As EColorTransform ColorMode kann ONLY_START_COLOR, START_AND_INV_COLOR und ALL_COLORS beinhalten. Mit dieser Einstellung kann man die zusätzlichen Farbübergänge beeinflussen.
    StartColor As D3DCOLORVALUE Das ist die Hauptfarbe mit der alle Partikel am Start eingefärbt werden.
    InvColor As D3DCOLORVALUE Mit dieser Farbe kann man einen sehr schönen Farbübergang hervorrufen.
    EndColor As D3DCOLORVALUE Eine dritte Farbe für denjenigen der noch einen Farbübergang benötigt. 
    MinParticleRadius
    MaxParticleRadius
As Single
As Single
Durch Min- und MaxParticleRadius können die Partikel eines Effekts unterschiedliche Größen haben.
    MinParticleRot
    MaxParticleRot
As Single
As Single
Die einzelnen Partikel können auch eine eigene Rotation haben. Diese Einstellung ist zwar sehr performancelastig, man kann aber mit ihr sehr schöne Effekte erzeugen.
    Particle() As TEffectParticle Dies ist das Array in dem alle Partikel gespeichert sind.
End Type  


Wie kann man solche Effekte nun anwenden?
Das geht ganz einfach.
Um die Partikeleffekte nutzen zu können, muss man als erstes die Engine initialisieren.

InitEffects

Wenn das geschafft ist, kann man sich auch schon seinen ersten Partikeleffekt selber bauen. Dazu muss man sich lediglich ein Objekt vom Typ TEffect erstellen. Hier im Beispiel nennen wir unseren Effekt BigExplosion. Eine Textur wird auch noch benötigt.

Public BigExplosion     As TEffect
Public EffectTexture    As DirectDrawSurface7

Der Effekt muss jetzt noch konfiguriert werden und die gewünschte Textur geladen werden. Eine extra Prozedur ist dafür am besten. Wichtig: Die zu ladende Bitmap muss eine Höhe und Breite haben die 2^(4+x) ist (16, 32, 64, 128, 256 ...).

Public Sub InitBigExplosion()

    CreateTexture g_App.Path_Pics & "\effect01.bmp", EffectTexture

    With BigExplosion
        .ParticleCount = 300
        ReDim .Particle(1 To .ParticleCount)
        'Das Array muss dimensioniert werden

        .SpreadRange = PI * 2
        .SpreadRangeOffset = 0

        .StartMinRadius = -20
        .EndRadius = 150

        .VDivIncreasing = True
        .VMaxIncreasing = 3
        .VMinIncreasing = 0.2

        .VDeceleration = 0.95
        .VDecelThreshold = 0.35

        .ColorMode = ONLY_START_COLOR
        .StartColor = SetColor(200, 150, 100)

        .AttenuationStartRange = 0.3
        .AttenuationSpeed = 0.01

        .MinParticleRadius = 0.3
        .MaxParticleRadius = 1.3
    End With
End Sub

Der Effekt muss als nächstes gezeichnet werden. Um eine ordentliche Darstellung zu gewährleisten, müssen vorher die Projektionseinstellungen vorgenommen werden (Prozedur SetCam). Der Prozedur DrawEffekt übergibt man einfach den Effekt den man darstellen möchte und die Textur durch die er sein Aussehen bekommt.

SetCam

If BigExplosion.Draw Then
    DrawEffect BigExplosion, EffectTexture
End If

Jetzt ist natürlich noch nichts zu sehen, da der Effekt ja erst mal einen Anstoß braucht um zu arbeiten.

Private Sub Form_MouseUp(X As Single, Y As Single)

    SetEffect BigExplosion, X, Y

End Sub

Ein Mausklick genügt jetzt um diesen Effekt auszulösen.

Das Problem ist ganz schnell entdeckt. Es kann immer nur einen Effekt zur selben Zeit geben. Um dieses Problem zu lösen muss man einfach ein Array von Effekten erstellen. Wie man das umsetzt und noch ein paar super Beispiele kann man sich hier anschauen. 


Das Feuer kann auch als Antrieb für Raumschiffe verwendet werden.  

Die beste Art das Effektsystem kennen zulernen, ist einfach damit rumzutesten. Einstellungen verändern und beobachten was sie bewirken.


Licht

Das Licht wie man es vielleicht aus D3D kennt, ist hier nicht vorzufinden. Es ist nur ein Sprite, das durch geschicktes Alphablending alle unter dem Sprite befindlichen Pixel illuminiert.

Public Type TLight

 

    Draw 

As Boolean

Draw gibt an ob das Licht gezeichnet werden muss.

    Radius 

As Single

Der Radius des Lichts in Pixel.

    iRadius

As Single

Interner Radius des Lichts. 

    Color 

As D3DCOLORVALUE

Farbe des Lichts.

    Intensity 

As Single

Intensität des Lichts.

    X
    Y
    VelX
    VelY
    AccX
    AccY

    AttenuationSpeed
    Attenuation
    VDecelThreshold
    VDeceleration

As Single
As Single
As Single
As Single
As Single
As Single
As Single
As Single
As Single
As Single

Der Rest der Variablen haben die gleichen Funktionen wie die gleichnamigen Variablen im EffektTyp.

End Type

 


Wie kann man Lichter anwenden?
Das geht nach dem gleichen Prinzip wie bei den Partikeleffekten.
Um die Lichter nutzen zu können, muss man (falls man es nicht schon wegen der Partikeleffekte getan hat) als erstes die Engine initialisieren.


InitEffects

Wenn das geschafft ist, kann man sich auch schon sein erstes Licht selber bauen. Dazu muss man sich lediglich ein Objekt vom Typ TLight erstellen. Hier im Beispiel nennen wir unser Licht Light. Eine Textur wird auch noch benötigt.

Public Light            As TLight
Public LightTexture     As DirectDrawSurface7

Das Licht muss jetzt noch konfiguriert werden und die gewünschte Textur geladen werden. Eine extra Prozedur ist dafür am besten. Wichtig: Die zu ladende Bitmap muss eine Höhe und Breite haben die 2^(4+x) ist (16, 32, 64, 128, 256 ...).

Public Sub InitLight()

    CreateTexture g_App.Path_Pics & "\light.bmp", LightTexture

    With Light
        .Radius = 200

        .AttenuationSpeed = 0

        .VDeceleration = 1

        .Color = SetColor(255, 255, 255)
        .Intensity = 3

    End With
End Sub

Das Licht muss als nächstes gezeichnet werden. Um eine ordentliche Darstellung zu gewährleisten, müssen vorher die Projektionseinstellungen vorgenommen werden (Prozedur SetCam). Dies muss nur einmal geschehen falls zwischendurch nicht die Projektionsmatrix verstellt wird. Der Prozedur DrawLight übergibt man einfach das Lichtdas man darstellen möchte und die Textur durch die es sein Aussehen bekommt.

SetCam

DrawLight Light, LightTexture

Jetzt ist natürlich noch nichts zu sehen, da das Licht ja erst mal gesetzt werden muss. Dies geschieht über die Prozedur SetLight. Die Angaben sind das zu setzende Licht, das Startalter und die Koordinaten an denen das Licht zu setzen ist.

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)

    If KeyCode = vbKeyL Then
        If Light.Draw Then
            Light.Draw = False
        Else
            SetLight Light, 0, CSng(g_MouseX), CSng(g_MouseY)
        End If
    End If

End Sub

Private Sub Form_MouseMove(X As Single, Y As Single)

    Flash.X = X + g_Map.Wnd.Left
    Flash.Y = Y + g_Map.Wnd.Top

End Sub

Ein Druck auf die Taste L genügt jetzt um dieses Licht ein- und auszuschalten. Mit der Maus kann man dann die Position des Lichts beeinflussen.

Das Ergebnis müsste dann in etwa so aussehen:


Schockwellen

Die Schockwelle ist ein sehr schöner Effekt den man sicher schon aus Filmen wie Minority Report kennt. Es sind einfach nur Druckwellen, die dadurch sichtbar werden, dass sie das Licht krümmen, das sie durchquert. Die Anwendung ist gleich der der Partikeleffekte und Lichter.

 

Public Type T3DWave

 

    Draw 

As Boolean

Draw gibt an ob die Welle gezeichnet werden muss.

    Amplitude

As Single

Der maximale Ausschlag der Welle.

    AmpAttenuation 

As Single

Ausschlagsverringerung. 

    WaveLength 

As Single

Wellenlänge.

    WaveCount 

As Single

Anzahl der Wellen.

    MaxRad

As Single

Interne Variable der Engine.

    Rad 

As Single

Interne Variable der Engine.

    c As Single Ausbreitungsgeschwindigkeit der Welle.
    cAttenuation As Single Geschwindigkeitsverminderung.
    X As Single Position des Wellenursprungs auf der Abszisse.
    Y As Single Position des Wellenursprungs auf der Ordinate.
    SrcX As Long Interne Variable der Engine.
    SrcY As Long Interne Variable der Engine.
End Type  

Wie kann man Wellen anwenden?
Das geht nach dem gleichen Prinzip wie bei den Partikeleffekten oder Lichtern.
Um die Wellen nutzen zu können, muss man als erstes die WaveEngine initialisieren. Man muss eine Textur angeben die in der Höhe und in der Breite 256 Pixel hat. Der Inhalt der Bitmap ist dabei egal.


InitWaveNet "e256.bmp"

Wenn das geschafft ist, kann man sich auch schon seine ersten Wellen selber bauen. Dazu muss man sich lediglich ein Array von Objekten vom Typ T3DWave erstellen. Eine Variable zur Kontrolle der Obergrenze und eine zur Zählung wird auch noch benötigt.

Public Wave(1 To 5) As T3DWave
Public WaveUBound As Long
Public WaveCount As Long

Die Wellen müssen jetzt noch konfiguriert werden. Eine extra Prozedur ist dafür am besten. 

Public Sub InitWaves()
    Dim n As Long

    For n = 1 To 5
        With Wave(n)
            .WaveCount = 1

            .c = 0.4

            .Amplitude = 0.7

            .WaveLength = 1

        End With
    Next n

End Sub

Die Wellen müssen als nächstes gezeichnet werden. Um eine ordentliche Darstellung zu gewährleisten, müssen vorher die Projektionseinstellungen vorgenommen werden (Prozedur SetCam). Dies muss nur einmal geschehen falls zwischendurch nicht die Projektionsmatrix verstellt wird. Der Prozedur MoveWaves übergibt man einfach das WellenArray das man berechnen lassen möchte und deren Unter- und Obergrenze. Die Prozedur AreWavesVisible prüft ob überhaupt Wellen sichtbar sind.

SetCam

MoveWaves Wave, 1, WaveUBound
If AreWavesVisible(Wave, 1, WaveUBound) Then
    DrawWaveNet
End If

Jetzt ist natürlich noch nichts zu sehen, da die Wellen ja erst mal gesetzt werden müssen. Dies geschieht über die Prozedur SetWaveNet. Die Angaben sind die zu setzende Welle und die Koordinaten an denen die Welle ihre Quelle haben soll.

Private Sub Form_MouseUp(X As Single, Y As Single)

    If Button = 1 Then

        WaveCount = WaveCount + 1
        If WaveCount > UBound(Wave) Then WaveCount = LBound(Wave)

        If WaveUBound < WaveCount Then WaveUBound = WaveCount

        SetWaveNet Wave(WaveCount), X, Y

    End If

End Sub

Per Mausklick kann man nun eine Welle erzeugen.


MotionBlur

Diese Engine bietet ein sehr performanceschonendes FullScreenMotionBlur an. Der Nachteil dabei ist, dass durch das Blur das Bild aufgehellt wird. Umso stärker das Blur desto heller ist das Bild.

Die Anwendung von MotionBlur ist sehr einfach. Die Initialisierung ist der der Schockwelle gleich, man muss eine Textur angeben die in der Höhe und in der Breite 256 Pixel hat. Der Inhalt der Bitmap ist dabei egal.

InitBlurNet "e256.bmp"

Um MotionBlur nun zu zeichnen gibt es zwei Prozeduren.

DrawBlurNet 0.3              '0.97 ist Maximum

RefreshBlurTextures

Bei DrawBlurNet muss ein BlurFactor übergeben werden. Der Bereich geht von 0.0 bis 0.97. umso größer der Faktor desto stärker ist das Blur. Alles was vor der Prozedur RefreshBlurTextures gezeichnet wurde kann "geblurt" werden. Alles was zwischen den beiden Prozeduren gezeichnet wird, wird nur am Rand "geblurt". Alles was vor DrawBlurNet gezeichnet wurde wird vollständig "geblurt" und somit auch illuminiert.

Hier im Beispiel ist der BlurFactor 0.7 und damit schon sehr hoch.


Wettereffekte (Schnee)

Der Schnee ist das am einfachsten zu handhabende Werkzeug der EffectEngine. Bei der Initialisierung gibt man einfach die gewünschte Anzahl an Schneepartikeln an und die zu verwendende Textur für den Schnee. Hier muss man sich wieder an die Texturkonvention halten: Höhe und Breite müssen 2^(4+x) sein. Die Prozedur InitEffects muss auch aufgerufen werden, falls das nicht schon für die Partikeleffekte oder Lichter getan wurde.

InitEffects 
InitSnow 500, "snow.bmp"

Um den Schnee dann zu zeichnen braucht man nur die Prozedur DrawSnow aufrufen. Der erste Parameter gibt die Intensität der Flocken an. So ist ein ein stufenloses Ein- und AusFaden möglich. Der Bereich geht von 0.0 bis 1.0.

DrawSnow 0.8, 0, 0

Die letzten beiden Parameter sind die Position des Bildschirms, falls man eine Bewegung simulieren will.