Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

So erzeugen Sie schockierend gute 2D-Blitzeffekte

Scroll to top
Read Time: 15 min

() translation by (you can also view the original English article)

Lightning hat in Spielen viele Verwendungsmöglichkeiten, von der Hintergrundatmosphäre während eines Sturms bis hin zu den verheerenden Blitzangriffen eines Zauberers. In diesem Tutorial erkläre ich, wie Sie programmgesteuert fantastische 2D-Blitzeffekte erzeugen: Schrauben, Zweige und sogar Text.

Hinweis: Obwohl dieses Tutorial mit C# und XNA geschrieben wurde, sollten Sie in der Lage sein, dieselben Techniken und Konzepte in fast jeder Spielentwicklungsumgebung zu verwenden.


Finale Videovorschau


Schritt 1: Zeichnen Sie eine leuchtende Linie

Der grundlegende Baustein, den wir zum Erstellen von Blitzen benötigen, ist ein Liniensegment. Öffnen Sie zunächst Ihre bevorzugte Bildbearbeitungssoftware und zeichnen Sie eine gerade Blitzlinie. So sieht meiner aus:

Line Segment

Wir möchten Linien unterschiedlicher Länge zeichnen, also schneiden wir das Liniensegment wie unten gezeigt in drei Teile. Dies ermöglicht es uns, das mittlere Segment auf jede gewünschte Länge zu dehnen. Da wir das mittlere Segment strecken werden, können wir es als nur ein einzelnes Pixel dick speichern. Da das linke und das rechte Stück Spiegelbilder voneinander sind, müssen wir nur eines davon speichern. Wir können es im Code umdrehen.

Divided Line Segment

Jetzt deklarieren wir eine neue Klasse für das Zeichnen von Liniensegmenten:

1
public class Line
2
{
3
	public Vector2 A;
4
	public Vector2 B;
5
	public float Thickness;
6
7
	public Line() { }
8
	public Line(Vector2 a, Vector2 b, float thickness = 1)
9
	{
10
		A = a;
11
		B = b;
12
		Thickness = thickness;
13
	}
14
}

A und B sind die Endpunkte der Linie. Durch Skalieren und Drehen der Teile der Linie können wir eine Linie beliebiger Dicke, Länge und Ausrichtung zeichnen. Fügen Sie der Line-Klasse die folgende Draw()-Methode hinzu:

1
public void Draw(SpriteBatch spriteBatch, Color color)
2
{
3
	Vector2 tangent = B - A;
4
	float rotation = (float)Math.Atan2(tangent.Y, tangent.X);
5
6
	const float ImageThickness = 8;
7
	float thicknessScale = Thickness / ImageThickness;
8
9
	Vector2 capOrigin = new Vector2(Art.HalfCircle.Width, Art.HalfCircle.Height / 2f);
10
	Vector2 middleOrigin = new Vector2(0, Art.LightningSegment.Height / 2f);
11
	Vector2 middleScale = new Vector2(tangent.Length(), thicknessScale);
12
13
	spriteBatch.Draw(Art.LightningSegment, A, null, color, rotation, middleOrigin, middleScale, SpriteEffects.None, 0f);
14
	spriteBatch.Draw(Art.HalfCircle, A, null, color, rotation, capOrigin, thicknessScale, SpriteEffects.None, 0f);
15
	spriteBatch.Draw(Art.HalfCircle, B, null, color, rotation + MathHelper.Pi, capOrigin, thicknessScale, SpriteEffects.None, 0f);
16
}

Hier sind Art.LightningSegment und Art.HalfCircle statische Texture2D-Variablen, die die Bilder der Teile des Liniensegments enthalten. ImageThickness wird auf die Stärke der Linie ohne das Leuchten eingestellt. In meinem Bild sind es 8 Pixel. Wir setzen den Ursprung der Kappe auf die rechte Seite und den Ursprung des mittleren Segments auf die linke Seite. Dadurch werden sie nahtlos zusammengefügt, wenn wir sie beide an Punkt A zeichnen. Das mittlere Segment wird auf die gewünschte Breite gestreckt und eine weitere Kappe wird an Punkt B um 180° gedreht gezeichnet.

