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

Unity 3D动画中途冻结异常问题求助

Unity第三人称移动动画中途冻结问题修复

问题描述

完成Unity第三人称移动与动画配置后,出现动画中途冻结异常:玩家跑步动作会卡在单腿抬起、另一腿斜伸的怪异姿势,但角色移动功能完全正常。尝试重置项目、重启工程、参考教程均未解决。

代码问题分析

  1. Animator变换被强制重置:Update函数中每帧执行anim.transform.localPosition = Vector3.zero;和anim.transform.localEulerAngles = Vector3.zero;,这会强制覆盖动画播放时产生的位移和旋转,直接打断动画的正常播放流程,导致动画冻结在某一帧。

  2. 地面检测层掩码错误:Physics.CheckSphere(transform.position, .1f, 1)中使用固定数值1作为层掩码,可能未正确匹配地面层,导致isGrounded状态判断异常,干扰动画状态机的切换逻辑。

  3. 动画参数切换无平滑过渡:直接给Speed参数赋值0/1/2,参数突变可能导致动画状态切换时出现卡顿或冻结。

修复方案

1. 移除Animator强制重置代码

删除Update中每帧重置Animator变换的两行代码,避免打断动画播放:

// 移除以下两行
anim.transform.localPosition = Vector3.zero;
anim.transform.localEulerAngles = Vector3.zero;

2. 修正地面检测层掩码

创建专门的"Ground"层,替换固定层掩码数值,确保地面检测准确:

// 替换原地面检测代码
isGrounded = Physics.CheckSphere(transform.position, .1f, LayerMask.GetMask("Ground"));

3. 给动画参数添加平滑过渡

使用SetFloat的重载方法,让Speed参数平滑变化,避免突变:

// 替换原Speed参数赋值逻辑
float targetSpeed = direction.magnitude >= .1f ? (sprinting ? 2f : 1f) : 0f;
anim.SetFloat("Speed", targetSpeed, 0.1f, Time.deltaTime);

4. 检查动画状态机配置

  • 确保跑步、走路动画片段开启循环(在动画导入设置中勾选Loop Time)。
  • 确认动画状态机中Idle、Walk、Sprint之间的过渡条件合理,无冲突的过渡规则。

修改后的完整代码

using System;
using UnityEngine;
using Quaternion = UnityEngine.Quaternion;
using Vector3 = UnityEngine.Vector3;

public class ThirdPersonMovement : MonoBehaviour
{
    public CharacterController controller;
    public float turnSmoothTime = .1f;
    private float turnSmoothVelocity;
    public float walkSpeed;
    public float sprintSpeed;
    private float trueSpeed;
    public Transform cam;
    public float jumpHeight;
    public float gravity;
    private bool isGrounded;
    private Vector3 velocity;
    public Animator anim;
    public bool sprinting;

    private void Start()
    {
        trueSpeed = walkSpeed;
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
        // 仅在初始化时重置Animator变换(可选,根据需求调整)
        anim.transform.localPosition = Vector3.zero;
        anim.transform.localEulerAngles = Vector3.zero;
    }

    void Update()
    {
        // 修正地面检测层掩码
        isGrounded = Physics.CheckSphere(transform.position, .1f, LayerMask.GetMask("Ground"));
        anim.SetBool("isGrounded", isGrounded);

        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -1;
        }

        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");
        Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;

        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            trueSpeed = sprintSpeed;
            sprinting = true;
        }

        if (Input.GetKeyUp(KeyCode.LeftShift))
        {
            trueSpeed = walkSpeed;
            sprinting = false;
        }

        if (direction.magnitude >= .1f)
        {
            float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
            transform.rotation = Quaternion.Euler(0f, angle, 0f);

            Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
            controller.Move(moveDir * trueSpeed * Time.deltaTime);
        }

        // 平滑设置Speed参数
        float targetSpeed = direction.magnitude >= .1f ? (sprinting ? 2f : 1f) : 0f;
        anim.SetFloat("Speed", targetSpeed, 0.1f, Time.deltaTime);

        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt((jumpHeight * 10) * -2f * gravity);
        }

        if (velocity.y > -20)
        {
            velocity.y += (gravity * 10) * Time.deltaTime;
        }
        controller.Move(velocity * Time.deltaTime);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:55:03