260 lines
7.8 KiB
C#
260 lines
7.8 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
|
||
[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;
|
||
|
||
[Header("Pulse (On/Off)")]
|
||
public bool pulsing = true;
|
||
public bool startOn = true;
|
||
public float onDuration = 1.5f;
|
||
public float offDuration = 1.5f;
|
||
public float fadeIn = 0.15f;
|
||
public float fadeOut = 0.15f;
|
||
public float startDelay = 0f;
|
||
public float randomStartOffset = 0f;
|
||
|
||
[Header("Lethality")]
|
||
[Range(0f, 1f)] public float lethalThreshold = 0.9f;
|
||
|
||
private LineRenderer line;
|
||
private Vector3 laserStart, laserEnd;
|
||
private Material matInstance;
|
||
|
||
private float currentIntensity = 0f;
|
||
private bool isActiveVisual = false;
|
||
private bool isEnabled = false;
|
||
private Coroutine pulseCo;
|
||
|
||
void Awake()
|
||
{
|
||
line = GetComponent<LineRenderer>();
|
||
SetupLaserRenderer();
|
||
}
|
||
|
||
void OnEnable()
|
||
{
|
||
isEnabled = true;
|
||
line.enabled = true;
|
||
InvokeRepeating(nameof(UpdateLaser), 0f, updateRate);
|
||
|
||
if (pulsing) pulseCo = StartCoroutine(PulseRoutine());
|
||
else
|
||
{
|
||
currentIntensity = 1f;
|
||
isActiveVisual = true;
|
||
ApplyIntensity(currentIntensity);
|
||
}
|
||
}
|
||
|
||
void OnDisable()
|
||
{
|
||
isEnabled = false;
|
||
CancelInvoke(nameof(UpdateLaser));
|
||
if (pulseCo != null) StopCoroutine(pulseCo);
|
||
if (line != null) line.enabled = false;
|
||
}
|
||
|
||
void UpdateLaser()
|
||
{
|
||
if (!isActiveVisual || currentIntensity <= 0.001f)
|
||
{
|
||
if (line.enabled) line.enabled = false;
|
||
return;
|
||
}
|
||
|
||
laserStart = laserOrigin ? laserOrigin.position : transform.position;
|
||
Vector3 direction = transform.forward;
|
||
|
||
if (Physics.Raycast(laserStart, direction, out RaycastHit hit, maxDistance, collisionMask))
|
||
{
|
||
laserEnd = hit.point;
|
||
|
||
if (/*currentIntensity >= lethalThreshold && */hit.collider.CompareTag("Player"))
|
||
{
|
||
// Use Shared_DieZibu for laser kill
|
||
var die = hit.collider.GetComponent<Shared_DieZibu>() ?? hit.collider.GetComponentInParent<Shared_DieZibu>();
|
||
if (die != null)
|
||
{
|
||
// optional: stop the runner’s local movement flags if present
|
||
var runner = die.GetComponent<ChasePlayerController>();
|
||
if (runner != null)
|
||
{
|
||
runner.StartCoroutine(runner.PlayStateAndGameOver(runner.fallingStateName, runner.fallingShortHash));
|
||
}
|
||
die.KillByLaser();
|
||
|
||
}
|
||
else
|
||
{
|
||
// Fallback: if no Shared_DieZibu found, keep old behavior (optional)
|
||
var runner = hit.collider.GetComponent<ChasePlayerController>() ?? hit.collider.GetComponentInParent<ChasePlayerController>();
|
||
if (runner != null /*&& !runner.waitingForGameOver*/)
|
||
{
|
||
runner.moveSpeed = 0;
|
||
runner.waitingForGameOver = true;
|
||
runner.StartCoroutine(runner.PlayStateAndGameOver(runner.fallingStateName, runner.fallingShortHash));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
laserEnd = laserStart + direction * maxDistance;
|
||
}
|
||
|
||
if (!line.enabled) line.enabled = true;
|
||
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;
|
||
|
||
Shader laserShader = Shader.Find("Custom/EmissiveLaser");
|
||
if (laserShader != null)
|
||
{
|
||
matInstance = new Material(laserShader);
|
||
matInstance.SetColor("_Color", laserColor);
|
||
matInstance.SetFloat("_Emission", 0f);
|
||
matInstance.SetFloat("_ScrollSpeed", scrollSpeed);
|
||
line.material = matInstance;
|
||
}
|
||
else
|
||
{
|
||
matInstance = new Material(Shader.Find("Sprites/Default"));
|
||
matInstance.color = laserColor * 0f;
|
||
line.material = matInstance;
|
||
}
|
||
|
||
line.startColor = laserColor;
|
||
line.endColor = laserColor;
|
||
}
|
||
|
||
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)
|
||
{
|
||
if (fadeIn > 0f) yield return FadeIntensity(1f, fadeIn);
|
||
else { currentIntensity = 1f; ApplyIntensity(currentIntensity); }
|
||
|
||
isActiveVisual = true;
|
||
if (onDuration > 0f) yield return new WaitForSeconds(onDuration);
|
||
}
|
||
else
|
||
{
|
||
if (fadeOut > 0f) yield return FadeIntensity(0f, fadeOut);
|
||
else { currentIntensity = 0f; ApplyIntensity(currentIntensity); }
|
||
|
||
isActiveVisual = false;
|
||
if (offDuration > 0f) yield return new WaitForSeconds(offDuration);
|
||
}
|
||
|
||
stateOn = !stateOn;
|
||
}
|
||
}
|
||
|
||
IEnumerator FadeIntensity(float target, float time)
|
||
{
|
||
float start = currentIntensity;
|
||
float t = 0f;
|
||
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 (currentIntensity <= 0.001f && line.enabled) line.enabled = false;
|
||
}
|
||
|
||
void ApplyIntensity(float normalized)
|
||
{
|
||
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);
|
||
}
|
||
else
|
||
{
|
||
Color c = laserColor;
|
||
c.a = Mathf.Clamp01(normalized);
|
||
matInstance.color = c;
|
||
}
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|