Mit der SpriteBatch-Klasse von XNA können Sie in ihrem Konstruktor einen SpriteSortMode übergeben, der die Reihenfolge angibt, in der die Sprites gezeichnet werden sollen. Stellen Sie beim Zeichnen der Linie sicher, dass Sie einen SpriteBatch mit SpriteSortMode auf SpriteSortMode.Texture übergeben. Dies dient der Leistungssteigerung.

Grafikkarten sind großartig darin, die gleiche Textur viele Male zu zeichnen. Jedes Mal, wenn sie die Texturen wechseln, gibt es jedoch Overhead. Wenn wir eine Reihe von Linien ohne Sortierung zeichnen, zeichnen wir unsere Texturen in dieser Reihenfolge:

BlitzSegment, Halbkreis, Halbkreis, BlitzSegment, Halbkreis, Halbkreis, ...

Das bedeutet, dass wir die Texturen für jede gezeichnete Linie zweimal wechseln würden. SpriteSortMode.Texture weist SpriteBatch an, die Draw()-Aufrufe nach Textur zu sortieren, sodass alle LightningSegments zusammen gezeichnet werden und alle HalfCircles zusammen gezeichnet werden. Wenn wir diese Linien verwenden, um Blitze zu erstellen, möchten wir außerdem die additive Mischung verwenden, um das Licht aus überlappenden Blitzstücken zusammenzufügen.

1
SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive);
2
// draw lines

3
SpriteBatch.End();

Schritt 2: Gezackte Linien

Blitze neigen dazu, gezackte Linien zu bilden, daher benötigen wir einen Algorithmus, um diese zu generieren. Wir werden dies tun, indem wir zufällig Punkte entlang einer Linie auswählen und sie um einen zufälligen Abstand von der Linie verschieben. Die Verwendung einer völlig zufälligen Verschiebung führt dazu, dass die Linie zu gezackt wird, daher werden wir die Ergebnisse glätten, indem wir begrenzen, wie weit benachbarte Punkte voneinander verschoben werden können.

Making Jagged Lines

Die Linie wird geglättet, indem Punkte mit einem ähnlichen Versatz zum vorherigen Punkt platziert werden; Dadurch kann die Linie als Ganzes auf und ab wandern und gleichzeitig verhindern, dass ein Teil davon zu gezackt wird. Hier ist der Code:

1
protected static List<Line> CreateBolt(Vector2 source, Vector2 dest, float thickness)
2
{
3
	var results = new List<Line>();
4
	Vector2 tangent = dest - source;
5
	Vector2 normal = Vector2.Normalize(new Vector2(tangent.Y, -tangent.X));
6
	float length = tangent.Length();
7
8
	List<float> positions = new List<float>();
9
	positions.Add(0);
10
11
	for (int i = 0; i < length / 4; i++)
12
		positions.Add(Rand(0, 1));
13
14
	positions.Sort();
15
16
	const float Sway = 80;
17
	const float Jaggedness = 1 / Sway;
18
19
	Vector2 prevPoint = source;
20
	float prevDisplacement = 0;
21
	for (int i = 1; i < positions.Count; i++)
22
	{
23
		float pos = positions[i];
24
25
		// used to prevent sharp angles by ensuring very close positions also have small perpendicular variation.

26
		float scale = (length * Jaggedness) * (pos - positions[i - 1]);
27
28
		// defines an envelope. Points near the middle of the bolt can be further from the central line.

29
		float envelope = pos > 0.95f ? 20 * (1 - pos) : 1;
30
31
		float displacement = Rand(-Sway, Sway);
32
		displacement -= (displacement - prevDisplacement) * (1 - scale);
33
		displacement *= envelope;
34
35
		Vector2 point = source + pos * tangent + displacement * normal;
36
		results.Add(new Line(prevPoint, point, thickness));
37
		prevPoint = point;
38
		prevDisplacement = displacement;
39
	}
40
41
	results.Add(new Line(prevPoint, dest, thickness));
42
43
	return results;
44
}

Der Code sieht vielleicht etwas einschüchternd aus, ist aber nicht so schlimm, wenn Sie die Logik verstanden haben. Wir beginnen mit der Berechnung der Normalen- und Tangentenvektoren der Linie sowie der Länge. Dann wählen wir zufällig eine Reihe von Positionen entlang der Linie und speichern sie in unserer Positionsliste. Die Positionen werden zwischen 0 und 1 skaliert, sodass 0 den Anfang der Linie und 1 den Endpunkt darstellt. Diese Positionen werden dann sortiert, damit wir problemlos Liniensegmente zwischen ihnen hinzufügen können.

