MiniGames/Assets/Scripts/ChaseOn/ChaseLaserBeam.cs

266 lines
8.1 KiB
C#
Raw Normal View History

2025-09-11 18:46:20 +05:00
using System.Collections;
using UnityEngine;
2025-08-19 16:59:43 +05:00
[RequireComponent(typeof(LineRenderer))]
public class ChaseLaserBeam : MonoBehaviour
{
[Header("Laser Setup")]
public Transform laserOrigin;
public float maxDistance = 20f;
public LayerMask collisionMask;
public Color laserColor = Color.red;
public float laserWidth = 0.05f;
[Header("Visuals")]
public float scrollSpeed = 1f;
public float emissionStrength = 5f;
[Header("Performance")]
public float updateRate = 0.02f;
2025-09-11 18:46:20 +05:00
[Header("Pulse (On/Off)")]
public bool pulsing = true;
public bool startOn = true;
public float onDuration = 1.5f; // fully-on time (excludes fade)
public float offDuration = 1.5f; // fully-off time (excludes fade)
public float fadeIn = 0.15f; // 0 = snap on
public float fadeOut = 0.15f; // 0 = snap off
public float startDelay = 0f;
public float randomStartOffset = 0f; // +/- random seconds added to startDelay
[Header("Lethality")]
[Tooltip("Beam only damages when intensity >= this (lets you show a non-lethal warmup).")]
[Range(0f, 1f)] public float lethalThreshold = 0.9f;
2025-08-19 16:59:43 +05:00
private LineRenderer line;
private Vector3 laserStart, laserEnd;
2025-09-11 18:46:20 +05:00
private Material matInstance;
private float currentIntensity = 0f; // 0..1 (drives emission/visibility)
private bool isActiveVisual = false; // visible & updating
private bool isEnabled = false; // component enabled
private Coroutine pulseCo;
2025-08-19 16:59:43 +05:00
void Awake()
{
line = GetComponent<LineRenderer>();
SetupLaserRenderer();
}
void OnEnable()
{
2025-09-11 18:46:20 +05:00
isEnabled = true;
2025-08-19 16:59:43 +05:00
line.enabled = true;
InvokeRepeating(nameof(UpdateLaser), 0f, updateRate);
2025-09-11 18:46:20 +05:00
if (pulsing)
{
pulseCo = StartCoroutine(PulseRoutine());
}
else
{
// Non-pulsing: just force ON
currentIntensity = 1f;
isActiveVisual = true;
ApplyIntensity(currentIntensity);
}
2025-08-19 16:59:43 +05:00
}
void OnDisable()
{
2025-09-11 18:46:20 +05:00
isEnabled = false;
2025-08-19 16:59:43 +05:00
CancelInvoke(nameof(UpdateLaser));
2025-09-11 18:46:20 +05:00
if (pulseCo != null) StopCoroutine(pulseCo);
if (line != null) line.enabled = false;
2025-08-19 16:59:43 +05:00
}
void UpdateLaser()
{
2025-09-11 18:46:20 +05:00
if (!isActiveVisual || currentIntensity <= 0.001f)
{
// Off: keep line hidden, skip raycast
if (line.enabled) line.enabled = false;
return;
}
2025-08-19 16:59:43 +05:00
laserStart = laserOrigin ? laserOrigin.position : transform.position;
Vector3 direction = transform.forward;
if (Physics.Raycast(laserStart, direction, out RaycastHit hit, maxDistance, collisionMask))
{
laserEnd = hit.point;
2025-09-11 18:46:20 +05:00
// Damage only when sufficiently "on"
if (currentIntensity >= lethalThreshold && hit.collider.CompareTag("Player"))
2025-08-19 16:59:43 +05:00
{
2025-09-11 18:46:20 +05:00
var player = hit.collider.GetComponent<ChasePlayerController>();
2025-08-19 16:59:43 +05:00
if (player != null && !player.waitingForGameOver)
{
2025-09-11 18:46:20 +05:00
Debug.Log("⚠️ Player hit by chase laser!");
2025-08-19 16:59:43 +05:00
player.moveSpeed = 0;
player.waitingForGameOver = true;
player.StartCoroutine(player.PlayStateAndGameOver(player.fallingStateName, player.fallingShortHash));
}
}
}
else
{
laserEnd = laserStart + direction * maxDistance;
}
2025-09-11 18:46:20 +05:00
// Draw
if (!line.enabled) line.enabled = true;
2025-08-19 16:59:43 +05:00
line.SetPosition(0, laserStart);
line.SetPosition(1, laserEnd);
}
void SetupLaserRenderer()
{
line.useWorldSpace = true;
line.positionCount = 2;
line.loop = false;
line.widthMultiplier = laserWidth;
line.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
line.receiveShadows = false;
2025-09-11 18:46:20 +05:00
// Unique material instance
2025-08-19 16:59:43 +05:00
Shader laserShader = Shader.Find("Custom/EmissiveLaser");
if (laserShader != null)
{
2025-09-11 18:46:20 +05:00
matInstance = new Material(laserShader);
matInstance.SetColor("_Color", laserColor);
matInstance.SetFloat("_Emission", 0f);
matInstance.SetFloat("_ScrollSpeed", scrollSpeed);
line.material = matInstance;
2025-08-19 16:59:43 +05:00
}
else
{
2025-09-11 18:46:20 +05:00
matInstance = new Material(Shader.Find("Sprites/Default"));
matInstance.color = laserColor * 0f; // start off
line.material = matInstance;
2025-08-19 16:59:43 +05:00
}
line.startColor = laserColor;
line.endColor = laserColor;
}
2025-09-11 18:46:20 +05:00
// ===== Pulse logic =====
IEnumerator PulseRoutine()
{
float jitter = (randomStartOffset > 0f) ? Random.Range(-randomStartOffset, randomStartOffset) : 0f;
if (startDelay + jitter > 0f) yield return new WaitForSeconds(startDelay + jitter);
bool stateOn = startOn;
while (isEnabled)
{
if (stateOn)
{
// Fade in
if (fadeIn > 0f) yield return FadeIntensity(1f, fadeIn);
else { currentIntensity = 1f; ApplyIntensity(currentIntensity); }
isActiveVisual = true; // visible & updating
if (onDuration > 0f) yield return new WaitForSeconds(onDuration);
}
else
{
// Fade out
if (fadeOut > 0f) yield return FadeIntensity(0f, fadeOut);
else { currentIntensity = 0f; ApplyIntensity(currentIntensity); }
isActiveVisual = false; // fully off
if (offDuration > 0f) yield return new WaitForSeconds(offDuration);
}
stateOn = !stateOn;
}
}
IEnumerator FadeIntensity(float target, float time)
{
float start = currentIntensity;
float t = 0f;
// Ensure visuals are considered active during fade (so you can show warning beam)
isActiveVisual = (target > 0f) || (start > 0f);
while (t < 1f)
{
t += Time.deltaTime / Mathf.Max(0.0001f, time);
currentIntensity = Mathf.Lerp(start, target, t);
ApplyIntensity(currentIntensity);
yield return null;
}
currentIntensity = target;
ApplyIntensity(currentIntensity);
// If ended at zero, hide line
if (currentIntensity <= 0.001f && line.enabled) line.enabled = false;
}
void ApplyIntensity(float normalized)
{
// Width & color scaling (optional: keep width fixed)
line.widthMultiplier = Mathf.Max(0.0001f, laserWidth * Mathf.Lerp(0.35f, 1f, normalized));
if (matInstance != null)
{
if (matInstance.HasProperty("_Emission"))
{
matInstance.SetFloat("_Emission", emissionStrength * normalized);
// If your shader uses HDR color for emission, you can also set _Color here if needed.
}
else
{
// Fallback: scale color alpha
Color c = laserColor;
c.a = Mathf.Clamp01(normalized);
matInstance.color = c;
}
}
}
// ===== Public controls =====
public void SetPulsing(bool enabled)
{
pulsing = enabled;
if (!isEnabled) return;
if (pulseCo != null) { StopCoroutine(pulseCo); pulseCo = null; }
if (pulsing)
{
pulseCo = StartCoroutine(PulseRoutine());
}
else
{
currentIntensity = 1f;
ApplyIntensity(currentIntensity);
isActiveVisual = true;
}
}
public void ForceOff()
{
if (pulseCo != null) { StopCoroutine(pulseCo); pulseCo = null; }
pulsing = false;
currentIntensity = 0f;
ApplyIntensity(0f);
isActiveVisual = false;
if (line) line.enabled = false;
}
public void ForceOn()
{
if (pulseCo != null) { StopCoroutine(pulseCo); pulseCo = null; }
pulsing = false;
currentIntensity = 1f;
ApplyIntensity(1f);
isActiveVisual = true;
if (line && !line.enabled) line.enabled = true;
}
2025-08-19 16:59:43 +05:00
}