using System.Collections.Generic; using UnityEngine; /// /// 激光静态工具类:激光实例的创建/朝向/长度计算,不依赖组件实例。 /// 调用方自行持有激光实例列表(fxList)、基准缩放(fxBaseScale)和长度校正值(lengthCorrect), /// 创建后每帧调用 JiGuangDirection/JiGuangLength 刷新。 /// 起点支持 Transform / Vector3 两种;Z 轴重载: /// - 不带 z 参数 → 直接读取起点/目标对象自身的 Z /// - 带 z 参数 → 强制起点和终点都使用指定 Z(如战神激光统一压到 -50 显示层) /// public static class JiGuangControl { // ==================== 创建 ==================== /// 按目标数量创建激光实例(克隆预制体,挂到 parent 下)。生成位置读取起点对象自身的 Z public static void JiGuangCreate(GameObject prefab, Transform start, List targets, List fxList, Transform parent = null) { if (start == null) return; JiGuangCreateCore(prefab, start.position, targets, fxList, parent, null); } /// 同上,但生成位置强制使用指定 Z public static void JiGuangCreate(GameObject prefab, Transform start, List targets, List fxList, Transform parent, float z) { if (start == null) return; JiGuangCreateCore(prefab, start.position, targets, fxList, parent, z); } /// 起点直接给坐标(如战神激光的动态炮口位置)。生成位置读取 startPos 自身的 Z public static void JiGuangCreate(GameObject prefab, Vector3 startPos, List targets, List fxList, Transform parent = null) { JiGuangCreateCore(prefab, startPos, targets, fxList, parent, null); } /// 同上,但生成位置强制使用指定 Z public static void JiGuangCreate(GameObject prefab, Vector3 startPos, List targets, List fxList, Transform parent, float z) { JiGuangCreateCore(prefab, startPos, targets, fxList, parent, z); } /// /// 多起点创建:startPositions 与 targets 一一对应(每条激光独立起点), /// 生成位置强制使用指定 Z。起点数量不足时复用最后一个起点。 /// (如战神激光:第0条=座位点+偏移的主起点,第1/2条=散射左右父对象起点) /// public static void JiGuangCreate(GameObject prefab, List startPositions, List targets, List fxList, Transform parent, float z) { if (prefab == null || startPositions == null || startPositions.Count == 0 || targets == null || fxList == null) return; for (int i = 0; i < fxList.Count; i++) if (fxList[i] != null) Object.Destroy(fxList[i].gameObject); fxList.Clear(); for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; Vector3 spawnPos = startPositions[Mathf.Min(i, startPositions.Count - 1)]; spawnPos.z = z; GameObject go = Object.Instantiate(prefab, spawnPos, Quaternion.identity, parent); go.name = prefab.name + "_" + i; fxList.Add(go.transform); } } private static void JiGuangCreateCore(GameObject prefab, Vector3 startPos, List targets, List fxList, Transform parent, float? forcedZ) { if (prefab == null || targets == null || fxList == null) return; for (int i = 0; i < fxList.Count; i++) if (fxList[i] != null) Object.Destroy(fxList[i].gameObject); fxList.Clear(); for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; Vector3 spawnPos = startPos; if (forcedZ.HasValue) spawnPos.z = forcedZ.Value; GameObject go = Object.Instantiate(prefab, spawnPos, Quaternion.identity, parent); go.name = prefab.name + "_" + i; fxList.Add(go.transform); } } // ==================== 朝向 ==================== /// 刷新激光朝向:直接读取起点/目标对象自身的 Z public static void JiGuangDirection(Transform start, List targets, List fxList) { if (start == null) return; JiGuangDirectionCore(start.position, targets, fxList, null); } /// 刷新激光朝向:起点和终点强制使用指定 Z(同层) public static void JiGuangDirection(Transform start, List targets, List fxList, float z) { if (start == null) return; JiGuangDirectionCore(start.position, targets, fxList, z); } /// 刷新激光朝向(起点为坐标):直接使用 startPos 自身的 Z public static void JiGuangDirection(Vector3 startPos, List targets, List fxList) { JiGuangDirectionCore(startPos, targets, fxList, null); } /// 刷新激光朝向(起点为坐标):起点和终点强制使用指定 Z(同层) public static void JiGuangDirection(Vector3 startPos, List targets, List fxList, float z) { JiGuangDirectionCore(startPos, targets, fxList, z); } /// /// 多起点朝向:startPositions 与 targets/fxList 一一对应(每条激光独立起点), /// 起点和终点强制使用指定 Z(同层)。起点数量不足时复用最后一个起点。 /// rotateZ:激光预制体自带的 Z 轴旋转(偏移),绕世界 Z 轴叠加在计算朝向上—— /// 预制体上转 Z = 激光在平面内整体旋转(手动修正角度用);X/Y 不参与,保证激光不会甩出平面。 /// public static void JiGuangDirection(List startPositions, List targets, List fxList, float z, float rotateZ) { if (startPositions == null || startPositions.Count == 0 || targets == null || fxList == null || fxList.Count == 0) return; int fxIndex = 0; for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; if (fxIndex >= fxList.Count) break; Vector3 startPos = startPositions[Mathf.Min(i, startPositions.Count - 1)]; Vector3 endPos = targets[i].position; startPos.z = z; endPos.z = z; Vector3 dir = endPos - startPos; if (dir.sqrMagnitude > 0.0001f) fxList[fxIndex].rotation = Quaternion.Euler(0f, 0f, rotateZ) * Quaternion.LookRotation(dir); fxIndex++; } } private static void JiGuangDirectionCore(Vector3 startPos, List targets, List fxList, float? forcedZ) { if (targets == null || fxList == null || fxList.Count == 0) return; int fxIndex = 0; for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; if (fxIndex >= fxList.Count) break; Vector3 endPos = targets[i].position; if (forcedZ.HasValue) { startPos.z = forcedZ.Value; endPos.z = forcedZ.Value; } Vector3 dir = endPos - startPos; if (dir.sqrMagnitude > 0.0001f) fxList[fxIndex].rotation = Quaternion.LookRotation(dir); fxIndex++; } } // ==================== 长度 ==================== /// 刷新激光长度(按基准缩放拉伸 Z 轴):直接读取起点/目标对象自身的 Z public static void JiGuangLength(Transform start, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect = 1f) { if (start == null) return; JiGuangLengthCore(start.position, targets, fxList, fxBaseScale, lengthCorrect, null); } /// 刷新激光长度:起点和终点强制使用指定 Z(同层) public static void JiGuangLength(Transform start, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect, float z) { if (start == null) return; JiGuangLengthCore(start.position, targets, fxList, fxBaseScale, lengthCorrect, z); } /// 刷新激光长度(起点为坐标):直接使用 startPos 自身的 Z public static void JiGuangLength(Vector3 startPos, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect = 1f) { JiGuangLengthCore(startPos, targets, fxList, fxBaseScale, lengthCorrect, null); } /// 刷新激光长度(起点为坐标):起点和终点强制使用指定 Z(同层) public static void JiGuangLength(Vector3 startPos, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect, float z) { JiGuangLengthCore(startPos, targets, fxList, fxBaseScale, lengthCorrect, z); } /// /// 多起点长度:startPositions 与 targets/fxList 一一对应(每条激光独立起点), /// 起点和终点强制使用指定 Z(同层)。起点数量不足时复用最后一个起点。 /// public static void JiGuangLength(List startPositions, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect, float z) { if (startPositions == null || startPositions.Count == 0 || targets == null || fxList == null || fxList.Count == 0) return; int fxIndex = 0; for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; if (fxIndex >= fxList.Count) break; Vector3 startPos = startPositions[Mathf.Min(i, startPositions.Count - 1)]; Vector3 endPos = targets[i].position; startPos.z = z; endPos.z = z; float distance = (endPos - startPos).magnitude; Vector3 scale = fxBaseScale; scale.z = distance * fxBaseScale.z * lengthCorrect; fxList[fxIndex].localScale = scale; fxIndex++; } } private static void JiGuangLengthCore(Vector3 startPos, List targets, List fxList, Vector3 fxBaseScale, float lengthCorrect, float? forcedZ) { if (targets == null || fxList == null || fxList.Count == 0) return; int fxIndex = 0; for (int i = 0; i < targets.Count; i++) { if (targets[i] == null) continue; if (fxIndex >= fxList.Count) break; Vector3 endPos = targets[i].position; if (forcedZ.HasValue) { startPos.z = forcedZ.Value; endPos.z = forcedZ.Value; } float distance = (endPos - startPos).magnitude; Vector3 scale = fxBaseScale; scale.z = distance * fxBaseScale.z * lengthCorrect; fxList[fxIndex].localScale = scale; fxIndex++; } } }