Die Schleife durchläuft die zufällig ausgewählten Punkte und verschiebt sie um einen zufälligen Betrag entlang der Normalen. Der Skalierungsfaktor ist dazu da, zu scharfe Winkel zu vermeiden, und die Hüllkurve stellt sicher, dass der Blitz tatsächlich zum Zielpunkt geht, indem sie die Verschiebung begrenzt, wenn wir uns dem Ende nähern.

Lightning BoltLightning BoltLightning Bolt

Schritt 3: Animation

Blitze sollten hell aufblitzen und dann ausblenden. Um dies zu handhaben, erstellen wir eine LightningBolt-Klasse.

1
class LightningBolt
2
{
3
	public List<Line> Segments = new List<Line>();
4
5
	public float Alpha { get; set; }
6
	public float FadeOutRate { get; set; }
7
	public Color Tint { get; set; }
8
9
	public bool IsComplete { get { return Alpha <= 0; } }
10
11
	public LightningBolt(Vector2 source, Vector2 dest) : this(source, dest, new Color(0.9f, 0.8f, 1f)) { }
12
13
	public LightningBolt(Vector2 source, Vector2 dest, Color color)
14
	{
15
		Segments = CreateBolt(source, dest, 2);
16
17
		Tint = color;
18
		Alpha = 1f;
19
		FadeOutRate = 0.03f;
20
	}
21
22
	public void Draw(SpriteBatch spriteBatch)
23
	{
24
		if (Alpha <= 0)
25
			return;
26
27
		foreach (var segment in Segments)
28
			segment.Draw(spriteBatch, Tint * (Alpha * 0.6f));
29
	}
30
31
	public virtual void Update()
32
	{
33
		Alpha -= FadeOutRate;
34
	}
35
36
	protected static List<Line> CreateBolt(Vector2 source, Vector2 dest, float thickness)
37
	{
38
		// ...

39
	}
40
41
	// ...

42
}

Um dies zu verwenden, erstellen Sie einfach einen neuen LightningBolt und rufen Sie Update() und Draw() für jeden Frame auf. Der Aufruf von Update() lässt es verblassen. IsComplete zeigt Ihnen an, wenn der Bolzen vollständig ausgeblendet ist.

Sie können jetzt Ihre Bolzen zeichnen, indem Sie den folgenden Code in Ihrer Spielklasse verwenden:

1
LightningBolt bolt;
2
MouseState mouseState, lastMouseState;
3
4
protected override void Update(GameTime gameTime)
5
{
6
	lastMouseState = mouseState;
7
	mouseState = Mouse.GetState();
8
9
	var screenSize = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
10
	var mousePosition = new Vector2(mouseState.X, mouseState.Y);
11
12
	if (MouseWasClicked())
13
		bolt = new LightningBolt(screenSize / 2, mousePosition);
14
15
	if (bolt != null)
16
		bolt.Update();
17
}
18
19
private bool MouseWasClicked()
20
{
21
	return mouseState.LeftButton == ButtonState.Pressed && lastMouseState.LeftButton == ButtonState.Released;
22
}
23
24
protected override void Draw(GameTime gameTime)
25
{
26
	GraphicsDevice.Clear(Color.Black);
27
28
	spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive);
29
30
	if (bolt != null)
31
		bolt.Draw(spriteBatch);
32
33
	spriteBatch.End();
34
}

Schritt 4: Branch Lightning

Sie können die LightningBolt-Klasse als Baustein verwenden, um interessantere Blitzeffekte zu erstellen. Sie können die Schrauben beispielsweise wie unten gezeigt verzweigen:

Brand Lightning

Um den Blitz zu verzweigen, wählen wir zufällige Punkte entlang des Blitzes und fügen neue Bolzen hinzu, die von diesen Punkten abzweigen. Im folgenden Code erstellen wir zwischen drei und sechs Zweige, die sich in einem Winkel von 30 ° vom Hauptbolzen trennen.

