Unity OnMouseDown()实现点击3D物体平滑动画问题求助
代码问题定位
你的代码实现不了平滑移动的核心原因有3个:
OnMouseDown()是鼠标点击时仅触发一次的生命周期方法,你把位移逻辑全写在这里,哪怕加了moveSpeed * Time.deltaTime,也只会在点击的那一帧移动极短的距离,根本不会产生持续的平滑移动效果。- 位移逻辑不一致:打开逻辑里只有
top部件乘了速度系数,board和bottom还是直接瞬移到终点;关闭逻辑里三个部件全是直接执行全量位移,完全没有过渡。 - 状态切换时机错误:点击瞬间就直接修改
isOpen状态,没有等部件移动到终点就切换状态,会导致后续点击判断逻辑混乱。 - 附带小问题:打开电池的方法里打印的日志是
"Close",和实际功能不匹配,调试的时候会误导判断。
最小改动可运行方案
你现在优先要跑通核心功能的话,用协程做逐帧插值是改动量最小的方案,不用重构现有逻辑结构,改完的完整代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class OpenBattery : MonoBehaviour { [SerializeField] float moveSpeed = 2f; // 原0.05数值过小,调整为2左右可获得正常移动速度,可按需修改 [SerializeField] GameObject top; [SerializeField] GameObject board; [SerializeField] GameObject cells; [SerializeField] GameObject bottom; public bool isOpen = false; public ExtendCells extendCells; private bool isMoving = false; // 移动中锁,防止移动过程中重复点击导致位置错乱 void OnMouseDown() { if (isMoving) return; if (!isOpen) { StartCoroutine(OpenBatteryCaseCoroutine()); } else if (isOpen && !extendCells.isExtended) { StartCoroutine(CloseBatteryCaseCoroutine()); } } private IEnumerator CloseBatteryCaseCoroutine() { isMoving = true; // 缓存每个部件的起点和终点位置 Vector3 topStart = top.transform.position; Vector3 topTarget = top.transform.position + new Vector3(-0.99f, 0f, 0f); Vector3 boardStart = board.transform.position; Vector3 boardTarget = board.transform.position + new Vector3(-0.68f, 0f, 0f); Vector3 bottomStart = bottom.transform.position; Vector3 bottomTarget = bottom.transform.position + new Vector3(0.79f, 0f, 0f); float progress = 0f; // 逐帧插值直到移动到终点 while (progress < 1f) { progress += Time.deltaTime * moveSpeed; top.transform.position = Vector3.Lerp(topStart, topTarget, progress); board.transform.position = Vector3.Lerp(boardStart, boardTarget, progress); bottom.transform.position = Vector3.Lerp(bottomStart, bottomTarget, progress); yield return null; } isOpen = false; isMoving = false; } private IEnumerator OpenBatteryCaseCoroutine() { isMoving = true; Debug.Log("Open"); // 修正原日志打印错误 Vector3 topStart = top.transform.position; Vector3 topTarget = top.transform.position + new Vector3(0.99f, 0f, 0f); Vector3 boardStart = board.transform.position; Vector3 boardTarget = board.transform.position + new Vector3(0.68f, 0f, 0f); Vector3 bottomStart = bottom.transform.position; Vector3 bottomTarget = bottom.transform.position + new Vector3(-0.79f, 0f, 0f); float progress = 0f; while (progress < 1f) { progress += Time.deltaTime * moveSpeed; top.transform.position = Vector3.Lerp(topStart, topTarget, progress); board.transform.position = Vector3.Lerp(boardStart, boardTarget, progress); bottom.transform.position = Vector3.Lerp(bottomStart, bottomTarget, progress); yield return null; } isOpen = true; isMoving = false; } }
补充说明
- 代码里用
Vector3.Lerp做线性插值,moveSpeed参数和移动耗时成反比:值为1时全程移动耗时1秒,值为2时耗时0.5秒,你可以根据实际效果调整到满意的数值。 - 原代码中空的
Start()和Update()方法如果后续没有逻辑要写,可以直接删掉,不影响功能运行。 - 等核心功能跑通之后,你可以再抽离公共的移动逻辑、统一配置每个部件的移动偏移量,减少重复代码做优化。
内容的提问来源于stack exchange,提问作者Tokatoey
相关产品推荐
相关产品推荐

