using UnityEngine; using Inventory; using DG.Tweening; // 引入 DOTween using Project.Interaction; public class HandController : MonoBehaviour { [Header("配置")] [Tooltip("拖入摄像机下的 HandHolder 物体")] public Transform handPosition; [Tooltip("切换物品的动画时长")] public float animationDuration = 0.25f; [Tooltip("物品收起时的位移偏移量")] public Vector3 hiddenOffset = new Vector3(0, -1.0f, 0); private GameObject currentModel; private Tween currentTween; // 记录当前的动画,防止冲突 // 供外部调用:切换物品 public void EquipItem(ItemData item) { // 如果正在播放动画,先杀掉 if (currentTween != null && currentTween.IsActive()) currentTween.Kill(); // 1. 如果手里有东西,先收起来 if (currentModel != null) { // 向下移动,并在完成后销毁 currentModel.transform.DOLocalMove(hiddenOffset, animationDuration) .SetEase(Ease.InBack) // 回收时用 InBack 更有感觉 .OnComplete(() => { Destroy(currentModel); currentModel = null; // 旧的收完了,再生成新的 SpawnNewItem(item); }); } else { // 手里本来就是空的,直接生成新的 SpawnNewItem(item); } } private void SpawnNewItem(ItemData item) { if (item == null || item.handModelPrefab == null) return; // 生成新模型 currentModel = Instantiate(item.handModelPrefab, handPosition); // 自动清理物理组件(防止手持物品掉落或把玩家挤飞) // 1. 关闭 Rigidbody 物理影响 Rigidbody rb = currentModel.GetComponent(); ItemPhysicsState physicsState = currentModel.GetComponent(); if (rb != null) { if (physicsState != null) { Debug.LogWarning($"{nameof(HandController)} 检测到手持模型带有 {nameof(ItemPhysicsState)}(通常依赖 Rigidbody)。已保留 Rigidbody 并关闭其物理影响,避免运行时报错。", currentModel); physicsState.enabled = false; } rb.isKinematic = true; rb.useGravity = false; rb.detectCollisions = false; rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } // 2. 禁用所有 Collider Collider[] cols = currentModel.GetComponentsInChildren(); foreach (var c in cols) c.enabled = false; // 3. (可选) 将层级设置为 "Player" 或 "Weapon" 防止穿模,如果需要的话 // SetLayerRecursively(currentModel, LayerMask.NameToLayer("FirstPerson")); // 初始位置设在“下面” Vector3 targetPos = Vector3.zero; Quaternion targetRot = Quaternion.identity; Vector3 targetScale = Vector3.one; if (item.useCustomHoldSettings) { targetPos = item.holdPositionOffset; targetRot = Quaternion.Euler(item.holdRotationOffset); targetScale = item.holdScale; } currentModel.transform.localScale = targetScale; currentModel.transform.localPosition = hiddenOffset; // 依然从隐藏位置开始 currentModel.transform.localRotation = targetRot; // 2. 播放“掏出来”动画 currentTween = currentModel.transform.DOLocalMove(targetPos, animationDuration) .SetEase(Ease.OutBack); // 掏出时用 OutBack 有一种弹出来的动感 } }