Unity中Vector.Lerp瞬移问题:UFO吸牛效果无法渐进实现
问题分析与解决方案
核心问题拆解
你的代码出现"瞬间吸牛"的问题,主要是这几个关键错误导致的:
- 跨帧状态丢失:
startTime在Update内定义,每帧都会被重置为当前时间,导致进度计算完全失效。 - Lerp方向搞反:你要把牛吸向UFO,但代码里是从UFO位置 lerp到牛的位置,方向完全颠倒。
- 进度计算公式错误:
distCovered = (Time.time - startTime * speed)的括号位置错误,正确逻辑应该是(Time.time - startTime) * speed。 - 重复加分:每帧都调用
PointManager(1),会瞬间刷出大量分数。 - 条件逻辑优先级错误:原判断条件会导致
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
相关产品推荐
相关产品推荐