1
class BranchLightning
2
{
3
	List<LightningBolt> bolts = new List<LightningBolt>();
4
		
5
	public bool IsComplete { get { return bolts.Count == 0; } }
6
	public Vector2 End { get; private set; }
7
	private Vector2 direction;
8
9
	static Random rand = new Random();
10
11
	public BranchLightning(Vector2 start, Vector2 end)
12
	{
13
		End = end;
14
		direction = Vector2.Normalize(end - start);
15
		Create(start, end);
16
	}
17
18
	public void Update()
19
	{
20
		bolts = bolts.Where(x => !x.IsComplete).ToList();
21
		foreach (var bolt in bolts)
22
			bolt.Update();
23
	}
24
25
	public void Draw(SpriteBatch spriteBatch)
26
	{
27
		foreach (var bolt in bolts)
28
			bolt.Draw(spriteBatch);
29
	}
30
31
	private void Create(Vector2 start, Vector2 end)
32
	{
33
		var mainBolt = new LightningBolt(start, end);
34
		bolts.Add(mainBolt);
35
36
		int numBranches = rand.Next(3, 6);
37
		Vector2 diff = end - start;
38
39
		// pick a bunch of random points between 0 and 1 and sort them

40
		float[] branchPoints = Enumerable.Range(0, numBranches)
41
			.Select(x => Rand(0, 1f))
42
			.OrderBy(x => x).ToArray();
43
44
		for (int i = 0; i < branchPoints.Length; i++)
45
		{
46
			// Bolt.GetPoint() gets the position of the lightning bolt at specified fraction (0 = start of bolt, 1 = end)

47
			Vector2 boltStart = mainBolt.GetPoint(branchPoints[i]);
48
49
			// rotate 30 degrees. Alternate between rotating left and right.

50
			Quaternion rot = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, MathHelper.ToRadians(30 * ((i & 1) == 0 ? 1 : -1)));
51
			Vector2 boltEnd = Vector2.Transform(diff * (1 - branchPoints[i]), rot) + boltStart;
52
			bolts.Add(new LightningBolt(boltStart, boltEnd));
53
		}
54
	}
55
56
	static float Rand(float min, float max)
57
	{
58
		return (float)rand.NextDouble() * (max - min) + min;
59
	}
60
}

Schritt 5: Blitztext

Unten ist ein Video eines anderen Effekts, den Sie aus den Blitzen machen können:

Zuerst müssen wir die Pixel im Text ermitteln, den wir zeichnen möchten. Dazu zeichnen wir unseren Text auf ein RenderTarget2D und lesen die Pixeldaten mit RenderTarget2D.GetData<T>() zurück. Wenn Sie mehr über das Erstellen von Textpartikeleffekten erfahren möchten, habe ich hier ein ausführlicheres Tutorial.

Wir speichern die Koordinaten der Pixel im Text als List<Vector2>. Dann wählen wir in jedem Frame zufällig Paare dieser Punkte aus und erzeugen einen Blitz zwischen ihnen. Wir wollen es so gestalten, dass je näher zwei Punkte beieinander liegen, desto größer ist die Chance, dass wir einen Bolzen zwischen ihnen erzeugen. Es gibt eine einfache Technik, die wir verwenden können, um dies zu erreichen: Wir wählen den ersten Punkt nach dem Zufallsprinzip aus, und dann wählen wir eine feste Anzahl anderer Punkte nach dem Zufallsprinzip und wählen den nächsten.

Die Anzahl der getesteten Kandidatenpunkte beeinflusst das Aussehen des Blitztextes. Wenn wir eine größere Anzahl von Punkten überprüfen, können wir sehr nahe Punkte finden, zwischen denen Bolzen gezogen werden können, wodurch der Text sehr sauber und lesbar wird, jedoch mit weniger langen Blitzen zwischen den Buchstaben. Kleinere Zahlen lassen den Blitztext verrückter aussehen, aber weniger lesbar.

1
public void Update()
2
{
3
	foreach (var particle in textParticles)
4
	{
5
		float x = particle.X / 500f;
6
		if (rand.Next(50) == 0)
7
		{
8
			Vector2 nearestParticle = Vector2.Zero;
9
			float nearestDist = float.MaxValue;
10
			for (int i = 0; i < 50; i++)
11
			{
12
				var other = textParticles[rand.Next(textParticles.Count)];
13
				var dist = Vector2.DistanceSquared(particle, other);
14
15
				if (dist < nearestDist && dist > 10 * 10)
16
				{
17
					nearestDist = dist;
18
					nearestParticle = other;
19
				}
20
			}
21
22
			if (nearestDist < 200 * 200 && nearestDist > 10 * 10)
23
				bolts.Add(new LightningBolt(particle, nearestParticle, Color.White));
24
		}
25
	}
26
27
	for (int i = bolts.Count - 1; i >= 0; i--)
28
	{
29
		bolts[i].Update();
30
31
		if (bolts[i].IsComplete)
32
			bolts.RemoveAt(i);
33
	}
34
}

