Unity中IK动画与布偶死亡动画切换的实现

news2024/12/22 23:56:16

在Unity游戏开发中,Inverse Kinematics(IK)是创建逼真角色动画的强大工具。同时,能够在适当的时候切换到布偶物理状态来实现死亡动画等效果,可以极大地增强游戏的视觉体验。本文将详细介绍如何在Unity中利用IK实现常规动画,并在需要时切换到布偶状态以展示死亡动画。

一、IK动画基础

1.1 设置Animator和IK目标

首先,我们需要为角色添加Animator组件,它将负责管理角色的动画状态机。同时,确定IK目标(查看 Animation Rigging教程),例如对于一个双足角色,我们通常会有左右脚和头部等IK目标。这些目标可以是空的游戏对象,它们的位置和旋转将通过IK算法来影响角色的骨骼。 从而实现更自然的动画效果。

以下是相关的代码声明:

// 用于控制角色动画的Animator组件
public Animator animator; 
// 左脚IK目标的Transform,用于设置左脚在动画中的目标位置和旋转
public Transform leftFootIKTarget; 
// 右脚IK目标的Transform
public Transform rightFootIKTarget; 
// 头部IK目标的Transform,这里只是示例,可根据需要添加更多IK目标,比如手部等
public Transform headIKTarget; 

1.2 在代码中启用IK

为了让Animator组件根据我们设置的IK目标工作,我们需要在脚本中重写OnAnimatorIK方法。这个方法用于设置IK权重和目标位置/旋转。以下是一个简单的示例,用于设置脚部和头部的IK目标:

// 当Animator处理IK时调用此方法,layerIndex表示当前动画层索引
void OnAnimatorIK(int layerIndex)
{
    // 首先确保Animator组件存在,否则无法进行IK设置
    if (animator)
    {
        // 设置左脚IK的位置权重为1,表示完全应用IK位置计算。AvatarIKGoal.LeftFoot是Unity定义的表示左脚IK目标的枚举值
        animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1f); 
        // 设置左脚IK目标的位置,animator会根据这个位置来调整角色左脚的位置
        animator.SetIKPosition(AvatarIKGoal.LeftFoot, leftFootIKTarget.position); 
        // 设置左脚IK的旋转权重为1,表示完全应用IK旋转计算
        animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 1f); 
        // 设置左脚IK目标的旋转,animator会根据这个旋转来调整角色左脚的旋转
        animator.SetIKRotation(AvatarIKGoal.LeftFoot, leftFootIKTarget.rotation); 

        // 右脚IK的设置,与左脚类似
        animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, 1f);
        animator.SetIKPosition(AvatarIKGoal.RightFoot, rightFootIKTarget.position);
        animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, 1f);
        animator.SetIKRotation(AvatarIKGoal.RightFoot, rightFootIKTarget.rotation);
  
    }
}

通过这样的设置,角色的脚部和头部就会根据我们设定的IK目标来动态调整位置和旋转,从而实现更自然的动画效果,比如行走、站立、转头等动画。

二、基于IK的常规动画实现

2.1 行走动画示例

对于行走动画,我们可以通过改变IK目标的位置来模拟脚步的移动。这里我们假设已经有一个walkSpeed参数来控制行走速度。

// 行走速度,用于控制角色行走动画的速度,值越大,单位时间内行走的距离越远
public float walkSpeed = 2.0f; 
// 记录左脚行走步骤的进度,范围从0到stepTime,表示当前左脚行走步骤的完成程度,初始值为0
private float leftFootStepProgress = 0; 
// 记录右脚行走步骤的进度,与左脚类似,初始值为0
private float rightFootStepProgress = 0; 
// 表示左脚是否正在移动的标志,在更完整的代码逻辑中应该有相应的设置和更新机制
private bool isLeftFootMoving; 
// 表示右脚是否正在移动的标志,同理
private bool isRightFootMoving; 
// 角色每一步抬起的高度,用于在行走动画中实现抬脚的效果,值越大,抬脚越高
private float stepHeight; 
// 记录左脚的初始位置,在动画过程中用于计算当前位置
private Vector3 leftFootInitialPosition; 
// 记录右脚的初始位置,用于计算右脚在动画中的当前位置
private Vector3 rightFootInitialPosition; 

