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

Unity滑动动画无法停止问题求助:StartCoroutine异常排查

Unity角色控制器滑动功能问题排查与修复

问题描述

按下空格键触发滑动动画后出现两个异常:

  • 滑动动画无法自动停止
  • 滑动启动时角色速度没有变化
    怀疑问题出在第137行的StartCoroutine()调用中,此前滑动功能为独立脚本,集成到PlayerController后出现该问题。

原代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public bool isSliding = false;

    public CapsuleCollider2D regularColl;
    public CapsuleCollider2D slideColl;

    SpriteRenderer rend;
    public float movementSpeed = 3.0f;
    Vector2 movement = new Vector2();
    Rigidbody2D rigidbody2D;
    [SerializeField] float normalSpeed, runSpeed, crouchSpeed, slideSpeed;

    Animator animator;

    void Start()
    {
        rend = GetComponent<SpriteRenderer>();
        animator = GetComponent<Animator>();
        rigidbody2D = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
        UpdateState();
        if (Input.GetKeyDown(KeyCode.Space))
            prefromSlide();
    }

    private void FixedUpdate()
    {
        MoveCharacter();
        
    }

    private void MoveCharacter()
    {
        movement.x = Input.GetAxisRaw("Horizontal");
        movement.y = Input.GetAxisRaw("Vertical");

        if (movement.x > 0)
        {
            rend.flipX = true;
        }
        else if (movement.x < 0)
        {
            rend.flipX = false;
        }
        
        rigidbody2D.velocity  = movement.normalized * movementSpeed;
        Vector3 moveDir = (Vector3.forward * movement.y) + (Vector3.right * movement.x);
    }

    private void UpdateState()
    {
        //걷기
        if (Mathf.Approximately(movement.x, 0) && Mathf.Approximately(movement.y, 0))
        {
            animator.SetBool("isMove", false);
        }
        else
        {
            animator.SetBool("isMove", true);
        }


        //달리기
        if (Input.GetKey(KeyCode.LeftShift))
        {
            movementSpeed = runSpeed;
            animator.SetBool("isRun", true);
        }
        else if (Input.GetKey(KeyCode.LeftControl))
        {
            movementSpeed = crouchSpeed;
            animator.SetBool("isCrouch", true);
        }
        else
        {
            movementSpeed = normalSpeed;
            animator.SetBool("isRun", false);

            movementSpeed = normalSpeed;
            animator.SetBool("isCrouch", false);
        }


        //대기상태 x방향 설정
        if (movement.x > 0)
        {
            animator.SetFloat("horIdle", 1);
            animator.SetFloat("verIdle", 0);
        }
        else if (movement.x < 0)
        {
            animator.SetFloat("horIdle", -1);
            animator.SetFloat("verIdle", 0);
        }


        //대기상태 y방향 설정
        if (movement.y > 0)
        {
            animator.SetFloat("verIdle", 1);
            animator.SetFloat("horIdle", 0);
        }
        else if (movement.y < 0)
        {
            animator.SetFloat("verIdle", -1);
            animator.SetFloat("horIdle", 0);
        }

        animator.SetFloat("horizontal", movement.x);
        animator.SetFloat("vertical", movement.y);

        
    }

    private void prefromSlide(){
        isSliding = true;

        animator.SetBool ("isSlide", true);

        regularColl.enabled = false;
        slideColl.enabled = true;

        if (!rend.flipX) {
            GetComponent<Rigidbody>().AddForce (Vector2.right * slideSpeed);
        }   else{
            GetComponent<Rigidbody>().AddForce (Vector2.left * slideSpeed);
        }

        StartCoroutine (stopSlide());
    }

    IEnumerator stopSlide(){
        yield return new WaitForSeconds (0.8f);
    
        animator.SetBool ("isSlide", false);

        regularColl.enabled = true;
        slideColl.enabled = false;
        isSliding = false;
    }

    
}

问题根源分析

  1. 滑动速度无效:代码错误调用GetComponent<Rigidbody>()获取3D刚体,但角色使用的是Rigidbody2D,导致加力逻辑完全不执行;同时MoveCharacter()方法每次FixedUpdate都会重置速度,直接覆盖滑动加力效果。
  2. 滑动动画无法停止:UpdateState()方法未判断isSliding状态,会在滑动过程中持续修改其他动画参数,干扰滑动动画的状态;且未限制重复触发滑动,连续按空格会多次启动协程,导致状态混乱。

修复方案

1. 修正刚体组件调用

将prefromSlide中的3D刚体调用改为已初始化的Rigidbody2D对象,同时添加重复触发限制:

private void prefromSlide(){
    if (isSliding) return; // 防止重复触发
    isSliding = true;

    animator.SetBool ("isSlide", true);

    regularColl.enabled = false;
    slideColl.enabled = true;

    // 使用已获取的Rigidbody2D组件
    if (!rend.flipX) {
        rigidbody2D.AddForce(Vector2.right * slideSpeed);
    }   else{
        rigidbody2D.AddForce(Vector2.left * slideSpeed);
    }

    StartCoroutine (stopSlide());
}

2. 避免移动逻辑覆盖滑动速度

在MoveCharacter()中添加isSliding判断,滑动时不重置速度:

private void MoveCharacter()
{
    movement.x = Input.GetAxisRaw("Horizontal");
    movement.y = Input.GetAxisRaw("Vertical");

    if (movement.x > 0)
    {
        rend.flipX = true;
    }
    else if (movement.x < 0)
    {
        rend.flipX = false;
    }

    // 滑动状态下不覆盖速度
    if (!isSliding)
    {
        rigidbody2D.velocity = movement.normalized * movementSpeed;
    }
    Vector3 moveDir = (Vector3.forward * movement.y) + (Vector3.right * movement.x);
}

3. 保护滑动动画状态

在UpdateState()开头添加isSliding判断,滑动时跳过其他动画状态处理:

private void UpdateState()
{
    // 滑动状态下仅维护基础动画状态,跳过其他逻辑
    if (isSliding)
    {
        animator.SetBool("isMove", false);
        animator.SetBool("isRun", false);
        animator.SetBool("isCrouch", false);
        return;
    }

    // 原有的行走、奔跑、待机方向等逻辑保持不变
    // ...(此处保留原代码内容)
}

补充说明

  • IEnumerator本质是迭代器,StartCoroutine会开启一个独立于主线程的协程流程,yield return会暂停协程执行,等待指定时间后继续执行后续代码,只要协程正常启动,stopSlide中的逻辑会在0.8秒后执行。
  • 建议将prefromSlide重命名为PerformSlide,符合C# PascalCase命名规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:01:04