Schritt 6: Optimierung

Der Blitztext, wie oben gezeigt, kann reibungslos laufen, wenn Sie einen Computer der Spitzenklasse haben, aber es ist sicherlich sehr anstrengend. Jede Schraube hält über 30 Frames, und wir erstellen Dutzende neuer Schrauben pro Frame. Da jeder Blitz aus bis zu ein paar hundert Liniensegmenten bestehen kann und jedes Liniensegment aus drei Teilen besteht, zeichnen wir am Ende viele Sprites. Meine Demo zeichnet zum Beispiel über 25.000 Bilder pro Frame mit deaktivierten Optimierungen. Wir können es besser.

Anstatt jede Schraube bis zum Ausblenden zu zeichnen, können wir jede neue Schraube zu einem Renderziel zeichnen und das Renderziel in jedem Frame ausblenden. Das bedeutet, dass wir, anstatt jede Schraube für 30 oder mehr Frames zeichnen zu müssen, sie nur einmal zeichnen. Es bedeutet auch, dass keine zusätzlichen Leistungskosten entstehen, wenn unsere Blitze langsamer ausgeblendet werden und länger halten.

Zuerst ändern wir die LightningText-Klasse, um jede Schraube nur für einen Frame zu zeichnen. Deklarieren Sie in Ihrer Game-Klasse zwei RenderTarget2D-Variablen: currentFrame und lastFrame. Initialisieren Sie sie in LoadContent() wie folgt:

1
lastFrame    = new RenderTarget2D(GraphicsDevice, screenSize.X, screenSize.Y, false, SurfaceFormat.HdrBlendable, DepthFormat.None);
2
currentFrame = new RenderTarget2D(GraphicsDevice, screenSize.X, screenSize.Y, false, SurfaceFormat.HdrBlendable, DepthFormat.None);

Beachten Sie, dass das Oberflächenformat auf HdrBlendable eingestellt ist. HDR steht für High Dynamic Range und bedeutet, dass unsere HDR-Oberfläche eine größere Farbpalette darstellen kann. Dies ist erforderlich, da das Renderziel dadurch Farben aufweisen kann, die heller als Weiß sind. Wenn sich mehrere Blitze überlappen, benötigen wir das Renderziel, um die volle Summe ihrer Farben zu speichern, die sich über den Standardfarbbereich hinaus summieren können. Obwohl diese heller-als-weißen Farben weiterhin als Weiß auf dem Bildschirm angezeigt werden, ist es wichtig, ihre volle Helligkeit zu speichern, damit sie korrekt ausgeblendet werden.

XNA-Tipp: Beachten Sie auch, dass Sie das XNA-Projektprofil auf Hi-Def setzen müssen, damit HDR-Blending funktioniert. Sie können dies tun, indem Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt klicken, Eigenschaften auswählen und dann das HD-Profil auf der Registerkarte XNA Game Studio auswählen.

Bei jedem Frame ziehen wir zunächst den Inhalt des letzten Frames auf den aktuellen Frame, jedoch leicht abgedunkelt. Anschließend fügen wir alle neu erstellten Schrauben zum aktuellen Frame hinzu. Schließlich rendern wir unseren aktuellen Frame auf dem Bildschirm und tauschen dann die beiden Renderziele aus, sodass sich lastFrame für unseren nächsten Frame auf den gerade gerenderten Frame bezieht.

1
void DrawLightningText()
2
{
3
	GraphicsDevice.SetRenderTarget(currentFrame);
4
	GraphicsDevice.Clear(Color.Black);
5
6
	// draw the last frame at 96% brightness

7
	spriteBatch.Begin(0, BlendState.Opaque, SamplerState.PointClamp, null, null);
8
	spriteBatch.Draw(lastFrame, Vector2.Zero, Color.White * 0.96f);
9
	spriteBatch.End();
10
11
	// draw new bolts with additive blending

12
	spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive);
13
	lightningText.Draw();
14
	spriteBatch.End();
15
16
	// draw the whole thing to the backbuffer

