Unity3D:点击触发器后如何让GameObject单次点击平滑移动到指定位置?
问题描述
需求:点击底部任意小立方体触发器,使对应的大立方体左右平滑移动至屏幕中心。
当前问题:使用Vector3.MoveTowards的脚本点击触发器后,物体仅移动一小段距离,需多次点击才能到达目标位置。希望实现单次点击即可让物体基于帧率平滑移动到目标,项目无需角色或刚体,曾尝试无效的do/while循环,考虑过Coroutine但想寻找更简便的解决方法。
问题原因
原代码将移动逻辑完全放在Input.GetMouseButtonDown(0)的分支中,这个判断仅在鼠标点击的单帧内执行一次,所以每次点击只会让物体移动一帧的距离(speed * Time.deltaTime),无法持续移动到目标位置。
优化方案
添加一个targetPosition变量存储目标位置,点击时仅更新这个目标值,然后在Update的每帧中执行移动逻辑,直到物体到达目标位置。同时优化标签判断逻辑,避免大量重复的if语句。
优化后的代码
public class MoveBoxes : MonoBehaviour { Camera cam; public LayerMask mask; private float speed = 7500f; // 存储目标位置,默认初始位置 private Vector3 targetPosition; // 用字典映射标签到目标位置,替代大量if判断 private Dictionary<string, Vector3> tagToPosition = new Dictionary<string, Vector3>(); void Awake() { cam = Camera.main; // 初始化位置映射 tagToPosition.Add("1stBox", new Vector3(37000.20f, -102.18f, -3919.06f)); tagToPosition.Add("2ndBox", new Vector3(27000.20f, -102.18f, -3919.06f)); tagToPosition.Add("3rdBox", new Vector3(17000.20f, -102.18f, -3919.06f)); tagToPosition.Add("4thBox", new Vector3(7000.20f, -102.18f, -3919.06f)); tagToPosition.Add("5thBox", new Vector3(-3000.20f, -102.18f, -3919.06f)); tagToPosition.Add("6thBox", new Vector3(-13000.20f, -102.18f, -3919.06f)); tagToPosition.Add("7thBox", new Vector3(-23000.20f, -102.18f, -3919.06f)); tagToPosition.Add("8thBox", new Vector3(-33000.20f, -102.18f, -3919.06f)); tagToPosition.Add("9thBox", new Vector3(-43000.20f, -102.18f, -3919.06f)); tagToPosition.Add("10thBox", new Vector3(-53000.20f, -102.18f, -3919.06f)); tagToPosition.Add("11thBox", new Vector3(-63000.20f, -102.18f, -3919.06f)); tagToPosition.Add("12thBox", new Vector3(-73000.20f, -102.18f, -3919.06f)); tagToPosition.Add("13thBox", new Vector3(-83000.20f, -102.18f, -3919.06f)); tagToPosition.Add("14thBox", new Vector3(-93000.20f, -102.18f, -3919.06f)); // 初始目标位置设为当前物体位置 targetPosition = transform.position; Debug.Log(transform.position); } void Update() { float moveStep = speed * Time.deltaTime; // 每帧执行移动,直到到达目标位置 if (transform.position != targetPosition) { transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveStep); Debug.Log(transform.position); } // 处理点击逻辑,仅更新目标位置 if (Input.GetMouseButtonDown(0)) { Ray ray = cam.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 15000, mask)) { string hitTag = hit.collider.tag; // 如果标签在映射字典中,更新目标位置 if (tagToPosition.ContainsKey(hitTag)) { targetPosition = tagToPosition[hitTag]; } } } } }
关键改进点
- 分离点击逻辑和移动逻辑:点击仅设置目标位置,移动逻辑在每帧Update中执行,保证持续平滑移动
- 使用
Dictionary替代大量重复的if判断,让代码更简洁易维护 - 初始时将
targetPosition设为物体当前位置,避免初始状态下的不必要移动
内容的提问来源于stack exchange,提问作者Eski Stoj
相关产品推荐
相关产品推荐

