using System.Collections; using UnityEngine; using UnityEngine.Rendering; namespace VRBeats { public class SliceTrailEffect : MonoBehaviour { private const float Lifetime = 0.24f; private const int PointCount = 7; private LineRenderer glowLine = null; private LineRenderer coreLine = null; private Vector3 center = Vector3.zero; private Vector3 tangent = Vector3.right; private Vector3 lift = Vector3.up; private Color effectColor = Color.cyan; public static void Spawn(Vector3 position, Vector3 hitDir, Vector3 saberUp, Color color) { GameObject effectObject = new GameObject("SliceTrailEffect"); SliceTrailEffect effect = effectObject.AddComponent(); effect.Construct(position, hitDir, saberUp, color); } private void Construct(Vector3 position, Vector3 hitDir, Vector3 saberUp, Color color) { center = position; transform.position = position; effectColor = NormalizeColor(color); tangent = saberUp.sqrMagnitude > 0.001f ? saberUp.normalized : Vector3.right; lift = hitDir.sqrMagnitude > 0.001f ? hitDir.normalized : Vector3.up; glowLine = CreateLine("Glow", 0.16f, 0.45f); coreLine = CreateLine("Core", 0.045f, 0.95f); StartCoroutine(Animate()); } private LineRenderer CreateLine(string name, float width, float alpha) { GameObject lineObject = new GameObject(name); lineObject.transform.SetParent(transform, false); LineRenderer line = lineObject.AddComponent(); line.positionCount = PointCount; line.useWorldSpace = true; line.alignment = LineAlignment.View; line.textureMode = LineTextureMode.Stretch; line.numCornerVertices = 8; line.numCapVertices = 8; line.shadowCastingMode = ShadowCastingMode.Off; line.receiveShadows = false; line.material = CreateMaterial(); line.widthMultiplier = width; ApplyGradient(line, alpha); return line; } private IEnumerator Animate() { float age = 0.0f; while (age < Lifetime) { float t = age / Lifetime; float length = Mathf.Lerp(0.72f, 1.45f, t); float bend = Mathf.Lerp(0.12f, 0.34f, t); float alpha = 1.0f - t; UpdateLine(glowLine, length, bend, alpha * 0.45f); UpdateLine(coreLine, length * 0.88f, bend * 0.55f, alpha * 0.95f); age += Time.deltaTime; yield return null; } Destroy(gameObject); } private void UpdateLine(LineRenderer line, float length, float bend, float alpha) { if (line == null) return; for (int i = 0; i < PointCount; i++) { float normalized = PointCount <= 1 ? 0.0f : (float)i / (PointCount - 1); float offset = normalized - 0.5f; float curve = Mathf.Sin(normalized * Mathf.PI) * bend; line.SetPosition(i, center + tangent * (offset * length) + lift * curve); } ApplyGradient(line, alpha); } private static Material CreateMaterial() { Shader shader = Shader.Find("Sprites/Default"); if (shader == null) shader = Shader.Find("Unlit/Transparent"); Material material = new Material(shader); material.name = "Runtime Slice Trail"; return material; } private void ApplyGradient(LineRenderer line, float alpha) { Color start = new Color(effectColor.r, effectColor.g, effectColor.b, 0.0f); Color mid = new Color(effectColor.r, effectColor.g, effectColor.b, alpha); Color end = new Color(effectColor.r, effectColor.g, effectColor.b, 0.0f); Gradient gradient = new Gradient(); gradient.SetKeys( new[] { new GradientColorKey(start, 0.0f), new GradientColorKey(mid, 0.5f), new GradientColorKey(end, 1.0f), }, new[] { new GradientAlphaKey(0.0f, 0.0f), new GradientAlphaKey(alpha, 0.5f), new GradientAlphaKey(0.0f, 1.0f), }); line.colorGradient = gradient; } private static Color NormalizeColor(Color color) { float max = Mathf.Max(color.r, Mathf.Max(color.g, color.b)); if (max > 1.0f) color /= max; color.a = 1.0f; return color; } } }