HOME
BLOG
Unity 动画系统
9月 12 2022

动画系统介绍

| 游戏动画

一般指模型的动作,服务视觉,实际攻击计算还靠碰撞体

暂时只尝试制作简单动画来知道动画的运行原理

如何给角色配置动作、如何切换动作、代码控制动作

| Unity动画

  • 模型和动作

    • 非人形角色,比如一个章鱼怪,他的动作基本上是完全为了这一个模型来设计的,无法复用到其他模型

    • 人形角色,符合标准的都可以复用,基于Avatar

  • 角色动作组成

    • 游戏物体上挂载 Animator 动画组件

    • Animator组件上持有 Controller(动画控制器),Controller 上配置好动作以及动作切换逻辑

    • 利用Animator组件来播放动画以及切换动画


Unity 内制作动画

选择一个具备 Animator组件的游戏物体后切换到 Animation 面板,即可进行动画的制作


Animator Controller

Animator Controller 是一个配置文件

  • 动画片段设置

    • Loop Time:动画是否循环播放

    • Loop Pose:是否循环姿势,让头尾链接更平滑

  • Animator 面板

  • 状态面板

    • 当我们选择一个状态后,检查面板中会出现这个状态的一些参数

    • Motion:这个状态具体要播方收的动画文件

    • Speed:动画的播放速度,float类型

    • Mirror:镜像动画,动画左右相反

    • Transitions:该状态参与的状态转换

      • Solo:当两个状态之间有多条条件时候仅此一条生效

      • Mute:禁用

  • 状态切换

  • 参数面板

    • 状态之间的连线,点击具体某根线后,检查面板中可以设置状态切换的具体参数

    • Has Exit Time:播放完毕才能切换

    • Conditions:条件参数,也就是这条线什么时候起效果

  • 代码控制

    • 游戏运行后,动画会自行从入口开始执行,但是我们可以获取 Animator 组件后修改参数,使动画切换

    • SetInteger("Run",1) :修改参数的值,对应的还有SetBool、SetTrigger、SetFloat

    • GetInteger("Run") :获取参数的值,对应的GetBool、GetFloat

    • speed:整体的播放速度

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

public class L8_3Demo : MonoBehaviour
{
    public Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            animator.SetTrigger("Jump"); 
        }
    }
}

模型资源与动画设置

Unity 常用模型格式:.fbx


人形动画的复用性

人性角色的骨骼结构是一致的

Avatar 映射文件:人形动作中才使用,映射人体的位置对应什么游戏物体,这样动作文件才能正确工作,基于此可以让动作复用


动画事件

自建动画:在 Animation 中添加事件

模型动画:在模型中找到动画片段,添加事件


角色控制器组件

  1. Transform 不具备物理特性

  2. 而 Rigidbody 却不稳定,很容易被弹开、穿模

  3. 角色控制器(CharacterController):

    • 面板:

      • Slope Limit:控制角色最大的爬坡斜率

      • Step Offset:控制角色可以迈上最大的台阶高度

      • Skin Width:在角色外围包裹一层 “皮肤”,这层皮肤的厚度,相当于角色身上透明的衣服,如果 Skin Width 设置为 1m,那么角色会 “浮空” 1m,一般保持默认即可

      • Min Move Distance:最小移动距离,默认是1毫米,如果该数值过大但代码中单位移动速度很慢,角色就不会动

      • Center / Radius / Height:角色控制器组件在 Scene面板 中体现为一个 “胶囊碰撞器” 的形状,这也导致其他的碰撞体我们并不需要,Center 为胶囊中心点位置,Radius 为半径,Height 为高度

    • 角色控制器组件所在的游戏物体身上不需要碰撞体和刚体

    • 常用属性:

      • isGrounded:是否在地面上
    • 常用方法

      • Move(Vector3 dir) :和 Transform.Translate雷同,没有重力,需要传递的是一个方向,数值的大小影响移动速度,所以需要乘上Time.deltaTime

      • SimpleMove(Vector3 speed) :会应用重力,需要传递的值是一个速度,并且本身就是按照时间来计算的,数值大小虽然也会影响移动速度,但是不会被帧率影响,所以不需要乘 Time.deltaTime

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

public class L8_7Demo : MonoBehaviour
{

    private CharacterController characterController;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
    }

    void Update()
    {
        Debug.Log(characterController.isGrounded);

        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        //Vector3 dir = new Vector3(horizontal, -9.8f, vertical);
        // 1
        //characterController.Move(dir * Time.deltaTime * 30);

        Vector3 dir = new Vector3(horizontal, 0, vertical);
        // 2
        characterController.SimpleMove(dir * 30);
    }
}

案例:3D 角色移动

使用角色控制器组件来控制角色位移,并且播放正确的待机或移动动画

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

public class L8_8Player : MonoBehaviour
{
    private CharacterController characterController;
    private Animator animator;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        Demo2();
    }

    // 实现基于自身坐标体系的移动,不考虑旋转
    private void Demo1()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        if (horizontal != 0 || vertical != 0)
        {
            animator.SetBool("Run", true);
        }
        else
        {
            animator.SetBool("Run", false);
        }

        Vector3 dir = new Vector3(horizontal, 0, vertical);

        // 如果以 transform 为参考方向,得到我自己的前方
        dir = transform.TransformDirection(dir);
        characterController.SimpleMove(dir);
    }

    private void Demo2()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        if (horizontal != 0 || vertical != 0)
        {
            animator.SetBool("Run", true);
        }
        else
        {
            animator.SetBool("Run", false);
        }

        Vector3 dir = new Vector3(0, 0, vertical);

        // 如果以 transform 为参考方向,得到我自己的前方
        dir = transform.TransformDirection(dir);
        characterController.SimpleMove(dir);

        transform.eulerAngles = new Vector3(0, transform.eulerAngles.y + horizontal * Time.deltaTime * 100, 0);
    }
}


👾森木清树👾

Unity Study