void Update()
{
    // 根据行走速度计算每一步所需的时间,用于控制脚步移动的节奏
    float stepTime = 1 / walkSpeed; 

    // 左脚的动画逻辑
    if (isLeftFootMoving)
    {
        // 增加左脚行走步骤的进度,根据每帧的时间增量(Time.deltaTime)来更新。Time.deltaTime是Unity提供的表示上一帧到当前帧的时间间隔
        leftFootStepProgress += Time.deltaTime; 
        // 如果左脚行走步骤的进度超过了一步所需的时间(stepTime),表示这一步已经完成
        if (leftFootStepProgress >= stepTime)
        {
            // 将左脚行走步骤的进度重置为0,准备下一次行走步骤
            leftFootStepProgress = 0; 
            // 设置左脚不再移动,后续需要有相应的逻辑来重新触发移动
            isLeftFootMoving = false; 
        }
        // 计算当前左脚行走步骤的插值因子t,用于计算当前左脚的目标位置,t的范围是0到1,用于实现脚步移动的平滑过渡
        float t = leftFootStepProgress / stepTime; 
        // 根据正弦函数计算当前左脚在垂直方向上的位置变化,以实现抬脚和落脚的效果。Mathf.Sin(t * Mathf.PI)的值在0到1再到0之间变化,乘以stepHeight就得到了垂直方向的位移
        Vector3 targetPosition = leftFootInitialPosition + new Vector3(0, Mathf.Sin(t * Mathf.PI) * stepHeight, 0); 
        // 设置左脚IK目标的位置,驱动动画系统更新左脚的位置,使角色的左脚根据计算出的位置移动
        leftFootIKTarget.position = targetPosition; 
    }
    else
    {
        // 如果左脚没有移动,将左脚IK目标位置设置为初始位置
        leftFootIKTarget.position = leftFootInitialPosition; 
    }

    // 右脚的动画逻辑,与左脚类似
    if (isRightFootMoving)
    {
        rightFootStepProgress += Time.deltaTime;
        if (rightFootStepProgress >= stepTime)
        {
            rightFootStepProgress = 0;
            isRightFootMoving = false;
        }
        float t = rightFootStepProgress / stepTime;
        Vector3 targetPosition = rightFootInitialPosition + new Vector3(0, Mathf.Sin(t * Mathf.PI) * stepHeight, 0);
        rightFootIKTarget.position = targetPosition;
    }
    else
    {
        rightFootIKTarget.position = rightFootInitialPosition;
    }
}

通过上述代码,我们利用IK目标位置的改变和时间控制,实现了基本的行走动画效果,角色的双脚会根据设定的速度和高度参数进行抬脚和落脚的动作。

三、布偶状态与死亡动画

3.1 设置布偶物理组件

要实现布偶状态,我们需要为角色添加适当的物理组件。首先是Rigidbody,它赋予角色物理属性,如重力、质量等。同时,对于每个骨骼,我们可以添加CharacterJointConfigurableJoint等关节组件来模拟物理连接,使角色在物理模拟下呈现出类似布偶的效果。
在这里插入图片描述

以下是相关的代码示例:

// 用于布偶物理模拟的根Rigidbody组件,它是整个布偶物理系统的基础,控制角色整体的物理行为
public Rigidbody rootRigidbody; 
// 角色各个关节的CharacterJoint数组,CharacterJoint用于模拟关节的物理连接,这里可用于布偶物理效果,每个关节都有其特定的物理属性设置
public CharacterJoint[] joints; 

void Start()
{
    // 初始时关闭根Rigidbody的物理模拟,使角色处于动画控制状态,不受物理引擎的影响,这样可以先让角色执行IK动画
    rootRigidbody.isKinematic = true; 
    // 遍历所有关节,关闭关节预处理。这一步可以在初始化时避免一些不必要的物理计算,在切换到布偶状态时再重新启用
    foreach (var joint in joints)
    {
        joint.enablePreprocessing = false; 
    }
}

