Periodic enabling of laser
This commit is contained in:
parent
700f11bc94
commit
66462ce70d
105
Assets/ChaseLaserBeam.cs
Normal file
105
Assets/ChaseLaserBeam.cs
Normal file
@ -0,0 +1,105 @@
|
||||
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;
|
||||
|
||||
private LineRenderer line;
|
||||
private Vector3 laserStart, laserEnd;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
line = GetComponent<LineRenderer>();
|
||||
SetupLaserRenderer();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
line.enabled = true;
|
||||
InvokeRepeating(nameof(UpdateLaser), 0f, updateRate);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
CancelInvoke(nameof(UpdateLaser));
|
||||
if (line != null)
|
||||
line.enabled = false;
|
||||
}
|
||||
|
||||
void UpdateLaser()
|
||||
{
|
||||
laserStart = laserOrigin ? laserOrigin.position : transform.position;
|
||||
Vector3 direction = transform.forward;
|
||||
|
||||
if (Physics.Raycast(laserStart, direction, out RaycastHit hit, maxDistance, collisionMask))
|
||||
{
|
||||
laserEnd = hit.point;
|
||||
|
||||
if (hit.collider.CompareTag("Player"))
|
||||
{
|
||||
Debug.Log("⚠️ Player hit by chase laser!");
|
||||
|
||||
ChasePlayerController player = hit.collider.GetComponent<ChasePlayerController>();
|
||||
if (player != null && !player.waitingForGameOver)
|
||||
{
|
||||
player.moveSpeed = 0;
|
||||
player.waitingForGameOver = true;
|
||||
player.StartCoroutine(player.PlayStateAndGameOver(player.fallingStateName, player.fallingShortHash));
|
||||
}
|
||||
// TODO: Trigger player damage or effects
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
laserEnd = laserStart + direction * maxDistance;
|
||||
}
|
||||
|
||||
line.enabled = true; // Force enabled in case something disables it
|
||||
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;
|
||||
|
||||
// Try using custom emissive shader
|
||||
Shader laserShader = Shader.Find("Custom/EmissiveLaser");
|
||||
if (laserShader != null)
|
||||
{
|
||||
Material laserMat = new Material(laserShader);
|
||||
laserMat.SetColor("_Color", laserColor);
|
||||
laserMat.SetFloat("_Emission", emissionStrength);
|
||||
laserMat.SetFloat("_ScrollSpeed", scrollSpeed);
|
||||
line.material = laserMat;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback shader
|
||||
Material fallback = new Material(Shader.Find("Sprites/Default"));
|
||||
fallback.color = laserColor;
|
||||
line.material = fallback;
|
||||
}
|
||||
|
||||
line.startColor = laserColor;
|
||||
line.endColor = laserColor;
|
||||
}
|
||||
}
|
11
Assets/ChaseLaserBeam.cs.meta
Normal file
11
Assets/ChaseLaserBeam.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a334db153d189a48b221ea963f66011
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -11,24 +11,28 @@ public class LaserBeam : MonoBehaviour
|
||||
|
||||
[Header("Laser Appearance")]
|
||||
public Color laserColor = Color.red;
|
||||
public Color warningColor = new Color(1f, 0.5f, 0f); // Orange
|
||||
public Color warningColor = new Color(1f, 0.5f, 0f);
|
||||
public float laserWidth = 0.05f;
|
||||
public float emissionStrength = 5f;
|
||||
public float scrollSpeed = 1f;
|
||||
|
||||
[Header("Player Hit")]
|
||||
public string playerTag = "Player";
|
||||
[Tooltip("Approximate beam thickness for hit tests.")]
|
||||
public float hitRadius = 0.1f;
|
||||
[Tooltip("Should raycasts consider trigger colliders? (Player often uses triggers)")]
|
||||
public QueryTriggerInteraction queryTriggerMode = QueryTriggerInteraction.Collide;
|
||||
|
||||
[Header("Intro Show")]
|
||||
public bool showIntro = true;
|
||||
public float initialShowDuration = 3f;
|
||||
[Tooltip("If true, the intro beam can kill the player too.")]
|
||||
public bool introIsDeadly = true;
|
||||
|
||||
[Header("Deflection (Box side center)")]
|
||||
public bool deflectFromBoxSides = true;
|
||||
public string boxTag = "Box";
|
||||
public float outDistance = 12f;
|
||||
public float sideExitPush = 0.02f;
|
||||
public float entryPush = 0.005f;
|
||||
|
||||
[Header("Debug")]
|
||||
public bool debugDraw = false;
|
||||
|
||||
@ -36,6 +40,9 @@ public class LaserBeam : MonoBehaviour
|
||||
private float timer = 0f;
|
||||
|
||||
private enum LaserState { Idle, Charging, Firing }
|
||||
public enum LaserPhase { Idle, Charging, Firing }
|
||||
|
||||
private LaserPhase currentPhase = LaserPhase.Idle;
|
||||
private LaserState currentState = LaserState.Idle;
|
||||
|
||||
private Vector3 laserStart;
|
||||
@ -44,44 +51,15 @@ public class LaserBeam : MonoBehaviour
|
||||
private bool introRunning = false;
|
||||
private bool hasTriggeredDeathThisBurst = false;
|
||||
|
||||
// cache root to ignore self-hits
|
||||
Transform _selfRoot;
|
||||
[Header("Deflection")]
|
||||
public bool enableDeflection = true;
|
||||
public string deflectTag = "Box";
|
||||
[Tooltip("How far the beam travels after deflection.")]
|
||||
public float deflectDistance = 10f;
|
||||
[Tooltip("Push along the deflected direction to avoid re-hitting the same face.")]
|
||||
public float deflectEdgePush = 0.02f;
|
||||
|
||||
// runtime cache so the left/right choice doesn't flicker
|
||||
Collider _currentDeflectCol;
|
||||
int _currentDeflectSign = 1; // +1 = right, -1 = left
|
||||
bool _isDeflecting;
|
||||
Vector3 _bouncePoint;
|
||||
Vector3 _bounceEnd;
|
||||
[Header("Deflection (Box side center)")]
|
||||
[Tooltip("Tiny push so the second segment isn't inside the face.")]
|
||||
|
||||
// runtime
|
||||
bool _segmented;
|
||||
[Header("Deflection (Box side center)")]
|
||||
public bool deflectFromBoxSides = true;
|
||||
public string boxTag = "Box";
|
||||
public float outDistance = 12f;
|
||||
public float sideExitPush = 0.02f; // push outward from side face
|
||||
public float entryPush = 0.005f; // push outward from front face so it shows
|
||||
|
||||
// runtime
|
||||
bool _routeViaSide;
|
||||
Vector3 _entryPoint; // front-face hit
|
||||
Vector3 _midPoint; // side-face center
|
||||
Collider _lastBox;
|
||||
int _sideSign = 1; // -1 = left, +1 = right (box local right axis)
|
||||
// Deflection
|
||||
private bool _routeViaSide;
|
||||
private Vector3 _entryPoint;
|
||||
private Vector3 _midPoint;
|
||||
private Collider _lastBox;
|
||||
private int _sideSign = 1;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_selfRoot = transform.root;
|
||||
SetupLaserRenderer();
|
||||
}
|
||||
|
||||
@ -100,7 +78,7 @@ public class LaserBeam : MonoBehaviour
|
||||
switch (currentState)
|
||||
{
|
||||
case LaserState.Idle:
|
||||
hasTriggeredDeathThisBurst = false; // reset per cycle
|
||||
hasTriggeredDeathThisBurst = false;
|
||||
if (timer >= chargeDuration)
|
||||
{
|
||||
timer = 0f;
|
||||
@ -138,20 +116,58 @@ public class LaserBeam : MonoBehaviour
|
||||
}
|
||||
|
||||
if (debugDraw)
|
||||
Debug.DrawLine(laserStart, laserEnd, Color.cyan);
|
||||
}
|
||||
|
||||
public void SetLaserPhase(LaserPhase phase)
|
||||
{
|
||||
currentPhase = phase;
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
Debug.DrawLine(laserStart, laserEnd, Color.cyan, 0f, false);
|
||||
case LaserPhase.Idle:
|
||||
DisableLaser();
|
||||
break;
|
||||
|
||||
case LaserPhase.Charging:
|
||||
UpdateLaserPath();
|
||||
line.enabled = true;
|
||||
SetLineColor(warningColor);
|
||||
break;
|
||||
|
||||
case LaserPhase.Firing:
|
||||
UpdateLaserPath();
|
||||
SetLineColor(laserColor);
|
||||
hasTriggeredDeathThisBurst = false;
|
||||
CheckHit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void TickLaserDuringFiring()
|
||||
{
|
||||
if (currentPhase == LaserPhase.Firing)
|
||||
{
|
||||
UpdateLaserPath();
|
||||
CheckHit();
|
||||
}
|
||||
}
|
||||
|
||||
public void TickLaserDuringCharging()
|
||||
{
|
||||
if (currentPhase == LaserPhase.Charging)
|
||||
{
|
||||
BlinkWarning();
|
||||
UpdateLaserPath();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- Intro show ----------------
|
||||
System.Collections.IEnumerator IntroShow()
|
||||
{
|
||||
introRunning = true;
|
||||
|
||||
float t = 0f;
|
||||
line.enabled = true;
|
||||
SetLineColor(laserColor);
|
||||
|
||||
hasTriggeredDeathThisBurst = false;
|
||||
|
||||
while (t < initialShowDuration)
|
||||
@ -170,7 +186,6 @@ public class LaserBeam : MonoBehaviour
|
||||
introRunning = false;
|
||||
}
|
||||
|
||||
// ---------------- States ----------------
|
||||
void StartCharging()
|
||||
{
|
||||
UpdateLaserPath();
|
||||
@ -178,20 +193,12 @@ public class LaserBeam : MonoBehaviour
|
||||
SetLineColor(warningColor);
|
||||
}
|
||||
|
||||
void BlinkWarning()
|
||||
{
|
||||
float blink = Mathf.PingPong(Time.time * 5f, 1f);
|
||||
Color blinkColor = Color.Lerp(Color.clear, warningColor, blink);
|
||||
SetLineColor(blinkColor);
|
||||
}
|
||||
|
||||
void FireLaser()
|
||||
{
|
||||
UpdateLaserPath();
|
||||
SetLineColor(laserColor);
|
||||
|
||||
hasTriggeredDeathThisBurst = false;
|
||||
CheckHit(); // initial frame
|
||||
CheckHit();
|
||||
}
|
||||
|
||||
void DisableLaser()
|
||||
@ -199,52 +206,6 @@ public class LaserBeam : MonoBehaviour
|
||||
line.enabled = false;
|
||||
}
|
||||
|
||||
// ---------------- Hit Detection (robust) ----------------
|
||||
//void CheckHit()
|
||||
//{
|
||||
// if (hasTriggeredDeathThisBurst) return;
|
||||
|
||||
// Vector3 dir = (laserEnd - laserStart).normalized;
|
||||
// float distToEnd = Vector3.Distance(laserStart, laserEnd);
|
||||
|
||||
// // Cast along visible beam, then pick the nearest valid hit
|
||||
// RaycastHit[] hits = Physics.SphereCastAll(
|
||||
// laserStart, hitRadius, dir,
|
||||
// distToEnd, collisionMask, queryTriggerMode
|
||||
// );
|
||||
|
||||
// if (hits == null || hits.Length == 0) return;
|
||||
|
||||
// float bestDist = float.MaxValue;
|
||||
// Transform best = null;
|
||||
|
||||
// foreach (var h in hits)
|
||||
// {
|
||||
// // Ignore self (any collider in our own hierarchy)
|
||||
// if (h.collider && h.collider.GetComponentInParent<LaserBeam>() == this)
|
||||
// continue;
|
||||
// // Keep the nearest hit under our visible segment
|
||||
// if (h.distance < bestDist)
|
||||
// {
|
||||
// bestDist = h.distance;
|
||||
// best = h.collider.transform;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (best == null) return;
|
||||
|
||||
// // Player detection: check both object and its root
|
||||
// bool isPlayer =
|
||||
// best.CompareTag(playerTag) ||
|
||||
// (best.root != null && best.root.CompareTag(playerTag));
|
||||
|
||||
// if (isPlayer)
|
||||
// {
|
||||
// Debug.Log("Laser hit player: " + best.name);
|
||||
// hasTriggeredDeathThisBurst = true;
|
||||
// CrateEscapeGameManager.Instance?.OnPlayerHitByLaser();
|
||||
// }
|
||||
//}
|
||||
void CheckHit()
|
||||
{
|
||||
if (hasTriggeredDeathThisBurst) return;
|
||||
@ -261,20 +222,32 @@ public class LaserBeam : MonoBehaviour
|
||||
|
||||
float best = float.MaxValue;
|
||||
Transform bestT = null;
|
||||
Collider bestCol = null;
|
||||
foreach (var h in hits)
|
||||
{
|
||||
if (h.collider && h.collider.GetComponentInParent<LaserBeam>() == this) continue;
|
||||
if (h.distance < best) { best = h.distance; bestT = h.collider.transform; }
|
||||
if (h.distance < best) { best = h.distance; bestT = h.collider.transform; bestCol = h.collider; }
|
||||
}
|
||||
|
||||
if (!bestT) return false;
|
||||
|
||||
bool isPlayer = bestT.CompareTag(playerTag) || (bestT.root && bestT.root.CompareTag(playerTag));
|
||||
if (isPlayer)
|
||||
// Hit player
|
||||
if (bestT.CompareTag(playerTag) || (bestT.root && bestT.root.CompareTag(playerTag)))
|
||||
{
|
||||
hasTriggeredDeathThisBurst = true;
|
||||
Debug.Log("Laser hit player: " + bestT.name);
|
||||
CrateEscapeGameManager.Instance?.OnPlayerHitByLaser();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hit box
|
||||
if (bestCol.CompareTag(boxTag))
|
||||
{
|
||||
var boxHealth = bestCol.GetComponent<LaserBoxHealth>();
|
||||
if (boxHealth != null)
|
||||
boxHealth.TakeLaserDamage();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -289,17 +262,19 @@ public class LaserBeam : MonoBehaviour
|
||||
CheckSegment(laserStart, laserEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void BlinkWarning()
|
||||
{
|
||||
float blink = Mathf.PingPong(Time.time * 5f, 1f);
|
||||
Color blinkColor = Color.Lerp(Color.clear, warningColor, blink);
|
||||
SetLineColor(blinkColor);
|
||||
}
|
||||
void UpdateLaserPath()
|
||||
{
|
||||
laserStart = transform.position;
|
||||
Vector3 dir = transform.forward;
|
||||
|
||||
float radius = Mathf.Max(0.0001f, hitRadius);
|
||||
|
||||
// first: straight cast to find the first collider
|
||||
RaycastHit[] hits = Physics.SphereCastAll(laserStart, radius, dir, maxDistance, collisionMask, queryTriggerMode);
|
||||
|
||||
Vector3 straightEnd = laserStart + dir * maxDistance;
|
||||
RaycastHit bestHit = default;
|
||||
float bestDist = float.MaxValue;
|
||||
@ -321,21 +296,18 @@ public class LaserBeam : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// default: straight line
|
||||
_routeViaSide = false;
|
||||
laserEnd = straightEnd;
|
||||
line.positionCount = 2;
|
||||
line.SetPosition(0, laserStart);
|
||||
line.SetPosition(1, laserEnd);
|
||||
|
||||
// route via side center only for tagged Box with a BoxCollider
|
||||
if (!deflectFromBoxSides || !gotHit || !bestHit.collider.CompareTag(boxTag))
|
||||
return;
|
||||
// Side-deflection logic
|
||||
if (!deflectFromBoxSides || !gotHit || !bestHit.collider.CompareTag(boxTag)) return;
|
||||
|
||||
var box = bestHit.collider.GetComponent<BoxCollider>();
|
||||
if (!box) return;
|
||||
|
||||
// choose/stabilize left/right per box
|
||||
if (_lastBox != bestHit.collider)
|
||||
{
|
||||
_lastBox = bestHit.collider;
|
||||
@ -343,19 +315,14 @@ public class LaserBeam : MonoBehaviour
|
||||
}
|
||||
|
||||
Transform t = box.transform;
|
||||
|
||||
// 1) ENTRY POINT on the FRONT face (push a hair outward so it's visible)
|
||||
_entryPoint = bestHit.point + bestHit.normal * entryPush;
|
||||
|
||||
// 2) SIDE-CENTER (left/right in box local space), and outward direction
|
||||
Vector3 centerW = t.TransformPoint(box.center);
|
||||
Vector3 half = Vector3.Scale(box.size * 0.5f, t.lossyScale);
|
||||
Vector3 rightW = t.right.normalized;
|
||||
Vector3 outDir = rightW * _sideSign;
|
||||
_midPoint = centerW + rightW * (_sideSign * half.x);
|
||||
|
||||
// 3) SECOND LEG: from side-center outward
|
||||
// remaining distance after traveling to entry + to side-center
|
||||
float traveled = bestHit.distance + Vector3.Distance(bestHit.point, _midPoint);
|
||||
float remain = Mathf.Max(0f, maxDistance - traveled);
|
||||
float leg = Mathf.Min(outDistance, remain);
|
||||
@ -369,7 +336,6 @@ public class LaserBeam : MonoBehaviour
|
||||
secondEnd = h2.point;
|
||||
}
|
||||
|
||||
// draw the full polyline: START -> ENTRY -> SIDE-CENTER -> OUT
|
||||
_routeViaSide = true;
|
||||
laserEnd = secondEnd;
|
||||
|
||||
@ -380,49 +346,22 @@ public class LaserBeam : MonoBehaviour
|
||||
line.SetPosition(3, laserEnd);
|
||||
}
|
||||
|
||||
//void UpdateLaserPath()
|
||||
//{
|
||||
// laserStart = transform.position;
|
||||
// Vector3 dir = transform.forward;
|
||||
public void ResetCycle()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
introRunning = false;
|
||||
timer = 0f;
|
||||
currentState = LaserState.Idle;
|
||||
currentPhase = LaserPhase.Idle;
|
||||
hasTriggeredDeathThisBurst = false;
|
||||
DisableLaser();
|
||||
}
|
||||
|
||||
// // SphereCast to find the FIRST valid hit along the visible beam,
|
||||
// // ignoring ONLY this laser's own colliders.
|
||||
// float radius = Mathf.Max(0.0001f, hitRadius);
|
||||
// RaycastHit[] hits = Physics.SphereCastAll(
|
||||
// laserStart, radius, dir, maxDistance, collisionMask, queryTriggerMode
|
||||
// );
|
||||
|
||||
// Vector3 end = laserStart + dir * maxDistance;
|
||||
// float bestDist = float.MaxValue;
|
||||
|
||||
// if (hits != null && hits.Length > 0)
|
||||
// {
|
||||
// foreach (var h in hits)
|
||||
// {
|
||||
// if (!h.collider) continue;
|
||||
|
||||
// // Ignore ONLY this LaserBeam's colliders (not the whole root/level)
|
||||
// if (h.collider.GetComponentInParent<LaserBeam>() == this)
|
||||
// continue;
|
||||
|
||||
// if (h.distance < bestDist)
|
||||
// {
|
||||
// bestDist = h.distance;
|
||||
// end = h.point;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// laserEnd = end;
|
||||
|
||||
// line.SetPosition(0, laserStart);
|
||||
// line.SetPosition(1, laserEnd);
|
||||
//}
|
||||
|
||||
// ---------------- Utils ----------------
|
||||
void SetLineColor(Color c)
|
||||
{
|
||||
line.material.color = c;
|
||||
if (line.material.HasProperty("_Color"))
|
||||
line.material.SetColor("_Color", c);
|
||||
|
||||
line.startColor = c;
|
||||
line.endColor = c;
|
||||
}
|
||||
@ -450,18 +389,10 @@ public class LaserBeam : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Custom/EmissiveLaser shader not found. Using fallback.");
|
||||
line.material = new Material(Shader.Find("Sprites/Default"));
|
||||
line.material.color = laserColor;
|
||||
}
|
||||
|
||||
line.enabled = false;
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!debugDraw) return;
|
||||
Gizmos.color = Color.magenta;
|
||||
Gizmos.DrawWireSphere(transform.position, hitRadius);
|
||||
}
|
||||
}
|
||||
|
117
Assets/LaserBeamController.cs
Normal file
117
Assets/LaserBeamController.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using static LaserBeam;
|
||||
|
||||
public class LaserBeamController : MonoBehaviour
|
||||
{
|
||||
public float interval = 20f;
|
||||
public float chargeDuration = 3f;
|
||||
public float fireDuration = 1f;
|
||||
|
||||
private List<LaserBeam> allLasers = new List<LaserBeam>();
|
||||
private List<List<LaserBeam>> batches = new List<List<LaserBeam>>();
|
||||
private List<LaserBeam> activeLasers = new List<LaserBeam>();
|
||||
|
||||
private float timer = 0f;
|
||||
private LaserPhase currentPhase = LaserPhase.Idle;
|
||||
|
||||
void Start()
|
||||
{
|
||||
allLasers.AddRange(FindObjectsOfType<LaserBeam>());
|
||||
|
||||
// Shuffle
|
||||
for (int i = 0; i < allLasers.Count; i++)
|
||||
{
|
||||
var temp = allLasers[i];
|
||||
int rand = Random.Range(i, allLasers.Count);
|
||||
allLasers[i] = allLasers[rand];
|
||||
allLasers[rand] = temp;
|
||||
}
|
||||
|
||||
// Split into 3 batches
|
||||
int batchSize = Mathf.CeilToInt(allLasers.Count / 3f);
|
||||
for (int i = 0; i < allLasers.Count; i += batchSize)
|
||||
{
|
||||
batches.Add(allLasers.GetRange(i, Mathf.Min(batchSize, allLasers.Count - i)));
|
||||
}
|
||||
|
||||
foreach (var lb in allLasers)
|
||||
lb.enabled = false;
|
||||
|
||||
StartCoroutine(ActivateBatches());
|
||||
}
|
||||
|
||||
IEnumerator ActivateBatches()
|
||||
{
|
||||
for (int i = 0; i < batches.Count; i++)
|
||||
{
|
||||
activeLasers.AddRange(batches[i]);
|
||||
|
||||
foreach (var laser in activeLasers)
|
||||
laser.enabled = true;
|
||||
|
||||
Debug.Log($"Activated batch {i + 1}, syncing all {activeLasers.Count} lasers.");
|
||||
ResetAllLasers();
|
||||
|
||||
yield return new WaitForSeconds(interval);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (activeLasers.Count == 0) return;
|
||||
|
||||
timer += Time.deltaTime;
|
||||
|
||||
switch (currentPhase)
|
||||
{
|
||||
case LaserPhase.Idle:
|
||||
if (timer >= chargeDuration)
|
||||
{
|
||||
timer = 0f;
|
||||
currentPhase = LaserPhase.Charging;
|
||||
foreach (var laser in activeLasers)
|
||||
laser.SetLaserPhase(LaserPhase.Charging);
|
||||
}
|
||||
break;
|
||||
|
||||
case LaserPhase.Charging:
|
||||
foreach (var laser in activeLasers)
|
||||
laser.TickLaserDuringCharging();
|
||||
|
||||
if (timer >= 1f)
|
||||
{
|
||||
timer = 0f;
|
||||
currentPhase = LaserPhase.Firing;
|
||||
foreach (var laser in activeLasers)
|
||||
laser.SetLaserPhase(LaserPhase.Firing);
|
||||
}
|
||||
break;
|
||||
|
||||
case LaserPhase.Firing:
|
||||
foreach (var laser in activeLasers)
|
||||
laser.TickLaserDuringFiring();
|
||||
|
||||
if (timer >= fireDuration)
|
||||
{
|
||||
timer = 0f;
|
||||
currentPhase = LaserPhase.Idle;
|
||||
foreach (var laser in activeLasers)
|
||||
laser.SetLaserPhase(LaserPhase.Idle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAllLasers()
|
||||
{
|
||||
timer = 0f;
|
||||
currentPhase = LaserPhase.Idle;
|
||||
|
||||
foreach (var laser in activeLasers)
|
||||
{
|
||||
laser.SetLaserPhase(LaserPhase.Idle);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/LaserBeamController.cs.meta
Normal file
11
Assets/LaserBeamController.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9511137add479ac46a49f0f07d801aea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
283
Assets/Prefabs/ChaseLaser.prefab
Normal file
283
Assets/Prefabs/ChaseLaser.prefab
Normal file
@ -0,0 +1,283 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &2076035923175665683
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4569536219989199992}
|
||||
- component: {fileID: 5627322522777133560}
|
||||
- component: {fileID: 673720149171018749}
|
||||
- component: {fileID: 89581383608372913}
|
||||
m_Layer: 10
|
||||
m_Name: BeamLine
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4569536219989199992
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2076035923175665683}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: -0.7071068, z: 0, w: 0.7071068}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 5.9825163, y: 5.9825163, z: 5.9825163}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5791487380880912914}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: -90, z: 0}
|
||||
--- !u!114 &5627322522777133560
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2076035923175665683}
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fb66dc0e33e58d7439c1db6e435dcc9e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
maxDistance: 6.2
|
||||
collisionMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 255
|
||||
chargeDuration: 3
|
||||
fireDuration: 1
|
||||
laserColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
warningColor: {r: 1, g: 0.5, b: 0, a: 1}
|
||||
laserWidth: 0.01
|
||||
emissionStrength: 2
|
||||
scrollSpeed: 1
|
||||
playerTag: Player
|
||||
hitRadius: 0.1
|
||||
queryTriggerMode: 2
|
||||
showIntro: 1
|
||||
initialShowDuration: 3
|
||||
introIsDeadly: 1
|
||||
deflectFromBoxSides: 1
|
||||
boxTag: Box
|
||||
outDistance: 12
|
||||
sideExitPush: 0.02
|
||||
entryPush: 0.005
|
||||
debugDraw: 0
|
||||
--- !u!120 &673720149171018749
|
||||
LineRenderer:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2076035923175665683}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 0
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_Positions:
|
||||
- {x: 1.5000002, y: 0.582, z: 56.903}
|
||||
- {x: 0.12069942, y: 0.5819865, z: 56.902992}
|
||||
m_Parameters:
|
||||
serializedVersion: 3
|
||||
widthMultiplier: 0.01
|
||||
widthCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
colorGradient:
|
||||
serializedVersion: 2
|
||||
key0: {r: 1, g: 0, b: 0, a: 1}
|
||||
key1: {r: 1, g: 0, b: 0, a: 1}
|
||||
key2: {r: 0, g: 0, b: 0, a: 0}
|
||||
key3: {r: 0, g: 0, b: 0, a: 0}
|
||||
key4: {r: 0, g: 0, b: 0, a: 0}
|
||||
key5: {r: 0, g: 0, b: 0, a: 0}
|
||||
key6: {r: 0, g: 0, b: 0, a: 0}
|
||||
key7: {r: 0, g: 0, b: 0, a: 0}
|
||||
ctime0: 0
|
||||
ctime1: 65535
|
||||
ctime2: 0
|
||||
ctime3: 0
|
||||
ctime4: 0
|
||||
ctime5: 0
|
||||
ctime6: 0
|
||||
ctime7: 0
|
||||
atime0: 0
|
||||
atime1: 65535
|
||||
atime2: 0
|
||||
atime3: 0
|
||||
atime4: 0
|
||||
atime5: 0
|
||||
atime6: 0
|
||||
atime7: 0
|
||||
m_Mode: 0
|
||||
m_ColorSpace: -1
|
||||
m_NumColorKeys: 2
|
||||
m_NumAlphaKeys: 2
|
||||
numCornerVertices: 0
|
||||
numCapVertices: 0
|
||||
alignment: 0
|
||||
textureMode: 0
|
||||
textureScale: {x: 1, y: 1}
|
||||
shadowBias: 0.5
|
||||
generateLightingData: 0
|
||||
m_MaskInteraction: 0
|
||||
m_UseWorldSpace: 1
|
||||
m_Loop: 0
|
||||
m_ApplyActiveColorSpace: 1
|
||||
--- !u!114 &89581383608372913
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2076035923175665683}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0a334db153d189a48b221ea963f66011, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
laserOrigin: {fileID: 4569536219989199992}
|
||||
maxDistance: 20
|
||||
collisionMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
laserColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
laserWidth: 0.05
|
||||
scrollSpeed: 1
|
||||
emissionStrength: 5
|
||||
updateRate: 0.02
|
||||
--- !u!1 &5941778434987404378
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5791487380880912914}
|
||||
- component: {fileID: 1558933298697028777}
|
||||
- component: {fileID: 355708440500072884}
|
||||
m_Layer: 10
|
||||
m_Name: ChaseLaser
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5791487380880912914
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5941778434987404378}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0.072500005, y: -0.001000023, z: -0.000029999112}
|
||||
m_LocalScale: {x: 5, y: 5, z: 5}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_Children:
|
||||
- {fileID: 4569536219989199992}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: -90, y: 0, z: 0}
|
||||
--- !u!33 &1558933298697028777
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5941778434987404378}
|
||||
m_Mesh: {fileID: 938762473992563870, guid: 672aa84817b45ba4aa212666c86e0d4a, type: 3}
|
||||
--- !u!23 &355708440500072884
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5941778434987404378}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: bd4a01711df9d8d43a627cfa7fd3d2cf, type: 2}
|
||||
- {fileID: 2100000, guid: c4a4afe7921aa2f4582fccd2bd7f1efa, type: 2}
|
||||
- {fileID: 2100000, guid: 5fbb0c4334374934abc11d566db804a9, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
7
Assets/Prefabs/ChaseLaser.prefab.meta
Normal file
7
Assets/Prefabs/ChaseLaser.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 464bfa86f2fc8034bb796ca8b991caef
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@ -1500,7 +1500,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!215 &1117356489
|
||||
ReflectionProbe:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -2512,6 +2512,8 @@ MonoBehaviour:
|
||||
fallingStateName: Falling
|
||||
secondHitWindow: 10
|
||||
stateWaitTimeout: 3
|
||||
waitingForGameOver: 0
|
||||
fallingShortHash: 0
|
||||
validateStatesOnStart: 1
|
||||
runTag: Run
|
||||
fallTag: Fall
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,6 @@ public class ChaseCoin : MonoBehaviour
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
Debug.Log("ChaseCoin0");
|
||||
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
|
@ -36,9 +36,10 @@ public class ChasePlayerController : MonoBehaviour
|
||||
float minSwipeDistance = 50f;
|
||||
|
||||
float lastObstacleHitTime = -999f;
|
||||
bool waitingForGameOver = false;
|
||||
public bool waitingForGameOver = false;
|
||||
|
||||
int runShortHash, fallShortHash, fallingShortHash;
|
||||
int runShortHash, fallShortHash;
|
||||
public int fallingShortHash;
|
||||
[SerializeField] bool validateStatesOnStart = true;
|
||||
[SerializeField] string runTag = "Run";
|
||||
[SerializeField] string fallTag = "Fall";
|
||||
@ -329,7 +330,7 @@ public class ChasePlayerController : MonoBehaviour
|
||||
animator.CrossFadeInFixedTime(runStateName, 0.1f, baseLayer, 0f);
|
||||
}
|
||||
}
|
||||
IEnumerator PlayStateAndGameOver(string stateName, int shortHash, float xfade = 0.08f)
|
||||
public IEnumerator PlayStateAndGameOver(string stateName, int shortHash, float xfade = 0.08f)
|
||||
{
|
||||
unableToMove = true;
|
||||
if (string.IsNullOrEmpty(stateName) || animator == null)
|
||||
|
98
Assets/Scripts/CrateEscape/LaserBoxHealth.cs
Normal file
98
Assets/Scripts/CrateEscape/LaserBoxHealth.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class LaserBoxHealth : MonoBehaviour
|
||||
{
|
||||
[Header("Health Settings")]
|
||||
public float maxHealth = 100f;
|
||||
public float currentHealth = 100f;
|
||||
public float damagePerHit = 10f;
|
||||
|
||||
[Header("Visual Feedback")]
|
||||
public Renderer targetRenderer; // assign your MeshRenderer here if not on same object
|
||||
private List<Material> runtimeMaterials = new List<Material>();
|
||||
private List<Color> originalColors = new List<Color>();
|
||||
|
||||
[Header("Destruction")]
|
||||
public float destructionDuration = 1f;
|
||||
private bool isDestroying = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (!targetRenderer)
|
||||
targetRenderer = GetComponent<Renderer>();
|
||||
|
||||
if (targetRenderer != null)
|
||||
{
|
||||
var sharedMats = targetRenderer.materials;
|
||||
runtimeMaterials.Clear();
|
||||
originalColors.Clear();
|
||||
|
||||
for (int i = 0; i < sharedMats.Length; i++)
|
||||
{
|
||||
Material mat = new Material(sharedMats[i]); // create runtime copy
|
||||
runtimeMaterials.Add(mat);
|
||||
originalColors.Add(mat.color);
|
||||
}
|
||||
|
||||
targetRenderer.materials = runtimeMaterials.ToArray(); // assign runtime copies
|
||||
}
|
||||
|
||||
currentHealth = maxHealth;
|
||||
}
|
||||
|
||||
public void TakeLaserDamage()
|
||||
{
|
||||
if (isDestroying || currentHealth <= 0f) return;
|
||||
|
||||
currentHealth -= damagePerHit;
|
||||
currentHealth = Mathf.Clamp(currentHealth, 0f, maxHealth);
|
||||
|
||||
UpdateColors();
|
||||
|
||||
if (currentHealth <= 0f)
|
||||
{
|
||||
StartCoroutine(ScaleAndDisable());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColors()
|
||||
{
|
||||
float healthPercent = currentHealth / maxHealth;
|
||||
|
||||
for (int i = 0; i < runtimeMaterials.Count; i++)
|
||||
{
|
||||
if (runtimeMaterials[i] == null) continue;
|
||||
|
||||
Color targetColor = originalColors[i];
|
||||
|
||||
if (healthPercent <= 0.5f && healthPercent > 0.1f)
|
||||
{
|
||||
float t = Mathf.InverseLerp(0.5f, 0.1f, healthPercent);
|
||||
runtimeMaterials[i].color = Color.Lerp(Color.black, targetColor, t);
|
||||
}
|
||||
else if (healthPercent <= 0.1f)
|
||||
{
|
||||
runtimeMaterials[i].color = Color.black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator ScaleAndDisable()
|
||||
{
|
||||
isDestroying = true;
|
||||
|
||||
Vector3 startScale = transform.localScale;
|
||||
Vector3 endScale = Vector3.zero;
|
||||
|
||||
float t = 0f;
|
||||
while (t < destructionDuration)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
transform.localScale = Vector3.Lerp(startScale, endScale, t / destructionDuration);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
11
Assets/Scripts/CrateEscape/LaserBoxHealth.cs.meta
Normal file
11
Assets/Scripts/CrateEscape/LaserBoxHealth.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7425323cb2d4b3d4cb9b8411e82185ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
x
Reference in New Issue
Block a user