using System.Collections.Generic; using DG.Tweening; using UnityEngine; public class EnhancedModelExploder : MonoBehaviour { [Header("爆炸效果设置")] [SerializeField] private float explodeStrength = 2.5f; [SerializeField] private float animationDuration = 1.5f; [SerializeField] private Ease easeType = Ease.OutBack; [Header("随机效果设置")] [SerializeField] private float rotationRandomness = 180f; [SerializeField] private float positionRandomness = 0.3f; [SerializeField] private float depthMultiplier = 0.5f; [Header("调试选项")] [SerializeField] private bool debugMode = false; [SerializeField] private Color debugColor = Color.cyan; private class TransformData { public Vector3 localPosition; public Quaternion localRotation; public Vector3 localScale; public Transform parent; public int depth; } private Dictionary originalTransforms = new Dictionary(); private bool isInitialized = false; private bool isExploded = false; private void CollectAllChildrenRecursive(Transform current, int currentDepth = 0) { if (current == this.transform && currentDepth == 0) { } else { originalTransforms[current] = new TransformData { localPosition = current.localPosition, localRotation = current.localRotation, localScale = current.localScale, parent = current.parent, depth = currentDepth }; } for (int i = 0; i < current.childCount; i++) { Transform child = current.GetChild(i); CollectAllChildrenRecursive(child, currentDepth + 1); } } private void InitializeTransforms(Transform modelRoot) { if (isInitialized) return; originalTransforms.Clear(); CollectAllChildrenRecursive(modelRoot, 0); if (debugMode) { Debug.Log($"已收集 {originalTransforms.Count} 个子物体的变换数据"); foreach (var kvp in originalTransforms) { Debug.Log($"物体: {kvp.Key.name}, 深度: {kvp.Value.depth}, 父物体: {kvp.Value.parent?.name ?? "null"}"); } } isInitialized = true; } public void ToggleExplode(Transform modelRoot, bool shouldExplode) { if (modelRoot == null) { Debug.LogWarning("模型根节点为空!"); return; } Debug.Log($"{isExploded}_{shouldExplode}_{isInitialized}"); if (isExploded != shouldExplode) { if (shouldExplode) { Debug.Log($"正在展开模型: {modelRoot.name}"); ExplodeModel(modelRoot); } else { Debug.Log($"正在折叠模型: {modelRoot.name}"); CollapseModel(modelRoot); } isExploded = shouldExplode; } } private void ExplodeModel(Transform modelRoot) { InitializeTransforms(modelRoot); int processedCount = 0; foreach (var kvp in originalTransforms) { Transform child = kvp.Key; TransformData data = kvp.Value; if (child == modelRoot) continue; Vector3 explodeDirection = CalculateExplodeDirection(child, modelRoot, data); float depthFactor = 1f + (data.depth * depthMultiplier); Vector3 targetPosition = data.localPosition + explodeDirection * explodeStrength * depthFactor; Vector3 randomOffset = Random.insideUnitSphere * positionRandomness; targetPosition += randomOffset; Transform originalParent = child.parent; if (child.parent != modelRoot) { child.SetParent(modelRoot, true); } child.DOLocalMove(targetPosition, animationDuration) .SetEase(easeType) .OnStart(() => { if (debugMode) { Debug.Log($"开始展开: {child.name}, 深度: {data.depth}, 目标位置: {targetPosition}"); } }); Vector3 randomRotation = new Vector3( Random.Range(-rotationRandomness, rotationRandomness), Random.Range(-rotationRandomness, rotationRandomness), Random.Range(-rotationRandomness, rotationRandomness) ); child.DOLocalRotate(child.localEulerAngles + randomRotation, animationDuration, RotateMode.LocalAxisAdd) .SetEase(Ease.OutQuad); child.DOScale(data.localScale * 1.1f, animationDuration * 0.5f) .SetLoops(2, LoopType.Yoyo) .SetEase(Ease.InOutSine); processedCount++; } if (debugMode) { Debug.Log($"已处理 {processedCount} 个子物体的爆炸动画"); } } private Vector3 CalculateExplodeDirection(Transform child, Transform modelRoot, TransformData data) { Vector3 directionFromCenter = (child.position - modelRoot.position).normalized; Vector3 directionFromParent = Vector3.zero; if (data.parent != null && data.parent != modelRoot) { directionFromParent = (child.position - data.parent.position).normalized; } Vector3 forwardDirection = child.forward; Vector3 finalDirection = directionFromCenter; if (directionFromCenter.magnitude < 0.1f) { finalDirection = forwardDirection; } if (directionFromParent.magnitude > 0.1f) { finalDirection = (finalDirection + directionFromParent * 0.5f).normalized; } if (finalDirection.magnitude < 0.01f) { finalDirection = Vector3.up + Random.insideUnitSphere * 0.5f; } return finalDirection.normalized; } private void CollapseModel(Transform modelRoot) { if (!isInitialized) return; int processedCount = 0; foreach (var kvp in originalTransforms) { Transform child = kvp.Key; TransformData data = kvp.Value; if (child == modelRoot) continue; child.DOKill(); if (child.parent != data.parent) { child.SetParent(data.parent, true); } child.DOLocalMove(data.localPosition, animationDuration) .SetEase(easeType) .OnStart(() => { if (debugMode) { Debug.Log($"开始合并: {child.name}, 目标位置: {data.localPosition}"); } }); child.DOLocalRotateQuaternion(data.localRotation, animationDuration) .SetEase(Ease.InOutQuad); child.DOScale(data.localScale, animationDuration) .SetEase(Ease.InOutSine); processedCount++; } if (debugMode) { Debug.Log($"已处理 {processedCount} 个子物体的合并动画"); } } public void Explode(Transform modelRoot) { ToggleExplode(modelRoot, true); } public void Collapse(Transform modelRoot) { ToggleExplode(modelRoot, false); } public void ResetImmediately(Transform modelRoot) { if (!isInitialized) return; foreach (var kvp in originalTransforms) { Transform child = kvp.Key; TransformData data = kvp.Value; child.DOKill(); if (child.parent != data.parent) { child.SetParent(data.parent, false); } child.localPosition = data.localPosition; child.localRotation = data.localRotation; child.localScale = data.localScale; } isExploded = false; if (debugMode) { Debug.Log($"已立即重置 {originalTransforms.Count} 个子物体的变换"); } } private void OnDrawGizmosSelected() { if (!debugMode || !isExploded) return; foreach (var kvp in originalTransforms) { Transform child = kvp.Key; TransformData data = kvp.Value; if (child == null || data == null) continue; Vector3 originalWorldPos = data.parent != null ? data.parent.TransformPoint(data.localPosition) : data.localPosition; Gizmos.color = debugColor; Gizmos.DrawLine(originalWorldPos, child.position); Gizmos.DrawWireCube(child.position, Vector3.one * 0.1f); Gizmos.color = Color.red; Gizmos.DrawSphere(originalWorldPos, 0.05f); } } [ContextMenu("测试爆炸效果")] public void TestExplosion() { if (Application.isPlaying) { Explode(this.transform); } else { Debug.Log("请在运行模式下测试爆炸效果"); } } [ContextMenu("测试合并效果")] public void TestCollapse() { if (Application.isPlaying) { Collapse(this.transform); } else { Debug.Log("请在运行模式下测试合并效果"); } } [ContextMenu("立即重置")] public void TestReset() { ResetImmediately(this.transform); } }