diff --git a/Assets/_Project/Art/Materials/M_Electrical_Glow.mat b/Assets/_Project/Art/Materials/M_Electrical_Glow.mat
index 558d2db..1dd11fe 100644
--- a/Assets/_Project/Art/Materials/M_Electrical_Glow.mat
+++ b/Assets/_Project/Art/Materials/M_Electrical_Glow.mat
@@ -105,7 +105,7 @@ Material:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- - _Blend: 2
+ - _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
@@ -114,8 +114,8 @@ Material:
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- - _DstBlend: 1
- - _DstBlendAlpha: 1
+ - _DstBlend: 10
+ - _DstBlendAlpha: 10
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity
index 32942ce..76b7f7f 100644
--- a/Assets/_Project/Scenes/Levels/9Player.unity
+++ b/Assets/_Project/Scenes/Levels/9Player.unity
@@ -12226,6 +12226,55 @@ Mesh:
- serializedVersion: 1
m_IndexStart: 0
m_IndexCount: 0
+--- !u!1 &832575517
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 832575519}
+ - component: {fileID: 832575518}
+ m_Layer: 0
+ m_Name: Global Volume
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &832575518
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 832575517}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_IsGlobal: 1
+ priority: 0
+ blendDistance: 0
+ weight: 1
+ sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2}
+--- !u!4 &832575519
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 832575517}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &839198900
GameObject:
m_ObjectHideFlags: 0
@@ -28696,6 +28745,7 @@ SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 410087041}
+ - {fileID: 832575519}
- {fileID: 441239881}
- {fileID: 167151709}
- {fileID: 1507514109}
diff --git a/Assets/_Project/Scripts/Combat/TeslaArcVisual.cs b/Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
index c4e7828..20de293 100644
--- a/Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
+++ b/Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
@@ -6,92 +6,35 @@ namespace TD.Combat
{
///
/// Local-only electrical-arc visual for
- /// towers (Tesla Coil). Subscribes to and draws an
- /// arced, jittering bolt from the tower's emitter to every enemy hit, re-randomized each
- /// frame so it crackles, then hidden after a short flash.
+ /// towers (Tesla Coil). Subscribes to and draws a
+ /// jagged line from the tower's emitter point to every enemy hit, flashed for a moment.
///
///
/// Pure visualization — runs on every peer from the replicated fire broadcast; nothing
- /// here is networked. Bolts are pooled s reused across ticks.
- /// The glow (bloom) comes from the material + an HDR color above the bloom threshold; see
- /// and the project's post-processing Volume.
+ /// here is networked. Arcs are pooled s reused across ticks.
///
[RequireComponent(typeof(TowerCombat))]
public class TeslaArcVisual : MonoBehaviour
{
- [Tooltip("Point the bolts originate from — the central top of the coil. " +
+ [Tooltip("Point the arcs originate from — the central top of the coil. " +
"If unset, falls back to one unit above the tower root.")]
[SerializeField] private Transform emitter;
- [Tooltip("Material for the bolts. Use an UNLIT ADDITIVE material for a convincing " +
- "glow (a Lit material won't bloom well on a thin line). If unset, a fallback " +
- "additive material is created at runtime.")]
+ [Tooltip("Material for the arc lines. Assign an unlit/additive material for a glow. " +
+ "If unset, a fallback Sprites/Default material is created at runtime.")]
[SerializeField] private Material arcMaterial;
- [Tooltip("Base bolt color. Multiplied by Emission Intensity to push it into HDR so " +
- "Bloom picks it up.")]
- [ColorUsage(true, true)]
- [SerializeField] private Color arcColor = new Color(0.55f, 0.8f, 1f, 1f);
-
- [Tooltip("HDR multiplier on the color. Must exceed the Bloom threshold (>1) for the " +
- "bolt to glow. Raise for a hotter, brighter arc.")]
- [SerializeField] private float emissionIntensity = 4f;
-
+ [SerializeField] private Color arcColor = new Color(0.6f, 0.85f, 1f, 1f);
[SerializeField] private float arcWidth = 0.06f;
-
- [Tooltip("How long each flash stays visible, in seconds.")]
+ [Tooltip("How long each arc flash stays visible, in seconds.")]
[SerializeField] private float arcDuration = 0.12f;
-
- [Tooltip("Points per bolt. More = smoother arc and finer crackle. ~12-20 looks good.")]
- [SerializeField] private int segmentsPerArc = 16;
-
- [Tooltip("Overall arc/bow as a fraction of bolt length (0 = straight line). The bolt " +
- "lifts toward the middle for an electrical-arc curve.")]
- [SerializeField] private float arcHeight = 0.18f;
-
- [Tooltip("Random crackle displacement (world units) at the middle of the bolt, " +
- "tapering to 0 at both ends so it stays anchored to the coil and enemy.")]
- [SerializeField] private float jitter = 0.18f;
-
- [Header("Light flash")]
- [Tooltip("Pulse a real point light at the emitter when firing so the bolts actually " +
- "illuminate nearby enemies (emission/bloom alone don't cast light).")]
- [SerializeField] private bool castLight = true;
-
- [Tooltip("Color of the flash light.")]
- [SerializeField] private Color lightColor = new Color(0.6f, 0.85f, 1f);
-
- [Tooltip("Peak intensity of the flash. The light flickers between this and ~70% of " +
- "it while firing for an electrical pulse.")]
- [SerializeField] private float lightIntensity = 8f;
-
- [Tooltip("Range of the emitter flash light — covers enemies near the coil.")]
- [SerializeField] private float lightRange = 12f;
-
- [Tooltip("Also flash a small light at each bolt's IMPACT point, so enemies struck at " +
- "the far edge of range get lit by the bolt — not just those near the coil.")]
- [SerializeField] private bool castImpactLight = true;
-
- [Tooltip("Peak intensity of each impact light (usually lower than the emitter flash).")]
- [SerializeField] private float impactLightIntensity = 4f;
-
- [Tooltip("Range of each impact light — only needs to cover the struck enemy, so keep it small.")]
- [SerializeField] private float impactLightRange = 5f;
-
- [Tooltip("Performance cap on simultaneous impact lights. URP limits how many lights " +
- "affect each object, and many towers add up — targets beyond this cap rely on " +
- "the emitter flash. Raise carefully.")]
- [SerializeField] private int maxImpactLights = 8;
+ [Tooltip("Number of points per arc. More = more jagged detail.")]
+ [SerializeField] private int segmentsPerArc = 6;
+ [Tooltip("Random offset applied to interior arc points for the lightning look.")]
+ [SerializeField] private float jitter = 0.2f;
private TowerCombat combat;
private readonly List pool = new List();
- private Light flashLight;
- private readonly List impactLightPool = new List();
-
- // Snapshot of the current flash so Update can re-randomize the bolts each frame.
- private Vector3[] activeTargets;
- private int activeCount;
- private bool active;
private float hideAt = -1f;
private void Awake() => combat = GetComponent();
@@ -108,120 +51,31 @@ namespace TD.Combat
private void Update()
{
- if (!active) return;
-
- if (Time.time >= hideAt)
+ if (hideAt >= 0f && Time.time >= hideAt)
{
- HideAll();
- active = false;
- return;
+ for (int i = 0; i < pool.Count; i++) pool[i].enabled = false;
+ hideAt = -1f;
}
-
- // Re-draw every frame with fresh jitter so the bolts crackle while visible.
- RedrawBolts();
}
private void HandleAreaFired(Vector3[] positions)
{
- if (positions == null || positions.Length == 0) return;
+ if (positions == null) return;
- activeTargets = positions; // RPC hands us a fresh array each call — safe to keep
- activeCount = positions.Length;
- active = true;
- hideAt = Time.time + arcDuration;
-
- RedrawBolts();
- }
-
- private void RedrawBolts()
- {
Vector3 origin = emitter != null ? emitter.position : transform.position + Vector3.up;
- for (int i = 0; i < activeCount; i++)
+ for (int i = 0; i < positions.Length; i++)
{
var lr = GetLine(i);
- DrawBolt(lr, origin, activeTargets[i]);
+ DrawArc(lr, origin, positions[i]);
lr.enabled = true;
}
- // Disable any leftover bolts from a previous, larger tick.
- for (int i = activeCount; i < pool.Count; i++)
+ // Disable any leftover lines from a previous, larger tick.
+ for (int i = positions.Length; i < pool.Count; i++)
pool[i].enabled = false;
- // Pulse the emitter light so the coil/source lights nearby enemies.
- if (castLight)
- {
- var fl = GetFlashLight();
- fl.intensity = lightIntensity * Random.Range(0.7f, 1f); // electrical flicker
- fl.enabled = true;
- }
-
- // Pulse a light at each bolt's impact point so far-struck enemies get lit by the
- // bolt itself. Capped for performance; extra targets rely on the emitter flash.
- if (castImpactLight)
- {
- int lit = Mathf.Min(activeCount, maxImpactLights);
- for (int i = 0; i < lit; i++)
- {
- var il = GetImpactLight(i);
- il.transform.position = activeTargets[i];
- il.intensity = impactLightIntensity * Random.Range(0.7f, 1f);
- il.enabled = true;
- }
- for (int i = lit; i < impactLightPool.Count; i++)
- impactLightPool[i].enabled = false;
- }
- }
-
- private void HideAll()
- {
- for (int i = 0; i < pool.Count; i++)
- pool[i].enabled = false;
-
- if (flashLight != null) flashLight.enabled = false;
- for (int i = 0; i < impactLightPool.Count; i++)
- impactLightPool[i].enabled = false;
- }
-
- // Lazily creates a small world-space point light for a bolt's impact point.
- private Light GetImpactLight(int index)
- {
- while (impactLightPool.Count <= index)
- {
- var go = new GameObject($"ArcImpactLight_{impactLightPool.Count}");
- go.transform.SetParent(transform, worldPositionStays: true);
-
- var l = go.AddComponent();
- l.type = LightType.Point;
- l.color = lightColor;
- l.range = impactLightRange;
- l.shadows = LightShadows.None;
- l.intensity = 0f;
- l.enabled = false;
- impactLightPool.Add(l);
- }
- return impactLightPool[index];
- }
-
- // Lazily creates the point light at the emitter (parented so it tracks the coil).
- private Light GetFlashLight()
- {
- if (flashLight == null)
- {
- var go = new GameObject("ArcFlashLight");
- Transform parent = emitter != null ? emitter : transform;
- go.transform.SetParent(parent, worldPositionStays: false);
- go.transform.localPosition = Vector3.zero;
-
- flashLight = go.AddComponent();
- flashLight.type = LightType.Point;
- flashLight.color = lightColor;
- flashLight.range = lightRange;
- flashLight.shadows = LightShadows.None; // perf: brief flashes don't need shadows
- flashLight.intensity = 0f;
- flashLight.enabled = false;
- }
- return flashLight;
+ hideAt = Time.time + arcDuration;
}
private LineRenderer GetLine(int index)
@@ -230,74 +84,33 @@ namespace TD.Combat
{
var go = new GameObject($"Arc_{pool.Count}");
go.transform.SetParent(transform, worldPositionStays: false);
-
var lr = go.AddComponent();
- lr.useWorldSpace = true;
- lr.widthMultiplier = arcWidth;
- lr.numCapVertices = 4;
- lr.numCornerVertices = 4;
- lr.alignment = LineAlignment.View; // face the camera, like a billboard
- lr.textureMode = LineTextureMode.Stretch;
+ lr.useWorldSpace = true;
+ lr.widthMultiplier = arcWidth;
+ lr.numCapVertices = 2;
+ lr.textureMode = LineTextureMode.Stretch;
lr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- lr.material = arcMaterial != null ? arcMaterial : CreateFallbackMaterial();
-
- // HDR color so Bloom in the post stack picks the bolt up as a glow.
- Color hdr = arcColor * Mathf.Max(1f, emissionIntensity);
- hdr.a = 1f;
- lr.startColor = lr.endColor = hdr;
-
- lr.enabled = false;
+ lr.material = arcMaterial != null
+ ? arcMaterial
+ : new Material(Shader.Find("Sprites/Default"));
+ lr.startColor = lr.endColor = arcColor;
+ lr.enabled = false;
pool.Add(lr);
}
return pool[index];
}
- // Additive unlit fallback so bolts still glow if no material is assigned. Prefer
- // assigning a real material in the inspector.
- private static Material CreateFallbackMaterial()
- {
- var shader = Shader.Find("Universal Render Pipeline/Particles/Unlit")
- ?? Shader.Find("Sprites/Default");
- return new Material(shader);
- }
-
- // Builds an arced, jagged bolt from a to b. A smooth sine bow gives the overall arc;
- // tapered random perpendicular offsets give the electrical crackle. Endpoints stay
- // exactly on the coil and the enemy.
- private void DrawBolt(LineRenderer lr, Vector3 a, Vector3 b)
+ private void DrawArc(LineRenderer lr, Vector3 a, Vector3 b)
{
int n = Mathf.Max(2, segmentsPerArc);
lr.positionCount = n;
-
- Vector3 delta = b - a;
- float len = delta.magnitude;
- Vector3 dir = len > 1e-4f ? delta / len : Vector3.forward;
-
- // Bow toward world-up, projected perpendicular to the bolt (any perpendicular for
- // near-vertical bolts), plus a sideways axis for 3D crackle.
- Vector3 bowDir = Vector3.up - dir * Vector3.Dot(Vector3.up, dir);
- if (bowDir.sqrMagnitude < 1e-4f) bowDir = Vector3.Cross(dir, Vector3.right);
- bowDir.Normalize();
- Vector3 sideDir = Vector3.Cross(dir, bowDir);
-
- float bow = arcHeight * len;
-
for (int s = 0; s < n; s++)
{
float t = s / (float)(n - 1);
- Vector3 p = a + delta * t;
-
- // Smooth arc — sine peaks at the middle, zero at both ends.
- float curve = Mathf.Sin(t * Mathf.PI);
- p += bowDir * (bow * curve);
-
- // Crackle on interior points, tapered to nothing at the ends.
+ Vector3 p = Vector3.Lerp(a, b, t);
+ // Jitter interior points only — endpoints stay anchored to the coil and enemy.
if (s != 0 && s != n - 1)
- {
- p += bowDir * (Random.Range(-jitter, jitter) * curve);
- p += sideDir * (Random.Range(-jitter, jitter) * curve);
- }
-
+ p += Random.insideUnitSphere * jitter;
lr.SetPosition(s, p);
}
}
diff --git a/Assets/_Project/Scripts/Combat/TowerCombat.cs b/Assets/_Project/Scripts/Combat/TowerCombat.cs
index 9c9ac7c..657d5f8 100644
--- a/Assets/_Project/Scripts/Combat/TowerCombat.cs
+++ b/Assets/_Project/Scripts/Combat/TowerCombat.cs
@@ -473,6 +473,8 @@ namespace TD.Combat
{
var multiplier = GetOwnerBuffManager()?.GetMultiplier(BuffStat.Damage) ?? 1f;
float effectiveDamage = p.Damage * multiplier;
+ Debug.Log("multiplier: " + multiplier);
+ Debug.Log("Effective damage: " + effectiveDamage);
target.TakeDamage(effectiveDamage, p.DamageType, owner);
ApplyStatusEffect(p, target, owner);
}
diff --git a/Assets/_Project/Settings/DefaultVolumeProfile.asset b/Assets/_Project/Settings/DefaultVolumeProfile.asset
index 1c6d468..66d98de 100644
--- a/Assets/_Project/Settings/DefaultVolumeProfile.asset
+++ b/Assets/_Project/Settings/DefaultVolumeProfile.asset
@@ -37,13 +37,13 @@ MonoBehaviour:
active: 1
shadows:
m_OverrideState: 1
- m_Value: {r: 0.5458793, g: 0.6841803, b: 0.8207547, a: 1}
+ m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1}
highlights:
m_OverrideState: 1
- m_Value: {r: 0.9811321, g: 0.7474893, b: 0.50445, a: 1}
+ m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1}
balance:
m_OverrideState: 1
- m_Value: -25
+ m_Value: 0
--- !u!114 &-8104416584915340131
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -161,10 +161,10 @@ MonoBehaviour:
active: 1
postExposure:
m_OverrideState: 1
- m_Value: -0.2
+ m_Value: 0
contrast:
m_OverrideState: 1
- m_Value: 20
+ m_Value: 0
colorFilter:
m_OverrideState: 1
m_Value: {r: 1, g: 1, b: 1, a: 1}
@@ -173,7 +173,7 @@ MonoBehaviour:
m_Value: 0
saturation:
m_OverrideState: 1
- m_Value: -25
+ m_Value: 0
--- !u!114 &-6288072647309666549
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -192,7 +192,7 @@ MonoBehaviour:
m_Value: 0
intensity:
m_OverrideState: 1
- m_Value: 0.3
+ m_Value: 0
response:
m_OverrideState: 1
m_Value: 0.8
@@ -214,7 +214,7 @@ MonoBehaviour:
active: 1
mode:
m_OverrideState: 1
- m_Value: 2
+ m_Value: 0
neutralHDRRangeReductionMode:
m_OverrideState: 1
m_Value: 2
@@ -363,10 +363,10 @@ MonoBehaviour:
m_Value: 1
threshold:
m_OverrideState: 1
- m_Value: 0.7
+ m_Value: 0.9
intensity:
m_OverrideState: 1
- m_Value: 1
+ m_Value: 0
scatter:
m_OverrideState: 1
m_Value: 0.7
@@ -410,10 +410,10 @@ MonoBehaviour:
active: 1
temperature:
m_OverrideState: 1
- m_Value: -8
+ m_Value: 0
tint:
m_OverrideState: 1
- m_Value: 5
+ m_Value: 0
--- !u!114 &-581120513425526550
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -855,7 +855,7 @@ MonoBehaviour:
active: 1
intensity:
m_OverrideState: 1
- m_Value: 0.1
+ m_Value: 0
--- !u!114 &6940869943325143175
MonoBehaviour:
m_ObjectHideFlags: 3
@@ -890,7 +890,7 @@ MonoBehaviour:
m_Value: {x: 0.5, y: 0.5}
intensity:
m_OverrideState: 1
- m_Value: 0.35
+ m_Value: 0
smoothness:
m_OverrideState: 1
m_Value: 0.2
diff --git a/Assets/_Project/Settings/Render Settings/URP-High.asset b/Assets/_Project/Settings/Render Settings/URP-High.asset
index 330830a..074ee15 100644
--- a/Assets/_Project/Settings/Render Settings/URP-High.asset
+++ b/Assets/_Project/Settings/Render Settings/URP-High.asset
@@ -45,7 +45,7 @@ MonoBehaviour:
m_MainLightShadowsSupported: 1
m_MainLightShadowmapResolution: 4096
m_AdditionalLightsRenderingMode: 1
- m_AdditionalLightsPerObjectLimit: 6
+ m_AdditionalLightsPerObjectLimit: 2
m_AdditionalLightShadowsSupported: 1
m_AdditionalLightsShadowmapResolution: 4096
m_AdditionalLightsShadowResolutionTierLow: 256
diff --git a/Assets/_Project/Settings/Render Settings/URP-Medium.asset b/Assets/_Project/Settings/Render Settings/URP-Medium.asset
index c5c5444..3b9f2ab 100644
--- a/Assets/_Project/Settings/Render Settings/URP-Medium.asset
+++ b/Assets/_Project/Settings/Render Settings/URP-Medium.asset
@@ -45,7 +45,7 @@ MonoBehaviour:
m_MainLightShadowsSupported: 1
m_MainLightShadowmapResolution: 2048
m_AdditionalLightsRenderingMode: 1
- m_AdditionalLightsPerObjectLimit: 4
+ m_AdditionalLightsPerObjectLimit: 2
m_AdditionalLightShadowsSupported: 1
m_AdditionalLightsShadowmapResolution: 2048
m_AdditionalLightsShadowResolutionTierLow: 256
diff --git a/Assets/_Project/Settings/Render Settings/URP-Ultra.asset b/Assets/_Project/Settings/Render Settings/URP-Ultra.asset
index 46ffed0..9564d20 100644
--- a/Assets/_Project/Settings/Render Settings/URP-Ultra.asset
+++ b/Assets/_Project/Settings/Render Settings/URP-Ultra.asset
@@ -45,7 +45,7 @@ MonoBehaviour:
m_MainLightShadowsSupported: 1
m_MainLightShadowmapResolution: 8192
m_AdditionalLightsRenderingMode: 1
- m_AdditionalLightsPerObjectLimit: 8
+ m_AdditionalLightsPerObjectLimit: 2
m_AdditionalLightShadowsSupported: 1
m_AdditionalLightsShadowmapResolution: 8192
m_AdditionalLightsShadowResolutionTierLow: 256