Unity 3D角色在地面Y轴持续抖动的问题求助
Unity 3D角色在地面Y轴持续抖动的问题求助
我在Unity 3D项目里用了MVC架构,写了个CollisionPoller来检测碰撞和处理移动逻辑。但现在遇到个头疼的问题:当同时使用MoveController和CollisionPoller时,角色的Y轴每帧都会有±0.01的抖动。
我试过把刚体设为Is Kinematic,这时候抖动消失了,但角色会直接穿过斜坡;也试过缩小胶囊碰撞体的高度,可一到斜坡上抖动又回来了。
下面是我的代码:
CollisionPoller 代码
public class CollisionPoller { private readonly PlayerView _playerView; private const int MaxBounces = 5; private const float Threshold = 0.015f; private const float MaxSlopeAngle = 45f; private Bounds _bounds; public CollisionPoller(PlayerView playerView) { _playerView = playerView; _bounds = _playerView.Collider.bounds; _bounds.Expand(-2 * Threshold); } public Vector3 CollideAndSlide(Vector3 velocity, Vector3 position, int depth, bool gravityPass, Vector3 velocityInit) { if(depth >= MaxBounces) return Vector3.zero; var distance = velocity.magnitude + Threshold; if (!Physics.SphereCast(position, _bounds.extents.x, velocity.normalized, out var hit, distance)) return velocity; var snapToSurface = velocity.normalized * (hit.distance - Threshold); var leftOver = velocity - snapToSurface; var angle = Vector3.Angle(Vector3.up, hit.normal); if(snapToSurface.magnitude <= Threshold) snapToSurface = Vector3.zero; if (angle <= MaxSlopeAngle) { if(gravityPass) return snapToSurface; leftOver = ProjectAndScale(leftOver, hit.normal); } else { var scale = 1 - Vector3.Dot(new Vector3(hit.normal.x, 0, hit.normal.z).normalized, -new Vector3(velocityInit.x, 0, velocityInit.z).normalized); var isGrounded = Physics.Raycast(_playerView.Transform.position, Vector3.down, _bounds.extents.y + 0.1f); if (isGrounded && !gravityPass) { leftOver = ProjectAndScale(new Vector3(leftOver.x, 0, leftOver.z), new Vector3(hit.normal.x, 0, hit.normal.z)).normalized; leftOver *= scale; } else { leftOver = ProjectAndScale(leftOver, hit.normal) * scale; } } return snapToSurface + CollideAndSlide(leftOver, position + snapToSurface, depth + 1, gravityPass, velocityInit); } private static Vector3 ProjectAndScale(Vector3 vector, Vector3 normal) { var magnitude = vector.magnitude; vector = Vector3.ProjectOnPlane(vector, normal).normalized; vector *= magnitude; return vector; } }
MoveController 代码
public class MoveController : BaseController { private readonly PlayerView _playerView; private readonly GameModel _gameModel; private readonly CollisionPoller _collisionPoller; public MoveController(PlayerView playerView, GameModel gameModel, CollisionPoller collisionPoller) { _playerView = playerView; _gameModel = gameModel; _collisionPoller = collisionPoller; } public void FixedUpdate() { var horizontalInput = Input.GetAxisRaw("Horizontal"); var verticalInput = Input.GetAxisRaw("Vertical"); var direction = new Vector3(horizontalInput, 0, verticalInput).normalized; var moveDirection = _collisionPoller.CollideAndSlide(direction, _playerView.Transform.position, 0, false, direction); moveDirection += _collisionPoller.CollideAndSlide(Vector3.down, _playerView.Transform.position + moveDirection, 0, true, Vector3.down); _playerView.Rigidbody.MovePosition(_playerView.Rigidbody.position + moveDirection * (_gameModel.CurrentPlayer.WalkSpeed * Time.fixedDeltaTime)); } }
备注:内容来源于stack exchange,提问作者lolka
相关产品推荐
相关产品推荐

