Unity 3D。我的性格表面上在颤抖

问题描述 投票:0回答:1

我在 Unity 3D 项目中使用 MVC。我有 CollisionPoller 来确定接触和移动。如果我使用 MoveController 和 CollisionPoller,我的角色每帧每 +/- 0.01 都会晃动 Y 轴。 如果我使用“Is kinematic”,它是有效的,但我的角色会穿过斜坡。我可以降低胶囊对撞机的高度,但它在斜坡上不起作用(我的角色再次摇晃)。

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;
    }
}
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));    
    }
}
c# unity-game-engine collision-detection
1个回答
0
投票

我不完全理解你的代码示例。但我怀疑你正在捕捉到表面,但对撞机与表面的对撞机稍微重叠。

这种碰撞会导致物体想要彼此远离,因为它们正在碰撞。所以它又开始离开了。

但是当它移开时,它就在你的捕捉距离之内,所以它会再次保持向下状态。如此重复,导致抖动。

当您捕捉时,您可能想要关闭该对象的物理特性(您通过 iskinematic 注意到这一点),然后当需要停止捕捉时,一旦该对象足够远而不会引起任何奇怪的碰撞,您就可以重新打开物理特性。

© www.soinside.com 2019 - 2024. All rights reserved.