返回提交历史
Added
Common/DeathDomainPrimitiveTextureSystem.cs
+91
-0
Modified
Common/DeathDomainVisualSystem.cs
+31
-32
Modified
Common/MyGlobalNPC.cs
+35
-0
Modified
Common/MyPlayer.cs
+58
-0
Modified
Items/DeathNecklace.cs
+3
-0
Modified
Projectiles/DeathDomainHarvestSlashProjectile.cs
+46
-48
Modified
Projectiles/DeathDomainHarvestTelegraphProjectile.cs
+3
-36
XFEstudio/DeathMod
重制领域刀光并加入边缘牵引
6ea468c
代码差异
7 个文件
+267
-116
@@ -0,0 +1,91 @@
1
using Microsoft.Xna.Framework;
2
using Microsoft.Xna.Framework.Graphics;
3
using System;
4
using Terraria;
5
using Terraria.ModLoader;
6
7
namespace DeathMod.Common;
8
9
/// <summary>
10
/// Builds a high-resolution, antialiased double-pointed mask for death-domain
11
/// blades. Drawing a single stretched mask avoids the seams and blocky corners
12
/// produced by assembling a slash out of dozens of MagicPixel rectangles.
13
/// </summary>
14
[Autoload(Side = ModSide.Client)]
15
internal sealed class DeathDomainPrimitiveTextureSystem : ModSystem
16
{
17
internal static Texture2D? BladeMask { get; private set; }
18
19
public override void PostSetupContent()
20
{
21
if (Main.dedServ)
22
return;
23
24
const int width = 1024;
25
const int height = 256;
26
Texture2D texture = new(Main.instance.GraphicsDevice, width, height, false, SurfaceFormat.Color);
27
Color[] pixels = new Color[width * height];
28
29
for (int y = 0; y < height; y++)
30
{
31
float vertical = Math.Abs((y + 0.5f) / height * 2f - 1f);
32
for (int x = 0; x < width; x++)
33
{
34
float horizontal = (x + 0.5f) / width;
35
float envelope = (float)Math.Pow(Math.Max(0f, Math.Sin(horizontal * MathHelper.Pi)), 0.62f);
36
float signedDistance = envelope <= 0.0001f ? 4f : vertical / envelope;
37
float alpha = 1f - SmoothStep(0.955f, 1.035f, signedDistance);
38
39
// Runtime textures are not processed by the content pipeline, so
40
// store premultiplied white explicitly for clean tinted edges.
41
byte value = (byte)Math.Clamp((int)Math.Round(alpha * 255f), 0, 255);
42
pixels[y * width + x] = new Color(value, value, value, value);
43
}
44
}
45
46
texture.SetData(pixels);
47
BladeMask = texture;
48
}
49
50
public override void Unload()
51
{
52
BladeMask?.Dispose();
53
BladeMask = null;
54
}
55
56
internal static void DrawBlade(
57
Vector2 start,
58
float rotation,
59
float length,
60
float width,
61
Color color,
62
float completion = 1f)
63
{
64
Texture2D? texture = BladeMask;
65
completion = MathHelper.Clamp(completion, 0f, 1f);
66
if (texture is null || length <= 0.05f || width <= 0.05f || completion <= 0.001f)
67
return;
68
69
float visibleLength = Math.Max(0.5f, length * completion);
70
float widthGrowth = MathHelper.Lerp(0.22f, 1f, SmoothStep(0f, 0.55f, completion));
71
Main.EntitySpriteDraw(
72
texture,
73
start,
74
null,
75
color,
76
rotation,
77
new Vector2(0f, texture.Height * 0.5f),
78
new Vector2(visibleLength / texture.Width, width * widthGrowth / texture.Height),
79
SpriteEffects.None,
80
0f);
81
}
82
83
private static float SmoothStep(float start, float end, float value)
84
{
85
if (end <= start)
86
return value >= end ? 1f : 0f;
87
88
value = MathHelper.Clamp((value - start) / (end - start), 0f, 1f);
89
return value * value * (3f - 2f * value);
90
}
91
}
@@ -228,7 +228,7 @@ internal class DeathDomainVisualSystem : ModSystem
228
228
float noiseAmplitude,
229
229
Color color)
230
230
{
231
const int boundarySegments = 128;
231
const int boundarySegments = 192;
232
232
const float preferredBandHeight = 3f;
233
233
Span<Vector2> boundary = stackalloc Vector2[boundarySegments];
234
234
float extent = 0f;
@@ -282,7 +282,7 @@ internal class DeathDomainVisualSystem : ModSystem
282
282
float mastery,
283
283
bool gaps)
284
284
{
285
const int segments = 128;
285
const int segments = 256;
286
286
float previousAngle = 0f;
287
287
float previousRadius = baseRadius + BoundaryNoise(previousAngle, time, seed) * noiseAmplitude;
288
288
Vector2 previous = center + Vector2.UnitX * previousRadius;
@@ -330,48 +330,47 @@ internal class DeathDomainVisualSystem : ModSystem
330
330
float mastery,
331
331
float pulse)
332
332
{
333
int streamCount = 11 + (int)Math.Round(mastery * 7f);
334
float outerRadius = edgeRadius + MathHelper.Lerp(26f, 42f, mastery);
335
float innerRadius = Math.Max(4f, coreRadius - MathHelper.Lerp(4f, 12f, mastery));
333
// Long accretion streams outside the red boundary restore the visual
334
// language of a black-hole edge: distant, dark matter bends into a spiral
335
// and tightens as it reaches the event horizon.
336
int streamCount = 7 + (int)Math.Round(mastery * 5f);
337
float outerRadius = edgeRadius + MathHelper.Lerp(72f, 126f, mastery);
336
338
for (int stream = 0; stream < streamCount; stream++)
337
339
{
338
340
float seed = stream * 4.731f + 2.4f;
339
float progress = PositiveModulo(time * MathHelper.Lerp(0.42f, 0.68f, mastery) + stream / (float)streamCount, 1f);
340
float inwardProgress = MathHelper.SmoothStep(0f, 1f, progress);
341
float waveRadius = MathHelper.Lerp(outerRadius, innerRadius, inwardProgress);
341
float movingHead = PositiveModulo(time * MathHelper.Lerp(0.48f, 0.78f, mastery)
342
+ stream / (float)streamCount, 1f);
342
343
float baseAngle = stream * MathHelper.TwoPi / streamCount
343
- time * (0.18f + mastery * 0.12f)
344
+ inwardProgress * (0.28f + mastery * 0.2f)
345
+ BoundaryNoise(stream, time * 0.24f, seed) * 0.07f;
346
float halfArc = MathHelper.Lerp(0.17f, 0.055f, inwardProgress);
347
float fade = (float)Math.Sin(progress * MathHelper.Pi) * pulse;
348
float width = MathHelper.Lerp(4.6f + mastery * 1.8f, 1.1f, inwardProgress);
349
Color outerColor = Color.Lerp(new Color(118, 4, 30), new Color(245, 22, 70), mastery);
350
Color innerColor = Color.Lerp(new Color(245, 28, 70), new Color(255, 115, 155), mastery);
351
Color color = Color.Lerp(outerColor, innerColor, inwardProgress) * (fade * 0.62f);
352
353
const int points = 9;
344
- time * (0.13f + mastery * 0.08f)
345
+ BoundaryNoise(stream, time * 0.18f, seed) * 0.06f;
346
347
const int points = 46;
354
348
Vector2 previous = Vector2.Zero;
355
349
for (int point = 0; point < points; point++)
356
350
{
357
float alongArc = point / (points - 1f) * 2f - 1f;
358
float angle = baseAngle + alongArc * halfArc;
359
float taperedRadius = waveRadius
360
+ BoundaryNoise(angle, -time * 1.35f, seed) * MathHelper.Lerp(3.8f, 1.2f, inwardProgress)
361
- Math.Abs(alongArc) * MathHelper.Lerp(1f, 4f, inwardProgress);
362
Vector2 current = center + angle.ToRotationVector2() * taperedRadius;
351
float inward = point / (points - 1f);
352
float curved = inward * inward * (3f - 2f * inward);
353
float angle = baseAngle + inward * MathHelper.Lerp(1.08f, 1.54f, mastery);
354
float radius = MathHelper.Lerp(outerRadius, edgeRadius + 2f, curved)
355
+ BoundaryNoise(angle, -time * 0.82f, seed) * MathHelper.Lerp(5.2f, 1.2f, inward);
356
Vector2 current = center + angle.ToRotationVector2() * radius;
363
357
if (point > 0)
364
358
{
365
float taper = 1f - Math.Abs(alongArc) * 0.46f;
366
DrawSegment(batch, pixel, previous, current - previous, color * taper, width * taper);
359
float bodyFade = (float)Math.Sin(inward * MathHelper.Pi);
360
float distanceFromHead = Math.Abs(inward - movingHead);
361
distanceFromHead = Math.Min(distanceFromHead, 1f - distanceFromHead);
362
float movingGlow = 1f - MathHelper.SmoothStep(0.02f, 0.25f, distanceFromHead);
363
float opacity = bodyFade * pulse * (0.16f + movingGlow * 0.64f);
364
Color color = Color.Lerp(
365
new Color(18, 0, 8),
366
Color.Lerp(new Color(174, 3, 40), new Color(255, 34, 76), mastery),
367
inward * (0.45f + movingGlow * 0.55f));
368
float width = MathHelper.Lerp(0.55f, 3.4f + mastery * 1.7f, inward)
369
* (0.68f + movingGlow * 0.48f);
370
DrawSegment(batch, pixel, previous, current - previous, color * opacity, width);
367
371
}
368
372
previous = current;
369
373
}
370
371
// A short inward hook makes the direction of travel readable even in a still frame.
372
Vector2 hookStart = center + baseAngle.ToRotationVector2() * (waveRadius + width * 0.4f);
373
Vector2 hookEnd = center + (baseAngle + 0.035f).ToRotationVector2() * (waveRadius - MathHelper.Lerp(5f, 11f, inwardProgress));
374
DrawSegment(batch, pixel, hookStart, hookEnd - hookStart, color * 0.72f, Math.Max(0.8f, width * 0.62f));
375
374
}
376
375
}
377
376
@@ -27,6 +27,8 @@ public class MyGlobalNPC : GlobalNPC
27
27
private int lastSicklePlayer = -1;
28
28
private int fatedSecondTimer;
29
29
private bool deathMarked;
30
private int deathDomainHitStopFrames;
31
private Vector2 deathDomainStoredVelocity;
30
32
31
33
public int FatedStackCount { get; private set; }
32
34
@@ -39,9 +41,30 @@ public class MyGlobalNPC : GlobalNPC
39
41
lastSicklePlayer = -1;
40
42
fatedSecondTimer = 0;
41
43
deathMarked = false;
44
deathDomainHitStopFrames = 0;
45
deathDomainStoredVelocity = Vector2.Zero;
42
46
FatedStackCount = 0;
43
47
}
44
48
49
public override bool PreAI(NPC npc)
50
{
51
if (deathDomainHitStopFrames <= 0)
52
return true;
53
54
deathDomainHitStopFrames--;
55
npc.velocity = Vector2.Zero;
56
if (deathDomainHitStopFrames <= 0)
57
{
58
// Restore only part of the previous movement so the pause reads as an
59
// impact without launching fast enemies immediately out of the blade.
60
npc.velocity = deathDomainStoredVelocity * 0.35f;
61
deathDomainStoredVelocity = Vector2.Zero;
62
if (Main.netMode != NetmodeID.MultiplayerClient)
63
npc.netUpdate = true;
64
}
65
return false;
66
}
67
45
68
public override void ModifyHitByItem(NPC npc, Player player, Item item, ref NPC.HitModifiers modifiers)
46
69
{
47
70
if (item.ModItem is not (NormalSickle or LegacyDeath))
@@ -214,6 +237,18 @@ public class MyGlobalNPC : GlobalNPC
214
237
DeathMod.BroadcastDeathMark(npc, marked: true);
215
238
}
216
239
240
internal void ApplyDeathDomainHitStop(NPC npc, int frames)
241
{
242
frames = Math.Clamp(frames, 1, 4);
243
if (deathDomainHitStopFrames <= 0)
244
deathDomainStoredVelocity = npc.velocity;
245
246
deathDomainHitStopFrames = Math.Max(deathDomainHitStopFrames, frames);
247
npc.velocity = Vector2.Zero;
248
if (Main.netMode != NetmodeID.MultiplayerClient)
249
npc.netUpdate = true;
250
}
251
217
252
internal void ReceiveDeathMarkState(bool marked)
218
253
{
219
254
deathMarked = marked;
@@ -370,6 +370,7 @@ public class MyPlayer : ModPlayer
370
370
return;
371
371
}
372
372
373
ApplyDeathDomainAttraction(necklace);
373
374
List<NPC> targets = FindDeathDomainTargets(necklace);
374
375
float visualMastery = MathHelper.Clamp((necklace.MasteryScore - 5f) / 65f, 0f, 1f);
375
376
UpdateDeathDomainTelegraphs(targets, necklace, visualMastery);
@@ -558,6 +559,63 @@ public class MyPlayer : ModPlayer
558
559
return targets;
559
560
}
560
561
562
private void ApplyDeathDomainAttraction(DeathNecklace necklace)
563
{
564
// A sovereign full-screen domain has no meaningful exterior on the active
565
// battlefield. Its targets are already inside, so no pull is necessary.
566
if (necklace.IsFullScreenDomain)
567
return;
568
569
float innerRadius = necklace.DomainRadius;
570
float outerRadius = necklace.DomainAttractionRadius;
571
float innerRadiusSquared = innerRadius * innerRadius;
572
float outerRadiusSquared = outerRadius * outerRadius;
573
float attractionWidth = Math.Max(1f, outerRadius - innerRadius);
574
HashSet<int> affectedTargets = [];
575
576
foreach (NPC npc in Main.ActiveNPCs)
577
{
578
if (npc.friendly || npc.immortal || npc.dontTakeDamage || npc.lifeMax <= 5 || npc.life <= 0)
579
continue;
580
581
NPC target = npc.realLife >= 0 && npc.realLife < Main.maxNPCs && Main.npc[npc.realLife].active
582
? Main.npc[npc.realLife]
583
: npc;
584
if (target.friendly || target.immortal || target.dontTakeDamage || target.lifeMax <= 5 || target.life <= 0
585
|| !affectedTargets.Add(target.whoAmI))
586
{
587
continue;
588
}
589
590
Vector2 toDomain = Player.Center - target.Center;
591
float distanceSquared = toDomain.LengthSquared();
592
// Crossing the red boundary terminates the force immediately. This is
593
// deliberately not a vortex that continues dragging enemies at centre.
594
if (distanceSquared <= innerRadiusSquared || distanceSquared > outerRadiusSquared || distanceSquared < 0.001f)
595
continue;
596
597
float distance = (float)Math.Sqrt(distanceSquared);
598
float normalizedDistance = MathHelper.Clamp((distance - innerRadius) / attractionWidth, 0f, 1f);
599
float edgeInfluence = 1f - normalizedDistance;
600
edgeInfluence = edgeInfluence * edgeInfluence * (3f - 2f * edgeInfluence);
601
bool bossOrBossPart = target.boss
602
|| NPCID.Sets.ShouldBeCountedAsBoss[target.type]
603
|| target.realLife >= 0 && target.realLife < Main.maxNPCs && Main.npc[target.realLife].boss;
604
float bossScale = bossOrBossPart ? 0.18f : 1f;
605
float force = necklace.DomainAttractionStrength * MathHelper.Lerp(0.22f, 1f, edgeInfluence) * bossScale;
606
float maximumInwardSpeed = necklace.DomainAttractionMaximumSpeed * (bossOrBossPart ? 0.35f : 1f);
607
Vector2 inward = toDomain / distance;
608
float currentInwardSpeed = Vector2.Dot(target.velocity, inward);
609
float allowedForce = Math.Max(0f, maximumInwardSpeed - currentInwardSpeed);
610
target.velocity += inward * Math.Min(force, allowedForce);
611
612
// Periodic authoritative velocity updates are enough for this gentle
613
// force while avoiding an NPC sync packet on every tick.
614
if ((Main.GameUpdateCount + (ulong)target.whoAmI) % 10UL == 0UL)
615
target.netUpdate = true;
616
}
617
}
618
561
619
private static int CalculateDeathDomainSlashDamage(NPC target, DeathNecklace necklace)
562
620
{
563
621
bool bossOrBossPart = target.boss
@@ -33,6 +33,9 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
33
33
public bool SovereigntyUnlocked { get; private set; }
34
34
35
35
public float DomainRadius => 160f + (RadiusLevel - 1) * 32f;
36
public float DomainAttractionRadius => DomainRadius + 320f + (RadiusLevel - 1) * 32f;
37
public float DomainAttractionStrength => 0.035f + (RadiusLevel - 1) * 0.0075f;
38
public float DomainAttractionMaximumSpeed => 0.75f + (RadiusLevel - 1) * 0.09f;
36
39
public int SpawnInterval => Math.Max(34, 100 - (FrequencyLevel - 1) * 7);
37
40
public float NormalSlashLifeRatio => DamageLevel * 0.01f;
38
41
public float BossSlashLifeRatio => DamageLevel * 0.0001f;
@@ -140,9 +140,9 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
140
140
float width = (28f + Mastery * 18f + (IsRequiem ? 12f : 0f)) * Projectile.scale;
141
141
Vector2 center = Projectile.Center - Main.screenPosition;
142
142
143
// Three passes over the exact same tapered silhouette produce one integrated
144
// blade. reveal advances from t=0 to t=1, so the cut travels from one tip
145
// toward the other instead of opening outward from its center.
143
// Three passes over one continuous high-resolution silhouette produce one
144
// integrated blade. reveal stretches it from the starting tip toward the
145
// destination, with no MagicPixel seams between individual segments.
146
146
DrawTaperedBladeLayer(center, rotation, length, width * 1.52f, reveal,
147
147
new Color(92, 0, 22, 0) * (strength * 0.54f));
148
148
DrawTaperedBladeLayer(center, rotation, length, width, reveal,
@@ -155,10 +155,36 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
155
155
Vector2 start = center - direction * length * 0.5f;
156
156
Vector2 cuttingEdge = start + direction * (length * reveal);
157
157
float spark = (8f + Mastery * 5f) * Projectile.scale * strength;
158
DrawSegment(cuttingEdge - normal * spark,
159
cuttingEdge + normal * spark,
160
new Color(255, 12, 52, 0) * strength,
161
1.6f + Mastery);
158
159
DeathDomainPrimitiveTextureSystem.DrawBlade(
160
cuttingEdge - normal * spark,
161
normal.ToRotation(),
162
spark * 2f,
163
1.6f + Mastery,
164
new Color(255, 12, 52, 0) * strength);
165
166
// A second, much longer blood-line races through the black core shortly
167
// after the main blade arrives. It gives the execution a crisp crimson
168
// centre without turning the whole strike into another thick beam.
169
float bloodReveal = Smooth01((progress - 0.08f) / 0.34f);
170
float bloodFade = 1f - Smooth01((progress - 0.64f) / 0.28f);
171
float bloodStrength = bloodReveal * bloodFade;
172
float bloodLength = length * (1.78f + Mastery * 0.28f + (IsRequiem ? 0.18f : 0f));
173
Vector2 bloodStart = center - direction * bloodLength * 0.5f;
174
DeathDomainPrimitiveTextureSystem.DrawBlade(
175
bloodStart,
176
rotation,
177
bloodLength,
178
(6.2f + Mastery * 2.2f) * Projectile.scale,
179
new Color(95, 0, 24, 0) * (bloodStrength * 0.72f),
180
bloodReveal);
181
DeathDomainPrimitiveTextureSystem.DrawBlade(
182
bloodStart,
183
rotation,
184
bloodLength,
185
(1.25f + Mastery * 0.55f) * Projectile.scale,
186
new Color(255, 0, 38, 0) * bloodStrength,
187
bloodReveal);
162
188
}
163
189
164
190
private static void DrawTaperedBladeLayer(Vector2 center, float rotation, float length, float maximumWidth, float reveal, Color color)
@@ -166,32 +192,13 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
166
192
if (maximumWidth <= 0.05f || reveal <= 0f)
167
193
return;
168
194
169
Vector2 direction = rotation.ToRotationVector2();
170
Vector2 start = center - direction * length * 0.5f;
171
const int pieces = 36;
172
int visiblePieces = Math.Clamp((int)Math.Ceiling(reveal * pieces), 1, pieces);
173
for (int piece = 0; piece < visiblePieces; piece++)
174
{
175
float t0 = piece / (float)pieces;
176
float t1 = Math.Min(reveal, (piece + 1f) / pieces);
177
if (t1 <= t0)
178
continue;
179
float middle = (t0 + t1) * 0.5f;
180
float bodyTaper = (float)Math.Pow(Math.Max(0f, Math.Sin(MathHelper.Pi * middle)), 0.64f);
181
float movingTipTaper = Smooth01((reveal - middle) / 0.075f);
182
DrawSegment(
183
start + direction * (length * t0),
184
start + direction * (length * t1 + 0.8f),
185
color,
186
Math.Max(0.15f, maximumWidth * bodyTaper * movingTipTaper));
187
}
195
Vector2 start = center - rotation.ToRotationVector2() * length * 0.5f;
196
DeathDomainPrimitiveTextureSystem.DrawBlade(start, rotation, length, maximumWidth, color, reveal);
188
197
}
189
198
190
199
private void ApplyHarvestDamage()
191
200
{
192
if (Main.netMode == NetmodeID.MultiplayerClient
193
|| Projectile.damage <= 0
194
|| Projectile.owner < 0
201
if (Projectile.owner < 0
195
202
|| Projectile.owner >= Main.maxPlayers
196
203
|| TargetIndex < 0
197
204
|| TargetIndex >= Main.maxNPCs)
@@ -203,6 +210,16 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
203
210
if (!target.active || target.friendly || target.immortal || target.dontTakeDamage || target.life <= 0)
204
211
return;
205
212
213
bool bossOrBossPart = target.boss
214
|| NPCID.Sets.ShouldBeCountedAsBoss[target.type]
215
|| target.realLife >= 0 && target.realLife < Main.maxNPCs && Main.npc[target.realLife].boss;
216
target.GetGlobalNPC<MyGlobalNPC>().ApplyDeathDomainHitStop(target, bossOrBossPart ? 1 : 3);
217
218
// Explicit client visuals repeat the timing of the hidden server scheduler.
219
// They only apply the local hit-stop above; damage remains authoritative.
220
if (Main.netMode == NetmodeID.MultiplayerClient || Projectile.damage <= 0)
221
return;
222
206
223
target.GetGlobalNPC<MyGlobalNPC>().RegisterSickleHit(target, Projectile.owner);
207
224
target.lastInteraction = Projectile.owner;
208
225
NPC.HitInfo harvestHit = new()
@@ -281,25 +298,6 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
281
298
return (126f + mastery * 76f) * scale * variation;
282
299
}
283
300
284
private static void DrawSegment(Vector2 start, Vector2 end, Color color, float width)
285
{
286
Vector2 segment = end - start;
287
if (segment.LengthSquared() < 0.01f || width <= 0.01f)
288
return;
289
290
Texture2D pixel = TextureAssets.MagicPixel.Value;
291
Main.EntitySpriteDraw(
292
pixel,
293
start,
294
null,
295
color,
296
segment.ToRotation(),
297
new Vector2(0f, pixel.Height * 0.5f),
298
new Vector2(segment.Length() / pixel.Width, width / pixel.Height),
299
SpriteEffects.None,
300
0f);
301
}
302
303
301
private static float Smooth01(float value)
304
302
{
305
303
value = MathHelper.Clamp(value, 0f, 1f);
@@ -1,10 +1,9 @@
1
using DeathMod.Common;
1
2
using Microsoft.Xna.Framework;
2
using Microsoft.Xna.Framework.Graphics;
3
3
using System;
4
4
using System.IO;
5
5
using Terraria;
6
6
using Terraria.DataStructures;
7
using Terraria.GameContent;
8
7
using Terraria.ID;
9
8
using Terraria.ModLoader;
10
9
@@ -106,39 +105,7 @@ public class DeathDomainHarvestTelegraphProjectile : ModProjectile
106
105
107
106
private static void DrawTaperedLine(Vector2 center, float rotation, float length, float maximumWidth, Color color)
108
107
{
109
Vector2 direction = rotation.ToRotationVector2();
110
Vector2 start = center - direction * length * 0.5f;
111
const int pieces = 28;
112
for (int piece = 0; piece < pieces; piece++)
113
{
114
float t0 = piece / (float)pieces;
115
float t1 = (piece + 1f) / pieces;
116
float middle = (t0 + t1) * 0.5f;
117
float taper = (float)Math.Pow(Math.Max(0f, Math.Sin(MathHelper.Pi * middle)), 0.62f);
118
DrawSegment(
119
start + direction * (length * t0),
120
start + direction * (length * t1 + 0.8f),
121
color,
122
Math.Max(0.15f, maximumWidth * taper));
123
}
124
}
125
126
private static void DrawSegment(Vector2 start, Vector2 end, Color color, float width)
127
{
128
Vector2 segment = end - start;
129
if (segment.LengthSquared() < 0.01f)
130
return;
131
132
Texture2D pixel = TextureAssets.MagicPixel.Value;
133
Main.EntitySpriteDraw(
134
pixel,
135
start,
136
null,
137
color,
138
segment.ToRotation(),
139
new Vector2(0f, pixel.Height * 0.5f),
140
new Vector2(segment.Length() / pixel.Width, width / pixel.Height),
141
SpriteEffects.None,
142
0f);
108
Vector2 start = center - rotation.ToRotationVector2() * length * 0.5f;
109
DeathDomainPrimitiveTextureSystem.DrawBlade(start, rotation, length, maximumWidth, color);
143
110
}
144
111
}