Unity自定义移动系统if条件不满足却误执行canMove赋值行问题
1. 检查canMove变量的初始值
如果你的canMove变量是public修饰,或者添加了[SerializeField]特性,Unity Inspector面板中的值会覆盖代码内的初始赋值。哪怕你在代码中写了bool canMove = true,只要Inspector面板中对应的勾选框未选中,运行时canMove默认就是false,直接导致玩家无法移动。
解决方法:运行前检查对应脚本Inspector面板中的canMove勾选状态,确保默认是勾选状态。
2. 修复DetectLedge重复调用的逻辑问题
你当前代码中每次调用DetectLedge()都会重新执行一次物理检测,而Unity物理更新和Update生命周期不同步,可能出现Debug.Log调用时的检测结果为false,但紧接着if判断调用时的检测结果为true的情况:此时if块会执行,canMove被设为false,但下一帧检测结果又变回false,Debug.LogWarning不会持续触发,你就会看到「只有canMove被改、Warning没打印」的假象。
同时你原有代码中没有将canMove复位为true的逻辑,哪怕只触发一次爬边,后续玩家永远无法移动。
解决方法:缓存单次DetectLedge()的检测结果,所有逻辑都用同一份结果,同时补充爬边完成后的复位逻辑:
void HandleLedgeClimbing(bool isEnabled) { if(!isEnabled) return; // 仅调用一次检测,缓存结果 bool[] ledgeInfo = DetectLedge(); Debug.Log(ledgeInfo[0] + " " + ledgeInfo[1] + " " + ledgeInfo[2]); if(ledgeInfo[2]) { Debug.LogWarning("Ledge!"); canMove = false; // 原有爬边逻辑保留 Vector3 calculatedPos = Vector3.zero; RaycastHit hit; Physics.Raycast(upperLedgeDetector.position, Vector3.down, out hit, 3f, 128); calculatedPos = new Vector3(lowerLedgeDetector.position.x, upperLedgeDetector.position.y - hit.distance, lowerLedgeDetector.position.z); if(transform.position != calculatedPos) { transform.position = Vector3.Lerp(transform.position, calculatedPos, Time.deltaTime); } else { // 爬边完成后复位canMove canMove = true; } } }
3. 精准定位canMove的修改来源
如果排查完上述问题还是存在异常,可以给canMove添加带调用栈打印的属性,只要变量被修改就会打印调用栈,直接定位修改来源:
// 把原来的canMove变量替换成这个属性 private bool _canMove = true; public bool canMove { get => _canMove; set { Debug.Log($"canMove被修改为{value},调用栈:\n{System.Environment.StackTrace}"); _canMove = value; } }
4. 清除Unity编译缓存
如果出现代码逻辑和运行表现不符的情况,大概率是Unity编译缓存异常,可以关闭Unity,删除项目根目录下的Library文件夹,重新打开项目等待编译完成后再测试。
内容的提问来源于stack exchange,提问作者Leonardo Poljak

