Files
2026-07-08 20:42:51 +08:00

102 lines
3.7 KiB
C#

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<Rigidbody>();
ItemPhysicsState physicsState = currentModel.GetComponent<ItemPhysicsState>();
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<Collider>();
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 有一种弹出来的动感
}
}