3.2 切换到布偶状态实现死亡动画

当角色死亡时,我们可以通过以下步骤切换到布偶状态:

// 用于触发角色死亡并切换到布偶状态的函数
public void Die()
{
    // 禁用Animator组件,停止基于动画状态机的动画播放,角色将不再受动画状态机控制,而是转为受物理引擎控制
    animator.enabled = false; 
    // 启用根Rigidbody的物理模拟,使角色进入布偶物理状态,开始受物理引擎的各种物理规则影响,如重力、碰撞等
    rootRigidbody.isKinematic = false; 
    // 遍历所有关节,启用关节预处理,使关节在物理模拟中正常工作,模拟布偶的物理效果,关节会根据物理作用力做出相应的动作
    foreach (var joint in joints)
    {
        joint.enablePreprocessing = true; 
    }
    // 给根Rigidbody添加一个向下的力,模拟死亡后的倒下效果。这里的力的大小和方向可以根据实际情况调整,ForceMode.Impulse表示瞬间施加一个力
    rootRigidbody.AddForce(Vector3.down * 5f, ForceMode.Impulse); 
}

通过这样的切换,角色就会从基于IK的动画状态切换到布偶物理状态,模拟出死亡后的倒下等效果,给玩家更真实的视觉感受。

四、动画状态切换的管理

在游戏中,需要合理地管理动画状态的切换。可以使用状态机或脚本逻辑来决定何时从正常的IK动画切换到死亡的布偶状态。例如,可以通过检测角色的生命值,当生命值为0时触发Die函数。这种方式可以根据游戏的具体逻辑来灵活调整,使动画过渡更加自然和符合游戏情境。

通过以上步骤,我们可以在Unity中实现基于IK的常规动画,并在合适的时机切换到布偶状态来展示死亡动画,为游戏角色带来更丰富和逼真的动画表现。希望本文对您在Unity动画开发方面有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2238645.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ArcGISPro】单次将自己建立的工具箱添加至Arcpy中

新建工具箱 添加至Arcpy中 调用刚添加的工具箱

JVM的组成、字节码文件的组成

目录 java虚拟机的组成 字节码文件的组成 基础信息 常量池 字段 方法 属性 字节码相关的常用工具: 总结: 1、如何查看字节码文件? 2、字节码文件的核心组成有哪些? java虚拟机的组成 类加载器 ClassLoader运行时数据区…

新的服务器Centos7.6 安卓基础的环境配置(新服务器可直接粘贴使用配置)

常见的基础服务器配置之Centos命令 正常来说都是安装一个docker基本上很多问题都可以解决了,我基本上都是通过docker去管理一些容器如:mysql、redis、mongoDB等之类的镜像,还有一些中间件如kafka。下面就安装一个 docker 和 nginx 的相关配置…

Mysql COUNT() 函数详解

Mysql COUNT 函数详解 COUNT() 的几种用法COUNT(*)COUNT(1)COUNT(column)COUNT(*) 与 GROUP BYCOUNT(*) 与 GROUP BY 和 HAVING COUNT(expr) 的用法COUNT(DISTINCT expr)COUNT(expr) 带条件查询 写在最后 在使用Mysql的时候,作为开发者,聚合函数是肯定会…

yum下载时出现报错 Couldn‘t read a file:// file for file:///mnt/repodata/repomd.xml

得知说yum源指定的/mnt/没有镜像源 发现可能是镜像没有挂载成功 mount /dev/cdrom /mnt 清理一下缓存重新试一下 yum clean all yum install mod_ssl 解决

视觉SLAM数学基础

本文系统梳理从相机成像模型,通过不同图像帧之间的构造几何约束求解位姿变换,再根据位姿变换和匹配点还原三维坐标的过程,可以作为基于特征点法的视觉SLAM的数学基础。 1、相机成像模型 1.1、针孔相机模型 实际相机的成像方式通常很复杂&a…

书生大模型第四期闯关任务与笔记

