Update LaserBeam.cs

This commit is contained in:
Hazim Bin Ijaz 2025-09-13 02:22:13 +05:00
parent f3d30841e3
commit a681beec0e

View File

@ -4,15 +4,11 @@ using System.Collections;
[RequireComponent(typeof(LineRenderer))] [RequireComponent(typeof(LineRenderer))]
public class LaserBeam : MonoBehaviour public class LaserBeam : MonoBehaviour
{ {
[Header("Control")]
[Tooltip("If true, this beam will NOT run its own timers or intro; it only responds to the controller.")]
public bool externalControl = true;
[Header("Laser Settings")] [Header("Laser Settings")]
public float maxDistance = 20f; public float maxDistance = 20f;
public LayerMask collisionMask = ~0; public LayerMask collisionMask = ~0;
public float chargeDuration = 3f; // used only if externalControl == false public float chargeDuration = 3f;
public float fireDuration = 1f; // used only if externalControl == false public float fireDuration = 1f;
[Header("Laser Appearance")] [Header("Laser Appearance")]
public Color laserColor = Color.red; public Color laserColor = Color.red;
@ -26,7 +22,7 @@ public class LaserBeam : MonoBehaviour
public float hitRadius = 0.1f; public float hitRadius = 0.1f;
public QueryTriggerInteraction queryTriggerMode = QueryTriggerInteraction.Collide; public QueryTriggerInteraction queryTriggerMode = QueryTriggerInteraction.Collide;
[Header("Intro Show (ignored if externalControl)")] [Header("Intro Show")]
public bool showIntro = true; public bool showIntro = true;
public float initialShowDuration = 3f; public float initialShowDuration = 3f;
public bool introIsDeadly = true; public bool introIsDeadly = true;
@ -35,8 +31,8 @@ public class LaserBeam : MonoBehaviour
public bool deflectFromBoxSides = true; public bool deflectFromBoxSides = true;
public string boxTag = "Box"; public string boxTag = "Box";
public float outDistance = 12f; public float outDistance = 12f;
public float sideExitPush = 0.02f; public float sideExitPush = 0.02f; // will be lifted to >= hitRadius + epsilon at runtime
public float entryPush = 0.005f; public float entryPush = 0.005f; // will be lifted to >= 0.25*hitRadius at runtime
[Header("Debug")] [Header("Debug")]
public bool debugDraw = false; public bool debugDraw = false;
@ -60,33 +56,22 @@ public class LaserBeam : MonoBehaviour
private Collider _lastBox; private Collider _lastBox;
private int _sideSign = 1; private int _sideSign = 1;
// External control hook (set by controller if used)
public bool externalControl = true;
void Awake() void Awake()
{ {
SetupLaserRenderer(); SetupLaserRenderer();
// Always start safe
currentPhase = LaserPhase.Idle;
hasTriggeredDeathThisBurst = false;
DisableLaser();
StopAllCoroutines();
} }
void Start() void Start()
{ {
// Only self-run if not externally controlled if (showIntro)
if (!externalControl && showIntro)
StartCoroutine(IntroShow()); StartCoroutine(IntroShow());
} }
void Update() void Update()
{ {
if (externalControl)
{
// Passive: only draw debug line if visible
if (debugDraw) Debug.DrawLine(laserStart, laserEnd, Color.cyan);
return;
}
// Legacy self-FSM (optional use)
if (introRunning) return; if (introRunning) return;
timer += Time.deltaTime; timer += Time.deltaTime;
@ -131,18 +116,19 @@ public class LaserBeam : MonoBehaviour
Debug.DrawLine(laserStart, laserEnd, Color.cyan); Debug.DrawLine(laserStart, laserEnd, Color.cyan);
} }
// LaserBeam.cs — replace SetLaserPhase with this version
public void SetLaserPhase(LaserPhase phase) public void SetLaserPhase(LaserPhase phase)
{ {
// When controller is driving, cancel any self-cycling
if (externalControl) if (externalControl)
{ {
StopAllCoroutines(); StopAllCoroutines();
introRunning = false; introRunning = false;
} }
if (!line) SetupLaserRenderer(); if (!line) SetupLaserRenderer();
// Always clear when entering lethal/lead-in phases // Clear 1-kill gate whenever we enter lead-in or lethal phases
if (phase == LaserPhase.Firing || phase == LaserPhase.Charging) if (phase == LaserPhase.Charging || phase == LaserPhase.Firing)
hasTriggeredDeathThisBurst = false; hasTriggeredDeathThisBurst = false;
currentPhase = phase; currentPhase = phase;
@ -163,7 +149,7 @@ public class LaserBeam : MonoBehaviour
UpdateLaserPath(); UpdateLaserPath();
line.enabled = true; line.enabled = true;
SetLineColor(laserColor); SetLineColor(laserColor);
CheckHit(); CheckHit(); // immediate check on enter
break; break;
} }
} }
@ -209,7 +195,7 @@ public class LaserBeam : MonoBehaviour
void DisableLaser() void DisableLaser()
{ {
line.enabled = false; line.enabled = false;
// Also clear endpoint for safety/debug // Optional: zero endpoints for clarity in debug
laserStart = transform.position; laserStart = transform.position;
laserEnd = laserStart; laserEnd = laserStart;
} }
@ -223,16 +209,12 @@ public class LaserBeam : MonoBehaviour
void CheckHit() void CheckHit()
{ {
// HARD GATES: never kill unless were allowed to // only lethal during Firing, or during Intro if flagged as deadly
if (!isActiveAndEnabled) return;
if (!gameObject.activeInHierarchy) return;
bool lethalNow = (currentPhase == LaserPhase.Firing) || (introRunning && introIsDeadly); bool lethalNow = (currentPhase == LaserPhase.Firing) || (introRunning && introIsDeadly);
if (!lethalNow) return; if (!lethalNow || hasTriggeredDeathThisBurst) return;
if (hasTriggeredDeathThisBurst) return; // local helper that can ignore a specific collider (e.g., the deflection box)
bool CheckSegment(Vector3 a, Vector3 b, Collider ignoreCol = null)
bool CheckSegment(Vector3 a, Vector3 b)
{ {
Vector3 d = b - a; Vector3 d = b - a;
float len = d.magnitude; float len = d.magnitude;
@ -247,12 +229,15 @@ public class LaserBeam : MonoBehaviour
Collider bestCol = null; Collider bestCol = null;
foreach (var h in hits) foreach (var h in hits)
{ {
if (h.collider && h.collider.GetComponentInParent<LaserBeam>() == this) continue; if (!h.collider) continue;
if (ignoreCol && h.collider == ignoreCol) continue; // NEW: ignore the deflection box
if (h.collider.GetComponentInParent<LaserBeam>() == this) continue;
if (h.distance < best) { best = h.distance; bestT = h.collider.transform; bestCol = h.collider; } if (h.distance < best) { best = h.distance; bestT = h.collider.transform; bestCol = h.collider; }
} }
if (!bestT) return false; if (!bestT) return false;
// Player?
if (bestT.CompareTag(playerTag) || (bestT.root && bestT.root.CompareTag(playerTag))) if (bestT.CompareTag(playerTag) || (bestT.root && bestT.root.CompareTag(playerTag)))
{ {
hasTriggeredDeathThisBurst = true; hasTriggeredDeathThisBurst = true;
@ -260,6 +245,7 @@ public class LaserBeam : MonoBehaviour
return true; return true;
} }
// Box? (still allow box damage feedback)
if (bestCol && bestCol.CompareTag(boxTag)) if (bestCol && bestCol.CompareTag(boxTag))
{ {
var boxHealth = bestCol.GetComponent<LaserBoxHealth>(); var boxHealth = bestCol.GetComponent<LaserBoxHealth>();
@ -270,11 +256,12 @@ public class LaserBeam : MonoBehaviour
return false; return false;
} }
// segmented checks if were deflecting
if (_routeViaSide) if (_routeViaSide)
{ {
if (CheckSegment(laserStart, _entryPoint)) return; if (CheckSegment(laserStart, _entryPoint)) return;
if (CheckSegment(_entryPoint, _midPoint)) return; if (CheckSegment(_entryPoint, _midPoint, _lastBox)) return; // ignore the box while exiting
CheckSegment(_midPoint, laserEnd); CheckSegment(_midPoint, laserEnd, _lastBox); // ignore it on the last leg too
} }
else else
{ {
@ -316,6 +303,7 @@ public class LaserBeam : MonoBehaviour
line.SetPosition(0, laserStart); line.SetPosition(0, laserStart);
line.SetPosition(1, laserEnd); line.SetPosition(1, laserEnd);
// No deflect?
if (!deflectFromBoxSides || !gotHit || !bestHit.collider.CompareTag(boxTag)) return; if (!deflectFromBoxSides || !gotHit || !bestHit.collider.CompareTag(boxTag)) return;
var box = bestHit.collider.GetComponent<BoxCollider>(); var box = bestHit.collider.GetComponent<BoxCollider>();
@ -328,21 +316,40 @@ public class LaserBeam : MonoBehaviour
} }
Transform t = box.transform; Transform t = box.transform;
_entryPoint = bestHit.point + bestHit.normal * entryPush;
// ensure we dont start the entry segment inside the box
float safeEntry = Mathf.Max(entryPush, hitRadius * 0.25f);
_entryPoint = bestHit.point + bestHit.normal * safeEntry;
// compute the midpoint on the box side were exiting from
Vector3 centerW = t.TransformPoint(box.center); Vector3 centerW = t.TransformPoint(box.center);
Vector3 half = Vector3.Scale(box.size * 0.5f, t.lossyScale); Vector3 half = Vector3.Scale(box.size * 0.5f, t.lossyScale);
Vector3 rightW = t.right.normalized; Vector3 rightW = t.right.normalized;
Vector3 outDir = rightW * _sideSign; Vector3 outDir = rightW * _sideSign;
_midPoint = centerW + rightW * (_sideSign * half.x); _midPoint = centerW + rightW * (_sideSign * half.x);
// how much distance remains for leg 2
float traveled = bestHit.distance + Vector3.Distance(bestHit.point, _midPoint); float traveled = bestHit.distance + Vector3.Distance(bestHit.point, _midPoint);
float remain = Mathf.Max(0f, maxDistance - traveled); float remain = Mathf.Max(0f, maxDistance - traveled);
float leg = Mathf.Min(outDistance, remain); float leg = Mathf.Min(outDistance, remain);
Vector3 secondStart = _midPoint + outDir * sideExitPush; // Choose a second start that is definitely OUTSIDE the box surface
float minExit = Mathf.Max(sideExitPush, radius + 0.02f);
Vector3 secondStart = _midPoint + outDir * minExit;
// If somehow still overlapping the box bounds, nudge out a bit more (guarded)
for (int i = 0; i < 3; i++)
{
// AABBs are conservative; this is cheap and “good enough”
if (box.bounds.Contains(secondStart))
secondStart += outDir * (radius + 0.02f);
else
break;
}
Vector3 secondEnd = secondStart + outDir * leg; Vector3 secondEnd = secondStart + outDir * leg;
// Trim second leg if it hits something early
if (Physics.SphereCast(secondStart, radius, outDir, out var h2, leg, collisionMask, queryTriggerMode)) if (Physics.SphereCast(secondStart, radius, outDir, out var h2, leg, collisionMask, queryTriggerMode))
{ {
if (!(h2.collider && h2.collider.GetComponentInParent<LaserBeam>() == this)) if (!(h2.collider && h2.collider.GetComponentInParent<LaserBeam>() == this))