17
	GraphicsDevice.SetRenderTarget(null);
18
	spriteBatch.Begin(0, BlendState.Opaque, SamplerState.PointClamp, null, null);
19
	spriteBatch.Draw(currentFrame, Vector2.Zero, Color.White);
20
	spriteBatch.End();
21
22
	Swap(ref currentFrame, ref lastFrame);
23
}
24
25
void Swap<T>(ref T a, ref T b)
26
{
27
	T temp = a;
28
	a = b;
29
	b = temp;
30
}

Schritt 7: Andere Variationen

Wir haben darüber gesprochen, Zweigblitze und Blitztexte zu erstellen, aber dies sind sicherlich nicht die einzigen Effekte, die Sie erzielen können. Schauen wir uns ein paar andere Variationen von Blitzen an, die Sie verwenden können.

Beweglicher Blitz

Oft möchten Sie vielleicht einen beweglichen Blitz machen. Sie können dies tun, indem Sie jedem Rahmen eine neue kurze Schraube am Endpunkt der Schraube des vorherigen Rahmens hinzufügen.

1
Vector2 lightningEnd = new Vector2(100, 100);
2
Vector2 lightningVelocity = new Vector2(50, 0);
3
4
void Update(GameTime gameTime)
5
{
6
	Bolts.Add(new LightningBolt(lightningEnd, lightningEnd + lightningVelocity));
7
	lightningEnd += lightningVelocity;
8
9
	// ...

10
}

Glatter Blitz

Sie haben vielleicht bemerkt, dass die Blitze an den Gelenken heller leuchten. Dies liegt an der Additivmischung. Vielleicht möchten Sie ein glatteres, gleichmäßigeres Aussehen für Ihren Blitz. Dies kann erreicht werden, indem Sie Ihre Mischstatusfunktion ändern, um den maximalen Wert der Quell- und Zielfarben auszuwählen, wie unten gezeigt.

1
private static readonly BlendState maxBlend = new BlendState()
2
{
3
		AlphaBlendFunction = BlendFunction.Max,
4
		ColorBlendFunction = BlendFunction.Max,
5
		AlphaDestinationBlend = Blend.One,
6
		AlphaSourceBlend = Blend.One,
7
		ColorDestinationBlend = Blend.One,
8
		ColorSourceBlend = Blend.One
9
};

Rufen Sie dann in Ihrer Draw()-Funktion SpriteBatch.Begin() mit maxBlend als BlendState anstelle von BlendState.Additive auf. Die folgenden Bilder zeigen den Unterschied zwischen additiver Mischung und maximaler Mischung auf einem Blitz.

Additive BlendingAdditive BlendingAdditive BlendingMax BlendingMax BlendingMax Blending

Bei maximaler Überblendung kann sich das Licht mehrerer Schrauben oder des Hintergrunds natürlich nicht gut summieren. Wenn Sie möchten, dass die Schraube selbst glatt aussieht, sich aber auch additiv mit anderen Schrauben verschmelzen lässt, können Sie die Schraube zuerst mit max. Achten Sie darauf, nicht zu viele große Renderziele zu verwenden, da dies die Leistung beeinträchtigen kann.

Eine andere Alternative, die bei einer großen Anzahl von Schrauben besser funktioniert, besteht darin, das in die Liniensegmentbilder integrierte Glühen zu entfernen und es mithilfe eines Nachbearbeitungs-Glüheffekts wieder hinzuzufügen. Die Details zur Verwendung von Shadern und zum Erstellen von Leuchteffekten sprengen den Rahmen dieses Tutorials, aber Sie können das XNA Bloom-Beispiel verwenden, um zu beginnen. Diese Technik erfordert keine weiteren Renderziele, wenn Sie weitere Schrauben hinzufügen.


Abschluss

Blitz ist ein großartiger Spezialeffekt, um Ihre Spiele aufzuwerten. Die in diesem Tutorial beschriebenen Effekte sind ein guter Ausgangspunkt, aber es ist sicherlich nicht alles, was Sie mit Blitzen tun können. Mit etwas Fantasie können Sie alle Arten von beeindruckenden Blitzeffekten erstellen! Laden Sie den Quellcode herunter und experimentieren Sie mit Ihrem eigenen.

Wenn Ihnen dieser Artikel gefallen hat, schauen Sie sich auch mein Tutorial über 2D-Wassereffekte an.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.