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

Unity中Vector.Lerp瞬移问题:UFO吸牛效果无法渐进实现

问题分析与解决方案

核心问题拆解

你的代码出现"瞬间吸牛"的问题,主要是这几个关键错误导致的:

  1. 跨帧状态丢失:startTime在Update内定义,每帧都会被重置为当前时间,导致进度计算完全失效。
  2. Lerp方向搞反:你要把牛吸向UFO,但代码里是从UFO位置 lerp到牛的位置,方向完全颠倒。
  3. 进度计算公式错误:distCovered = (Time.time - startTime * speed)的括号位置错误,正确逻辑应该是(Time.time - startTime) * speed。
  4. 重复加分:每帧都调用PointManager(1),会瞬间刷出大量分数。
  5. 条件逻辑优先级错误:原判断条件会导致Cow2标签的物体即使是Jet也会被触发。

修改后的完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TractorBeam : MonoBehaviour
{
    private bool tractorBeamEnabled = false;
    public GameObject tractorBeam;
    // 新增跨帧状态变量
    private GameObject currentAbductingCow;
    private float abductStartTime;
    public float abductSpeed = 2f; // 可调整的吸牛速度
    private bool hasGivenPoints = false;

    public void StopTractorBeam(bool death)
    {
        if (death)
        {
            Destroy(GameObject.FindWithTag("TractorBeam"));
        }
    }

    void Start()
    {
        currentAbductingCow = null;
        hasGivenPoints = false;
    }

    void Update()
    {
        // 默认关闭牵引光束
        tractorBeam.GetComponent<Renderer>().enabled = false;

        if (Input.GetKey(KeyCode.Space))
        {
            tractorBeamEnabled = true;
            tractorBeam.GetComponent<Renderer>().enabled = true;

            RaycastHit raycastHit;
            if (Physics.Raycast(transform.position, Vector3.down, out raycastHit, Mathf.Infinity))
            {
                bool isTargetCow = raycastHit.collider.tag == "Cow1" || raycastHit.collider.tag == "Cow2";
                // 修正条件优先级,确保非Jet且是牛才触发
                if (raycastHit.collider.tag != "Jet" && isTargetCow)
                {
                    // 初始化吸牛状态
                    if (currentAbductingCow == null)
                    {
                        currentAbductingCow = raycastHit.collider.gameObject;
                        abductStartTime = Time.time;
                        hasGivenPoints = false;
                        Debug.Log("开始吸牛");
                    }

                    // 仅首次检测时加分
                    if (!hasGivenPoints)
                    {
                        FindObjectOfType<GameManager>().PointManager(1);
                        hasGivenPoints = true;
                    }

                    // 用MoveTowards实现匀速移动(比Lerp更适合这个场景)
                    Vector3 ufoBottomPos = new Vector3(transform.position.x, transform.position.y - 1f, transform.position.z);
                    currentAbductingCow.transform.position = Vector3.MoveTowards(
                        currentAbductingCow.transform.position, 
                        ufoBottomPos, 
                        abductSpeed * Time.deltaTime
                    );

                    // 检测是否到达目标位置,完成吸牛
                    if (Vector3.Distance(currentAbductingCow.transform.position, ufoBottomPos) < 0.1f)
                    {
                        Destroy(currentAbductingCow);
                        currentAbductingCow = null;
                        hasGivenPoints = false;
                    }
                }
            }
        }
        else
        {
            // 松开空格重置吸牛状态
            currentAbductingCow = null;
            hasGivenPoints = false;
        }
    }
}

关键修改说明

  • 跨帧状态保存:用类成员变量currentAbductingCow和abductStartTime保存吸牛的状态,避免每帧重置。
  • 替换移动方法:用Vector3.MoveTowards替代Lerp,它更适合匀速移动的场景,无需手动计算进度,减少出错概率。
  • 修正条件逻辑:用括号明确优先级,确保只有非Jet的牛才会被吸起。
  • 优化加分逻辑:仅在开始吸牛时加一次分,避免重复触发。
  • 到达检测:当牛接近UFO底部时销毁,完成吸牛流程。

新手建议

  • 不要在Update内定义需要跨帧保留的变量,这类变量要放在类的成员位置。
  • 复杂条件一定要用括号明确优先级,避免因运算符优先级导致逻辑错误。
  • 调试时多打印关键变量(比如进度值、位置坐标),能快速定位问题。
  • 移动类需求优先选择合适的API:匀速移动用MoveTowards,平滑插值用Lerp,物理移动用AddForce。

内容的提问来源于stack exchange,提问作者George Rees

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:27:23