This commit is contained in:
2026-10-14 19:39:24 +08:00
parent 4fd5a3bd45
commit 8498afd5cf
202 changed files with 12624 additions and 236 deletions
+260
View File
@@ -0,0 +1,260 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 激光静态工具类:激光实例的创建/朝向/长度计算,不依赖组件实例。
/// 调用方自行持有激光实例列表(fxList)、基准缩放(fxBaseScale)和长度校正值(lengthCorrect),
/// 创建后每帧调用 JiGuangDirection/JiGuangLength 刷新。
/// 起点支持 Transform / Vector3 两种;Z 轴重载:
/// - 不带 z 参数 → 直接读取起点/目标对象自身的 Z
/// - 带 z 参数 → 强制起点和终点都使用指定 Z(如战神激光统一压到 -50 显示层)
/// </summary>
public static class JiGuangControl
{
// ==================== 创建 ====================
/// <summary>按目标数量创建激光实例(克隆预制体,挂到 parent 下)。生成位置读取起点对象自身的 Z</summary>
public static void JiGuangCreate(GameObject prefab, Transform start, List<Transform> targets, List<Transform> fxList, Transform parent = null)
{
if (start == null) return;
JiGuangCreateCore(prefab, start.position, targets, fxList, parent, null);
}
/// <summary>同上,但生成位置强制使用指定 Z</summary>
public static void JiGuangCreate(GameObject prefab, Transform start, List<Transform> targets, List<Transform> fxList, Transform parent, float z)
{
if (start == null) return;
JiGuangCreateCore(prefab, start.position, targets, fxList, parent, z);
}
/// <summary>起点直接给坐标(如战神激光的动态炮口位置)。生成位置读取 startPos 自身的 Z</summary>
public static void JiGuangCreate(GameObject prefab, Vector3 startPos, List<Transform> targets, List<Transform> fxList, Transform parent = null)
{
JiGuangCreateCore(prefab, startPos, targets, fxList, parent, null);
}
/// <summary>同上,但生成位置强制使用指定 Z</summary>
public static void JiGuangCreate(GameObject prefab, Vector3 startPos, List<Transform> targets, List<Transform> fxList, Transform parent, float z)
{
JiGuangCreateCore(prefab, startPos, targets, fxList, parent, z);
}
/// <summary>
/// 多起点创建:startPositions 与 targets 一一对应(每条激光独立起点),
/// 生成位置强制使用指定 Z。起点数量不足时复用最后一个起点。
/// (如战神激光:第0条=座位点+偏移的主起点,第1/2条=散射左右父对象起点)
/// </summary>
public static void JiGuangCreate(GameObject prefab, List<Vector3> startPositions, List<Transform> targets, List<Transform> 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<Transform> targets, List<Transform> 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);
}
}
// ==================== 朝向 ====================
/// <summary>刷新激光朝向:直接读取起点/目标对象自身的 Z</summary>
public static void JiGuangDirection(Transform start, List<Transform> targets, List<Transform> fxList)
{
if (start == null) return;
JiGuangDirectionCore(start.position, targets, fxList, null);
}
/// <summary>刷新激光朝向:起点和终点强制使用指定 Z(同层)</summary>
public static void JiGuangDirection(Transform start, List<Transform> targets, List<Transform> fxList, float z)
{
if (start == null) return;
JiGuangDirectionCore(start.position, targets, fxList, z);
}
/// <summary>刷新激光朝向(起点为坐标):直接使用 startPos 自身的 Z</summary>
public static void JiGuangDirection(Vector3 startPos, List<Transform> targets, List<Transform> fxList)
{
JiGuangDirectionCore(startPos, targets, fxList, null);
}
/// <summary>刷新激光朝向(起点为坐标):起点和终点强制使用指定 Z(同层)</summary>
public static void JiGuangDirection(Vector3 startPos, List<Transform> targets, List<Transform> fxList, float z)
{
JiGuangDirectionCore(startPos, targets, fxList, z);
}
/// <summary>
/// 多起点朝向:startPositions 与 targets/fxList 一一对应(每条激光独立起点),
/// 起点和终点强制使用指定 Z(同层)。起点数量不足时复用最后一个起点。
/// rotateZ:激光预制体自带的 Z 轴旋转(偏移),绕世界 Z 轴叠加在计算朝向上——
/// 预制体上转 Z = 激光在平面内整体旋转(手动修正角度用);X/Y 不参与,保证激光不会甩出平面。
/// </summary>
public static void JiGuangDirection(List<Vector3> startPositions, List<Transform> targets, List<Transform> 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<Transform> targets, List<Transform> 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++;
}
}
// ==================== 长度 ====================
/// <summary>刷新激光长度(按基准缩放拉伸 Z 轴):直接读取起点/目标对象自身的 Z</summary>
public static void JiGuangLength(Transform start, List<Transform> targets, List<Transform> fxList, Vector3 fxBaseScale, float lengthCorrect = 1f)
{
if (start == null) return;
JiGuangLengthCore(start.position, targets, fxList, fxBaseScale, lengthCorrect, null);
}
/// <summary>刷新激光长度:起点和终点强制使用指定 Z(同层)</summary>
public static void JiGuangLength(Transform start, List<Transform> targets, List<Transform> fxList, Vector3 fxBaseScale, float lengthCorrect, float z)
{
if (start == null) return;
JiGuangLengthCore(start.position, targets, fxList, fxBaseScale, lengthCorrect, z);
}
/// <summary>刷新激光长度(起点为坐标):直接使用 startPos 自身的 Z</summary>
public static void JiGuangLength(Vector3 startPos, List<Transform> targets, List<Transform> fxList, Vector3 fxBaseScale, float lengthCorrect = 1f)
{
JiGuangLengthCore(startPos, targets, fxList, fxBaseScale, lengthCorrect, null);
}
/// <summary>刷新激光长度(起点为坐标):起点和终点强制使用指定 Z(同层)</summary>
public static void JiGuangLength(Vector3 startPos, List<Transform> targets, List<Transform> fxList, Vector3 fxBaseScale, float lengthCorrect, float z)
{
JiGuangLengthCore(startPos, targets, fxList, fxBaseScale, lengthCorrect, z);
}
/// <summary>
/// 多起点长度:startPositions 与 targets/fxList 一一对应(每条激光独立起点),
/// 起点和终点强制使用指定 Z(同层)。起点数量不足时复用最后一个起点。
/// </summary>
public static void JiGuangLength(List<Vector3> startPositions, List<Transform> targets, List<Transform> 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<Transform> targets, List<Transform> 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++;
}
}
}