Unity制作避障球类游戏时小球提速后抖动、减速、相机无法追踪的求助
Unity躲避类小球运动异常问题排查
问题背景
- 项目为小球躲避障碍物的休闲游戏,初始设计为每3秒提升一次小球移动速度
- 已完成基础调试,游戏前期运行正常
- 已尝试排查项:为所有游戏对象添加物理材质,将摩擦参数全部设为0,抖动问题无改善
异常表现
- 游戏运行至中途,小球出现高频抖动
- 小球实际前进速度不升反降
- 跟随相机无法匹配小球的移动节奏
挂载于小球的PlayerController核心代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class PlayerController : MonoBehaviour { public Text gameOverText; public Text scoreText; public bool isGameOver; public float speeder; public float Score; Touch touch; public float speedmodifier ; public float speed = 5; private void Awake() { isGameOver = false; Score = 0; if(PlayerPrefs.GetFloat("HighScore") == 0) { PlayerPrefs.SetFloat("HighScore", 0); } PlayerPrefs.SetFloat("Score", Score); } void Start() { speeder = 4f; gameOverText.enabled = false; speedmodifier = 0.01f; } void Update() { if(speeder >= 0) { speeder -= Time.deltaTime; } if (speeder <= 0 && speed < 50) { speed++; speeder = 4f; } Debug.Log(speed); if (isGameOver == false) { Score++; } scoreText.text = "Score : " + Score ; if (Input.touchCount > 0 && transform.position.x >= -3.5f && transform.position.x <= 3.5f) { touch = Input.GetTouch(0); transform.Translate(touch.deltaPosition.x * speedmodifier, 0, 0); } else if(transform.position.x > 3.5f) { transform.position = new Vector3(3.49f, transform.position.y, transform.position.z); } else if(transform.position.x < -3.5f) { transform.position = new Vector3(-3.49f, transform.position.y, transform.position.z); } if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 3.5f) { transform.Translate(Vector3.right * speed * Time.deltaTime); } if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x > -3.5f) { transform.Translate(Vector3.left * speed * Time.deltaTime); } transform.Translate(Vector3.forward * speed * Time.deltaTime); } private void OnTriggerEnter(Collider other) { if(other.gameObject.tag == "enemy") { isGameOver = true; StartCoroutine("Wait"); GetComponent<MeshRenderer>().enabled = false; gameObject.GetComponentInChildren<TrailRenderer>().enabled = false; gameOverText.enabled = true; if(PlayerPrefs.GetFloat("HighScore") < Score) { PlayerPrefs.SetFloat("HighScore", Score); PlayerPrefs.SetFloat("Score", Score); } else { PlayerPrefs.SetFloat("Score", Score); } } } IEnumerator Wait() { Debug.Log(" My HighScore is : " + PlayerPrefs.GetFloat("HighScore")); Debug.Log(" Score is : " + PlayerPrefs.GetFloat("Score")); yield return new WaitForSeconds(3f); SceneManager.LoadScene(1); } }
问题根因
- 运动逻辑与物理管线冲突:所有位移计算全部写在Update()中,且通过
Transform.Translate直接修改坐标。当小球速度随时间升高后,单帧位移量变大,直接改坐标的操作会和物理引擎的刚体模拟产生执行顺序冲突,触发抖动;单帧位移量超过碰撞体连续检测阈值时,还会出现碰撞穿透、卡滞,导致实际前进速度下降。 - 逐帧日志拉低性能:代码在每帧的Update中调用
Debug.Log(speed),随着运行时间变长,日志输出量累积,会占用大量主线程性能,导致帧率下降,进而出现移动速度不升反降、相机跟不上的问题。 - 边界逻辑触发反复强制位移:当小球X坐标超出±3.5范围时,代码每帧都会强制把坐标拉回3.49/-3.49的位置,和横向输入的位移计算叠加时,会让坐标在阈值边界反复横跳,进一步放大抖动。
- 加速逻辑与设计不符:原设计为每3秒提速一次,实际代码中计时器重置值为4秒,和预期的提速节奏存在偏差。
- 相机跟随逻辑错配:如果相机是在LateUpdate中跟随Transform的位置,会同步放大Transform的抖动,且固定平滑系数无法适配逐渐升高的移动速度,出现跟不上的问题。
修复方案
- 所有涉及移动、碰撞的逻辑全部从
Update()迁移到FixedUpdate()中执行,匹配物理引擎的固定执行步长 - 移除所有
Transform.Translate的位移调用,改用挂载的Rigidbody组件设置速度的方式控制移动,避免直接修改坐标和物理模拟的冲突 - 移除运行时的逐帧
Debug.Log日志输出,避免不必要的性能开销 - 边界判定改为在输入位移计算阶段就做范围截断,不在坐标位置上做每帧强制拉回,避免边界抖动
- 将提速计时器的重置值调整为3f,匹配“每3秒提速一次”的设计
- 相机跟随改为基于Rigidbody的位置做插值平滑,调整平滑系数适配动态升高的移动速度
内容的提问来源于stack exchange,提问作者vikram
相关产品推荐
相关产品推荐

