Adding Tesla Coil Tower and Arc VFX
New tower!
This commit is contained in:
parent
7b93137216
commit
699ea34268
20 changed files with 1317 additions and 2 deletions
118
Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
Normal file
118
Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Assets/_Project/Scripts/Combat/TeslaArcVisual.cs
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TD.Combat
|
||||
{
|
||||
/// <summary>
|
||||
/// Local-only electrical-arc visual for <see cref="TD.Core.TargetType.AllInRange"/>
|
||||
/// towers (Tesla Coil). Subscribes to <see cref="TowerCombat.OnAreaFired"/> and draws a
|
||||
/// jagged line from the tower's emitter point to every enemy hit, flashed for a moment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Pure visualization — runs on every peer from the replicated fire broadcast; nothing
|
||||
/// here is networked. Arcs are pooled <see cref="LineRenderer"/>s reused across ticks.
|
||||
/// </remarks>
|
||||
[RequireComponent(typeof(TowerCombat))]
|
||||
public class TeslaArcVisual : MonoBehaviour
|
||||
{
|
||||
[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 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;
|
||||
|
||||
[SerializeField] private Color arcColor = new Color(0.6f, 0.85f, 1f, 1f);
|
||||
[SerializeField] private float arcWidth = 0.06f;
|
||||
[Tooltip("How long each arc flash stays visible, in seconds.")]
|
||||
[SerializeField] private float arcDuration = 0.12f;
|
||||
[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<LineRenderer> pool = new List<LineRenderer>();
|
||||
private float hideAt = -1f;
|
||||
|
||||
private void Awake() => combat = GetComponent<TowerCombat>();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (combat != null) combat.OnAreaFired += HandleAreaFired;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (combat != null) combat.OnAreaFired -= HandleAreaFired;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (hideAt >= 0f && Time.time >= hideAt)
|
||||
{
|
||||
for (int i = 0; i < pool.Count; i++) pool[i].enabled = false;
|
||||
hideAt = -1f;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAreaFired(Vector3[] positions)
|
||||
{
|
||||
if (positions == null) return;
|
||||
|
||||
Vector3 origin = emitter != null ? emitter.position : transform.position + Vector3.up;
|
||||
|
||||
for (int i = 0; i < positions.Length; i++)
|
||||
{
|
||||
var lr = GetLine(i);
|
||||
DrawArc(lr, origin, positions[i]);
|
||||
lr.enabled = true;
|
||||
}
|
||||
|
||||
// Disable any leftover lines from a previous, larger tick.
|
||||
for (int i = positions.Length; i < pool.Count; i++)
|
||||
pool[i].enabled = false;
|
||||
|
||||
hideAt = Time.time + arcDuration;
|
||||
}
|
||||
|
||||
private LineRenderer GetLine(int index)
|
||||
{
|
||||
while (pool.Count <= index)
|
||||
{
|
||||
var go = new GameObject($"Arc_{pool.Count}");
|
||||
go.transform.SetParent(transform, worldPositionStays: false);
|
||||
var lr = go.AddComponent<LineRenderer>();
|
||||
lr.useWorldSpace = true;
|
||||
lr.widthMultiplier = arcWidth;
|
||||
lr.numCapVertices = 2;
|
||||
lr.textureMode = LineTextureMode.Stretch;
|
||||
lr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
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];
|
||||
}
|
||||
|
||||
private void DrawArc(LineRenderer lr, Vector3 a, Vector3 b)
|
||||
{
|
||||
int n = Mathf.Max(2, segmentsPerArc);
|
||||
lr.positionCount = n;
|
||||
for (int s = 0; s < n; s++)
|
||||
{
|
||||
float t = s / (float)(n - 1);
|
||||
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 += Random.insideUnitSphere * jitter;
|
||||
lr.SetPosition(s, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue