You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:45:48