自定义PingPong函数逻辑咨询:为何无法实现对象路点往返移动?
拆解你的代码逻辑&解决往返移动问题
让我帮你理清这段代码到底在做什么,以及为什么它没达到你想要的两个路点往返效果。
首先先看你的两个方法,先从Modulus开始:
private int Modulus(int baseNumber, int modulus) { return (modulus == 0)? baseNumber : baseNumber - modulus * (int)Mathf.Floor(baseNumber / (float)modulus); }
这个方法其实是实现了支持负数的非负取模运算——Unity自带的%运算符处理负数时会返回负数结果,而这个方法会返回0到modulus-1之间的非负余数。比如Modulus(-1, 5)会返回4,而原生-1 % 5在C#里是-1,这是它和原生取模的核心区别。
接下来是核心的PingPong方法:
private int PingPong(int baseNumber, int limit) { if (limit < 2) return 0; return limit - Mathf.Abs(limit - Modulus(baseNumber, limit + (limit - 2)) - 1) - 1; }
我们先简化里面的模运算参数:limit + (limit - 2)等于2*limit -2。把逻辑拆解开就是:
- 先把
baseNumber对2*limit -2取模,得到[0, 2*limit-3]范围内的非负整数 - 计算
limit - 取模结果 -1并取绝对值,再用limit减去这个绝对值后减1
我们代入具体值测试更直观:
- 当
limit=2(对应两个路点索引0和1):- baseNumber=0 → 返回0
- baseNumber=1 → 返回1
- baseNumber=2 → 返回0
- baseNumber=3 → 返回1
- 以此循环,确实是
0→1→0→1的往返序列
那为什么你觉得没实现?可能的问题点:
- 你是不是把
limit设错了?比如两个路点你设成了路点的最大索引(比如路点是0和5,你把limit设成5),这会导致返回的索引范围是0-4,完全没覆盖到5这个路点 - 你有没有正确把返回的索引对应到路点?比如你的路点数组长度不对,或者调用
PingPong时baseNumber没有持续递增(比如没在Update里累加步数/时间) - 这个方法返回的是整数索引,如果你要的是平滑移动(不是瞬间跳转),它只能给你切换的节点信号,还需要配合插值逻辑才能实现连续移动
更简单的两个路点往返实现
如果是要平滑往返,直接用Unity原生的Mathf.PingPong就足够了,不用自己造轮子:
public Transform waypointA; public Transform waypointB; public float moveSpeed = 2f; private void Update() { // 生成0~1之间的往返值,控制从A到B的插值比例 float lerpRatio = Mathf.PingPong(Time.time * moveSpeed, 1f); // 插值得到当前位置 transform.position = Vector3.Lerp(waypointA.position, waypointB.position, lerpRatio); }
这个代码会让对象以moveSpeed的速度在两个路点之间平滑往返,逻辑清晰还不容易出错。
如果是要瞬间跳转式的往返,你的代码调整后也能用:
private int stepCounter = 0; public Transform[] waypoints; // 确保数组长度为2 private void Update() { // 比如每2秒切换一次路点 if (Time.time % 2f < 0.05f) { stepCounter++; int targetIndex = PingPong(stepCounter, 2); transform.position = waypoints[targetIndex].position; } }
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

