EnergyEfficiencyManagement/Assets/Zion/Scripts/Utils/SplitMergeController.cs

595 lines
16 KiB
C#

using DG.Tweening;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SplitMergeController : MonoBehaviour
{
[System.Serializable]
public class PartInfo
{
public Transform partTransform;
[HideInInspector] public Vector3 assembledWorldPosition;
[HideInInspector] public Quaternion assembledWorldRotation;
[HideInInspector] public Vector3 detachedWorldPosition;
[HideInInspector] public Quaternion detachedWorldRotation;
[HideInInspector] public Vector3 assembledLocalPosition;
[HideInInspector] public Quaternion assembledLocalRotation;
}
[Header("动画参数")]
[SerializeField] private float animationDuration = 1.0f;
[SerializeField] private float splitDistance = 3.0f;
[SerializeField] private float heightOffset = 1.0f;
[SerializeField] private Ease moveEase = Ease.OutCubic;
[SerializeField] private Ease rotateEase = Ease.OutCubic;
[Header("调试设置")]
[SerializeField] private bool debugMode = false;
[SerializeField] private List<PartInfo> parts = new List<PartInfo>();
// 状态控制
private bool isSplit = false;
private Sequence currentAnimationSequence;
private float lastOperationTime = 0f;
private const float CLICK_COOLDOWN = 0.1f;
private Transform targetParent;
#region
/// <summary>
/// 设置目标父节点
/// </summary>
public void SetTarget(Transform parent)
{
if (parent == null)
{
Debug.LogError("SetTarget: 父节点不能为空");
return;
}
if (debugMode) Debug.Log($"SetTarget: 开始设置目标父节点 {parent.name}");
// 停止当前动画
StopCurrentAnimation();
// 清空现有部件
parts.Clear();
targetParent = parent;
// 收集所有可移动的子物体
CollectMovableParts(parent);
if (debugMode) Debug.Log($"SetTarget: 已收集 {parts.Count} 个可移动部件");
if (parts.Count == 0)
{
Debug.LogWarning($"SetTarget: 目标父节点 {parent.name} 下没有找到可移动的部件");
return;
}
// 初始化部件数据
InitializeParts();
Debug.Log($"SetTarget: 成功设置目标 {parent.name}, 包含 {parts.Count} 个部件");
}
/// <summary>
/// 拆分所有部件
/// </summary>
public void Split()
{
if (parts.Count == 0)
{
Debug.LogError("Split: 请先调用 SetTarget 设置目标");
return;
}
if (isSplit)
{
if (debugMode) Debug.Log("Split: 已处于拆分状态");
return;
}
if (IsInCooldown())
{
if (debugMode) Debug.Log("Split: 操作冷却中");
return;
}
if (IsAnimating())
{
if (debugMode) Debug.Log("Split: 正在动画中,将中断当前动画");
}
StopCurrentAnimation();
lastOperationTime = Time.time;
if (debugMode) Debug.Log($"Split: 开始拆分 {parts.Count} 个部件");
// 使用DOTween创建动画序列
currentAnimationSequence = DOTween.Sequence();
int activeParts = 0;
foreach (PartInfo part in parts)
{
if (part.partTransform == null || !part.partTransform.gameObject.activeInHierarchy)
{
if (debugMode) Debug.LogWarning($"Split: 跳过无效部件 {part.partTransform?.name}");
continue;
}
// 检查部件是否在场景中
if (!IsTransformValid(part.partTransform))
{
if (debugMode) Debug.LogWarning($"Split: 跳过无效变换 {part.partTransform.name}");
continue;
}
activeParts++;
// 添加移动动画
var moveTween = part.partTransform.DOMove(
part.detachedWorldPosition,
animationDuration
).SetEase(moveEase);
// 添加旋转动画
var rotateTween = part.partTransform.DORotateQuaternion(
part.detachedWorldRotation,
animationDuration
).SetEase(rotateEase);
// 添加到序列
currentAnimationSequence.Insert(0, moveTween);
currentAnimationSequence.Insert(0, rotateTween);
}
if (activeParts == 0)
{
Debug.LogError("Split: 没有有效的部件可以拆分");
currentAnimationSequence = null;
return;
}
if (debugMode) Debug.Log($"Split: 为 {activeParts} 个有效部件创建动画");
// 设置动画完成回调
currentAnimationSequence.OnComplete(() =>
{
isSplit = true;
currentAnimationSequence = null;
if (debugMode) Debug.Log("Split: 拆分动画完成");
});
currentAnimationSequence.OnKill(() =>
{
if (debugMode) Debug.Log("Split: 拆分动画被中断");
});
currentAnimationSequence.Play();
}
/// <summary>
/// 合并所有部件
/// </summary>
public void Merge()
{
if (parts.Count == 0)
{
Debug.LogError("Merge: 请先调用 SetTarget 设置目标");
return;
}
if (!isSplit)
{
if (debugMode) Debug.Log("Merge: 已处于合并状态");
return;
}
if (IsInCooldown())
{
if (debugMode) Debug.Log("Merge: 操作冷却中");
return;
}
if (IsAnimating())
{
if (debugMode) Debug.Log("Merge: 正在动画中,将中断当前动画");
}
StopCurrentAnimation();
lastOperationTime = Time.time;
if (debugMode) Debug.Log($"Merge: 开始合并 {parts.Count} 个部件");
// 使用DOTween创建动画序列
currentAnimationSequence = DOTween.Sequence();
int activeParts = 0;
foreach (PartInfo part in parts)
{
if (part.partTransform == null || !part.partTransform.gameObject.activeInHierarchy)
{
if (debugMode) Debug.LogWarning($"Merge: 跳过无效部件 {part.partTransform?.name}");
continue;
}
// 检查部件是否在场景中
if (!IsTransformValid(part.partTransform))
{
if (debugMode) Debug.LogWarning($"Merge: 跳过无效变换 {part.partTransform.name}");
continue;
}
activeParts++;
// 添加移动动画
var moveTween = part.partTransform.DOMove(
part.assembledWorldPosition,
animationDuration
).SetEase(moveEase);
// 添加旋转动画
var rotateTween = part.partTransform.DORotateQuaternion(
part.assembledWorldRotation,
animationDuration
).SetEase(rotateEase);
// 添加到序列
currentAnimationSequence.Insert(0, moveTween);
currentAnimationSequence.Insert(0, rotateTween);
}
if (activeParts == 0)
{
Debug.LogError("Merge: 没有有效的部件可以合并");
currentAnimationSequence = null;
return;
}
if (debugMode) Debug.Log($"Merge: 为 {activeParts} 个有效部件创建动画");
// 设置动画完成回调
currentAnimationSequence.OnComplete(() =>
{
isSplit = false;
currentAnimationSequence = null;
if (debugMode) Debug.Log("Merge: 合并动画完成");
});
currentAnimationSequence.OnKill(() =>
{
if (debugMode) Debug.Log("Merge: 合并动画被中断");
});
currentAnimationSequence.Play();
}
/// <summary>
/// 切换拆分/合并状态
/// </summary>
public void Toggle()
{
if (IsInCooldown())
{
if (debugMode) Debug.Log("Toggle: 操作冷却中");
return;
}
if (isSplit)
{
Merge();
}
else
{
Split();
}
}
/// <summary>
/// 停止当前动画
/// </summary>
public void StopCurrentAnimation()
{
if (currentAnimationSequence != null && currentAnimationSequence.IsActive())
{
if (debugMode) Debug.Log("停止当前动画");
currentAnimationSequence.Kill();
currentAnimationSequence = null;
}
}
/// <summary>
/// 立即完成拆分
/// </summary>
public void InstantSplit()
{
StopCurrentAnimation();
int movedParts = 0;
foreach (PartInfo part in parts)
{
if (part.partTransform == null || !part.partTransform.gameObject.activeInHierarchy) continue;
if (!IsTransformValid(part.partTransform)) continue;
part.partTransform.position = part.detachedWorldPosition;
part.partTransform.rotation = part.detachedWorldRotation;
movedParts++;
}
isSplit = true;
if (debugMode) Debug.Log($"InstantSplit: 立即拆分了 {movedParts} 个部件");
}
/// <summary>
/// 立即完成合并
/// </summary>
public void InstantMerge()
{
StopCurrentAnimation();
int movedParts = 0;
foreach (PartInfo part in parts)
{
if (part.partTransform == null || !part.partTransform.gameObject.activeInHierarchy) continue;
if (!IsTransformValid(part.partTransform)) continue;
part.partTransform.position = part.assembledWorldPosition;
part.partTransform.rotation = part.assembledWorldRotation;
movedParts++;
}
isSplit = false;
if (debugMode) Debug.Log($"InstantMerge: 立即合并了 {movedParts} 个部件");
}
/// <summary>
/// 获取当前状态
/// </summary>
public bool GetCurrentState()
{
return isSplit;
}
/// <summary>
/// 是否正在动画中
/// </summary>
public bool IsAnimating()
{
return currentAnimationSequence != null && currentAnimationSequence.IsActive();
}
/// <summary>
/// 设置动画时长
/// </summary>
public void SetAnimationDuration(float duration)
{
animationDuration = Mathf.Max(0.1f, duration);
}
/// <summary>
/// 设置拆分距离
/// </summary>
public void SetSplitDistance(float distance)
{
splitDistance = Mathf.Max(0.5f, distance);
if (parts.Count > 0 && targetParent != null)
{
CalculateDetachedPositions();
}
}
/// <summary>
/// 设置移动缓动类型
/// </summary>
public void SetMoveEase(Ease ease)
{
moveEase = ease;
}
/// <summary>
/// 设置旋转缓动类型
/// </summary>
public void SetRotateEase(Ease ease)
{
rotateEase = ease;
}
/// <summary>
/// 获取部件数量
/// </summary>
public int GetPartCount()
{
return parts.Count;
}
/// <summary>
/// 重新计算拆分位置
/// </summary>
public void RecalculatePositions()
{
if (targetParent != null && parts.Count > 0)
{
CalculateDetachedPositions();
}
}
#endregion
#region
/// <summary>
/// 收集可移动的部件
/// </summary>
private void CollectMovableParts(Transform parent)
{
if (parent == null) return;
// 收集所有直接子物体
foreach (Transform child in parent)
{
if (child == null) continue;
// 检查这个子物体是否应该被移动
if (ShouldMoveTransform(child))
{
PartInfo part = new PartInfo
{
partTransform = child
};
parts.Add(part);
if (debugMode)
{
Debug.Log($"收集部件: {child.name}, 子物体数量: {GetChildCount(child)}");
}
}
}
if (debugMode && parts.Count == 0)
{
Debug.LogWarning($"没有收集到任何部件,父节点 {parent.name} 有 {parent.childCount} 个子物体");
}
}
/// <summary>
/// 判断变换是否应该被移动
/// </summary>
private bool ShouldMoveTransform(Transform t)
{
if (t == null) return false;
// 总是移动直接子物体,无论它是否为空
return true;
}
/// <summary>
/// 获取子物体数量
/// </summary>
private int GetChildCount(Transform parent)
{
if (parent == null) return 0;
return parent.childCount;
}
/// <summary>
/// 检查变换是否有效
/// </summary>
private bool IsTransformValid(Transform t)
{
if (t == null) return false;
// 检查变换是否被销毁
if (t.Equals(null)) return false;
// 检查游戏对象是否有效
if (t.gameObject == null) return false;
return true;
}
/// <summary>
/// 初始化部件
/// </summary>
private void InitializeParts()
{
if (parts.Count == 0) return;
if (debugMode) Debug.Log("开始初始化部件数据");
foreach (PartInfo part in parts)
{
if (part.partTransform == null) continue;
part.assembledWorldPosition = part.partTransform.position;
part.assembledWorldRotation = part.partTransform.rotation;
part.assembledLocalPosition = part.partTransform.localPosition;
part.assembledLocalRotation = part.partTransform.localRotation;
if (debugMode)
{
Debug.Log($"初始化部件: {part.partTransform.name}, " +
$"世界位置: {part.assembledWorldPosition}, " +
$"本地位置: {part.assembledLocalPosition}");
}
}
CalculateDetachedPositions();
isSplit = false;
if (debugMode) Debug.Log("部件初始化完成");
}
/// <summary>
/// 计算拆分位置
/// </summary>
private void CalculateDetachedPositions()
{
if (targetParent == null) return;
Vector3 center = targetParent.position;
for (int i = 0; i < parts.Count; i++)
{
if (parts[i].partTransform == null) continue;
// 获取部件当前位置
Vector3 currentPos = parts[i].assembledWorldPosition;
// 计算从中心到当前位置的方向
Vector3 direction = (currentPos - center).normalized;
// 如果方向是零向量(部件在中心),则使用随机方向
if (direction == Vector3.zero)
{
direction = Random.onUnitSphere;
}
// 计算拆分位置
parts[i].detachedWorldPosition = center + direction * splitDistance;
// 添加高度偏移
parts[i].detachedWorldPosition += Vector3.up * (i % 3) * heightOffset;
// 添加一些随机旋转
Vector3 randomRotation = new Vector3(
Random.Range(-20f, 20f),
Random.Range(-180f, 180f),
Random.Range(-20f, 20f)
);
parts[i].detachedWorldRotation = parts[i].assembledWorldRotation * Quaternion.Euler(randomRotation);
if (debugMode)
{
Debug.Log($"计算拆分位置: {parts[i].partTransform.name}, " +
$"从 {currentPos} 到 {parts[i].detachedWorldPosition}");
}
}
}
/// <summary>
/// 检查是否在冷却中
/// </summary>
private bool IsInCooldown()
{
float timeSinceLastOperation = Time.time - lastOperationTime;
return timeSinceLastOperation < CLICK_COOLDOWN;
}
#endregion
#region
private void OnDestroy()
{
StopCurrentAnimation();
}
#endregion
}