You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity FPS:基于Character Controller的滑铲功能实现求助

基于Character Controller的跑后滑铲实现方案(无需Rigidbody)

针对你现有基于Character Controller的FPS角色控制器,以下是无需Rigidbody的简便滑铲实现,完全复用现有逻辑,改动量小:

核心思路

滑铲本质是奔跑状态下触发的带冲量的蹲伏滑行:按下滑铲键时,立即切换到蹲伏状态,赋予一个高于奔跑速度的初始滑铲冲量,随后逐渐减速,直到滑铲结束或松开滑铲键,最后恢复站立/奔跑状态。


代码修改步骤

1. 添加滑铲相关配置变量

在现有代码对应位置插入以下变量:

[Header("Controls")]
[SerializeField] private KeyCode sprintKey = KeyCode.LeftShift;
[SerializeField] private KeyCode jumpKey = KeyCode.Space;
[SerializeField] private KeyCode crouchKey = KeyCode.C;
[SerializeField] private KeyCode slideKey = KeyCode.LeftControl; // 启用滑铲按键
[SerializeField] private KeyCode zoomKey = KeyCode.Mouse1;

[Header("Movement Parameters")]
[SerializeField] private float walkSpeed = 3.0f;
[SerializeField] private float sprintSpeed = 6.0f;
[SerializeField] private float crouchSpeed = 1.5f;
[SerializeField] private float slopeSpeed = 8f;
[SerializeField] private float slideSpeed = 8.0f; // 滑铲初始速度
[SerializeField] private float slideDuration = 0.5f; // 滑铲持续时间
[SerializeField] private float slideDecay = 4.0f; // 滑铲减速系数

// 滑铲状态变量
private bool isPerformingSlide;
private float slideTimer;
private float currentSlideSpeed;

2. 添加滑铲输入判断

在顶部布尔判断区域新增滑铲触发条件:

private bool shouldSlide => Input.GetKeyDown(slideKey) && isSpritning && characterController.isGrounded && !duringCrouchAnimation && !isPerformingSlide;

3. 新增滑铲处理逻辑

添加HandleSlide函数,并在Update中调用:

private void Update() 
{
    if (canMove)
    {
        HandleMovementInput();
        HandleMouseLook();

        if (canJump)
        {
            HandleJump();
        }

        if (canCrouch)
        {
            HandleCrouch();
        }

        // 新增滑铲处理
        if (canCrouch)
        {
            HandleSlide();
        }

        if (canUseHeadbob)
        {
            HandleHeadbob();
        }

        if (canZoom)
        {
            HandleZoom();
        }

        ApplyFinalMovements();
    }
}

private void HandleSlide()
{
    // 触发滑铲
    if (shouldSlide)
    {
        isPerformingSlide = true;
        slideTimer = slideDuration;
        currentSlideSpeed = slideSpeed;
        // 直接进入蹲伏状态(跳过动画,提升滑铲爽快感)
        isCrouching = true;
        characterController.height = crouchHeight;
        characterController.center = crouchingCenter;
    }

    // 滑铲进行中逻辑
    if (isPerformingSlide)
    {
        slideTimer -= Time.deltaTime;
        // 线性减速
        currentSlideSpeed = Mathf.Lerp(currentSlideSpeed, 0, slideDecay * Time.deltaTime);
        
        // 滑铲结束条件:时间耗尽/松开滑铲键/离开地面
        if (slideTimer <= 0 || Input.GetKeyUp(slideKey) || !characterController.isGrounded)
        {
            isPerformingSlide = false;
            // 头顶无障碍物则自动站起
            if (!Physics.Raycast(playerCamera.transform.position, Vector3.up, 1f))
            {
                isCrouching = false;
                characterController.height = standingHeight;
                characterController.center = standingCenter;
            }
        }
    }
}

4. 修改移动输入逻辑

在HandleMovementInput中优先判断滑铲状态,替换原速度选择逻辑:

private void HandleMovementInput()
{
    // 优先级:滑铲速度 > 蹲伏速度 > 奔跑速度 > 行走速度
    float moveSpeed = isPerformingSlide ? currentSlideSpeed : 
                      isCrouching ? crouchSpeed : 
                      isSpritning ? sprintSpeed : walkSpeed;

    currentInput = new Vector2(moveSpeed * Input.GetAxis("Vertical"),
                               moveSpeed * Input.GetAxis("Horizontal"));

    float moveDirectionY = moveDirection.y;
    moveDirection = (transform.TransformDirection(Vector3.forward) * currentInput.x) + (transform.TransformDirection(Vector3.right) * currentInput.y);
    moveDirection.y = moveDirectionY;
}

5. 修复蹲伏协程冲突

修改CrouchStand协程,避免与滑铲状态冲突:

private IEnumerator CrouchStand()
{
    if(isCrouching && Physics.Raycast(playerCamera.transform.position, Vector3.up, 1f))
    {
        yield break;
    }
    // 滑铲进行中不允许触发蹲伏动画
    if (isPerformingSlide) yield break;
    
    duringCrouchAnimation = true;

    float timeElapsed = 0;
    float targetHeight = isCrouching ? standingHeight : crouchHeight;
    float currentHeight = characterController.height;
    Vector3 targetCenter = isCrouching ? standingCenter : crouchingCenter;
    Vector3 currentCenter = characterController.center;

    isCrouching = !isCrouching;

    while (timeElapsed < timeToCrouch)
    {
        characterController.height = Mathf.Lerp(currentHeight, targetHeight, timeElapsed / timeToCrouch);
        characterController.center = Vector3.Lerp(currentCenter, targetCenter, timeElapsed / timeToCrouch);
        timeElapsed += Time.deltaTime;
        yield return null;
    }

    characterController.height = targetHeight;
    characterController.center = targetCenter;

    duringCrouchAnimation = false;
}

手感调整建议

  • 调大slideSpeed或增加slideDuration可以延长滑铲距离;
  • 提高slideDecay系数会让滑铲更快停止;
  • 滑铲时可在HandleHeadbob中新增滑铲状态判断,使用更急促的头部晃动参数增强反馈。

内容的提问来源于stack exchange,提问作者gitanogamer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 06:57:06