书生大模型第四期闯关任务与笔记 入门岛第一关 Linux闯关任务:完成SSH连接与端口映射并运行hello_world.py笔记与过程SSH端口映射linux文件管理命令linux进程管理命令 第二关 Python闯关任务:Leetcode 383(笔记中提交代码与leetcode提交通过截图)闯关任务…

【React】深入理解 JSX语法

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 深入理解 JSX语法1. JSX 简介2. JSX 的基本语法2.1 基本结构2.2 与普通 JavaScr…

MyBatis——增删查改(XML 方式)

1. 查询 1.1. 简单查询 使用注解的方式主要是完成一些简单的增删查改功能,如果要实现复杂的 SQL 功能,还是建议使用 XML 来配置映射语句,将 SQL 语句写在 XML 配置文件中 如果要操作数据库,需要做以下的配置,与注解…

YJN5216 手提式升降工作灯

YJN5216 手提式升降工作灯 产品简介: 适用于防汛应急抢修、铁路工务、电务、供电、运输等场所小范围检修、施工照明,也适用于电网、公消等行业小方位应急照明使用。 性能特点: 灯具体积小、重量轻,可以实现手提、背行两种携带方式。 灯具…

LeetCode题练习与总结:完美矩形--391

一、题目描述 给你一个数组 rectangles ,其中 rectangles[i] [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。 如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则…

Mac中安装OhMyZsh

Mac中安装OhMyZsh 文章目录 Mac中安装OhMyZsh一、Homebrew二、OhMyZsh1、Oh-My-Zsh配置1.1:主题配置1.2:插件配置(语法高亮和自动提示)1、zsh-autosuggestions(需下载安装):高亮显示所有支持的命…

计算机毕业设计Python+图神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习 深度学习

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

Llama旋转位置编码代码实现及详解

旋转位置编码RoPE 在旋转位置编码与Transformer和BERT之间的区别中介绍了旋转位置编码(RoPE)的特点和优势,这种输入长度动态可变的优势使得在Llama编码时,不需要掩码将多余的嵌入掩住。为了详细了解RoPE是如何实现的,…

如何保证Redis与MySQL双写一致性

什么是双写一致性问题? 双写一致性主要指在一个数据同时存在于缓存(如Redis)和持久化存储(如MySQL)的情况下,任何一方的数据更新都必须确保另一方数据的同步更新,以保持双方数据的一致状态。这一…

STM32获取SHT3X温湿度芯片数据

目录 一、概述 二、单次数据采集模式的测量 1、配置说明 2、代码实现方式 三、周期性数据采集模式的测量 1、配置说明 2、代码实现方式 四、完整代码下载链接 一、概述 SHT3X是Sensirion公司推出的一款高精度、完全校准的温湿度传感器,基于CMOSens技术。它提…

计算机新手练级攻略——善用搜索引擎

计算机学生新手练级攻略——善用搜索引擎 在信息爆炸的时代,计算机专业的学生如何有效地自我提升?答案可能就藏在一个简单却强大的工具——搜索引擎中。搜索引擎不仅是获取知识的入口,更是解决问题的利器。下面,我将分享一些善用搜…

【MySQL】数据库表连接简明解释

未经许可,不得转载。 文章目录 表连接表连接的类型内连接与外连接结合 WHERE 条件交叉连接(cross join)表连接 在关系型数据库中,建模是数据组织的核心难点。数据库建模需要将数据关系理清,构建出适合存储和查询的结构。 所谓“模型”包括实体(entity) 和关系(relati…

Unity 网格模型及优化

一个模型中可以包含很多网格,一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格(Sub-Mesh)组成。 在渲染引擎的时候,每个子网格都要匹配一个材质球来做渲染,实际上一个子网格本身就是一个个普通的模型&#xff0…

恒源云使用手册记录:从服务器下载数据到本地

文章目录 一、xftp下载二、通过Xftp客户端连接站点 一、xftp下载 先下载xftp:下载连接 二、通过Xftp客户端连接站点 右击文件,点击新建 名称可以任意 主机、端口号、用户名 点击这里的复制登录命令 比如我这里得到ssh -p 41604 rooti-2.gpushare.co…