Unity3D--如何让你的人物角色动起来?十分详细(特别教程篇)

        废话不多说,要想让你的角色动起来,你必须先了解一个会动的角色都需要什么?(完整代码我会在最后面贴,但是对于刚接触Unity3D的同学来说,我这个教程会尽量给你们详细并快速的介绍。)

        

一.准备工作

        我们要事先准备最基本的人物的模型,这个模型除了人物模型本身(包含骨骼、贴图材质、动画等等)其中,一个人物模型必须要有动画骨骼绑定(不然不能上动画),而动画会使你的人物在移动时动起来,不然真的就成了T字Pose到处乱跑了。。。(不过有些人物模型它是以预制体的形式打包的,很可能一开始就有绑定的动画,但是它需要对应的脚本去调用它,否则和没有没区别,所以我们一般要全部自己从头开始弄。。。)

        那么,这么好用的人物模型要去哪里找呢?

        如果,你实在没有途径去下载到这些模型,那么你最好在Unity官方商店(Unity Assets Store)里面去下载(虽然免费的资源确实不多。。。)这里笔者下载了名为Unity-Chan!Model(Unity酱)的人物模型,它内部就包含着几乎我们所需要的一个人物模型中要用的资源。

        隔壁的SD chan Animation bundle则是和动作动画有关的资源,内含有人物动画(不过笔者当时没有注意到有这个资源,转而下载了“Basic Motons FREE”这个动画资源。但是其实走路啊、跑动啊这些动画其实都大同小异的,无所谓。当然到时候你们可以自由发挥搞些什么跳跃动作、瞬移动作都行,这里我只完成了走路和跑步)

Basic Motons FREE

        (下载过程笔者就忽略了。。。)下载完这些资源后,它们默认会放在Unity的一个默认资源文件夹里面,我们需要找到它,路径为:

C:\Users\你的计算机用户名\AppData\Roaming\Unity\Asset Store-5.x

这样你就可以看到你从Unity Store中下载的资源了。(注意:AppData是个隐藏文件夹,如果不知道如何解锁隐藏文件夹的小伙伴请看:隐藏文件夹怎么找出来?(3种方法)

吐槽:当然后续当你Import(载入)这些额外资源后,你当前工程的Assets文件夹里会自动存在这些资源的,所以你没有必要从默认资源下载的路径里去重新移动它。(但是它真的好占空间。。。)

二.导入下载资源

        我们下载好的资源,它本质上是一个打包好的资源包(文件后缀为:.unitypackage),我们可以在Unity中导入它。如下:

找到Import Package --> Custom Package选项并点击

搜索咱们下载的资源包(Unity-chan和Basic Motions FREE)

点Import后就会自动导入了

三.认识人物的一些基础参数

unitychan(1)是我们这次的调整的对象

我们来看看人物模型的一些配置

再来看看Unity3D手册的官方解释:

手册链接:Animator 组件

 我来简单易懂的解释一下:

Controller(控制器):其实就是控制角色的动画了,但是,这个动画可以由很多状态(其他动画)组成,这对我们后续用脚本写状态操控它非常重要,后面将会非常详尽的演示。

Avatar(角色):即当前需要被动画操作的对象(角色模型)。

Apply Root Motion:这个比较难懂,总而言之就是,如果你启用它,那么到时候角色的运动,位移和动画就会一起动;而不启用则只会保持动画是可以动的。但我们为什么不用它呢?明明启用了,角色的动作和动画就会一起动了,可以省去很多麻烦。

原因就在于:1.它不能识别人物走动朝向(似乎是只能一直向前走);2.会出现人物朝向瞬移的情况(转向不自然)。

这些问题我们都将在脚本里去一步步调整它,而不轻易使用Applt Root Motion。

后两个参数对新手来说问题不大,不需要额外调整,因此本文略过,详情还是请查看Unity3D官方手册的信息或者自行搜索。

四.Animator(重要)

要让我们的角色动起来,动画是十分重要的一环,而这些都将由Animator这个组件完成。

关于Animator的功能,实际上非常多,但由于我们希望最快速度完成一个角色的运动,详细的原理和其他的特殊功能我在这里就不讲了,只需按照我说的一步步来就行。

对于想要更加了解Animator全部功能的同学,这里指路这个文章:Unity动画系统详解3:如何播放、切换动画?

我们先在Assets里面创建一个用于存放动画配置的文件夹(Animator(Custom)):

在Assets中右键-->Create-->Floder就可以生成文件夹了。(我这里已经创建好了)

接着我们继续在Animator(Custom)这个文件夹里右键-->Create-->Animator Controller,创建新的动画系统,命名为NewAnimator,接着我们就会看到以下状态:

在Animator那有着三个彩色方块的小窗口,就是我们要配置的动画系统部分了。

五.Animator的配置

在这个界面中,我们先认识一下Animator是怎么工作的。

我们一开始所创建的新动画状态(NewAnimator)是没有任何状态切换的,因此就需要我们自己去创建切换状态,而在这个过程中,我们想引入任何子动画,并在它们之间切换都是可以的。

Entry是执行动画的入口,Entry指向的动画状态会以橙黄色标识,表示默认动画动作。

例如接下来我们先让人物“站起来”,摆脱T字型站姿。

在该窗口中我们右键Create State-->Empty 先创建一个没有动画的状态:

我们会发现,Entry会自动连接我们这个刚新建好的什么都没有的状态,此时,这个“New State”就成了我们的默认动作状态,如果我们在游戏中什么也不做,那么Entry会一直指向并执行这个"New State"

现在请看这边:

我们可以给“New State”改个名字,叫做“Stand”(站立),并在Motion中找到有关站立的动画。

别忘记这些动画的来源来自于资源包(Basic Motons FREE和unity-chan中)

我们找到WAIT00(这应该是Unity-chan资源中自带的待机动作之一,只会自然站立)

接下来我们回到这里:

选中后试试效果点击运行试试效果:

快看!她站起来了!(左边那个是成品先不管)

也可以换换其他动作玩玩:

十分可爱不是吗?你可以自由搭配!

接下来我们继续,将它们进一步完成,形成完整的运动动画系统。

我们再多创建两个状态,走路(Walk)和跑步(Run),并且我们也在Motion中找到对应动作加入上去。        

接着我们给它做状态之间的连线(Transition)

Transition:即状态之间的切换条件,该条件可以是一个也可以是多个,用于从一个状态切换到另一个状态

点击橙黄色方块-->Make Transition-->连线连到对应的方块上,其他方块同理,最后搭成这样就行:

我们可以点击StandWalk的那段连线(或者WalkStand的那段连线),看看它的配置都有什么?

解释一下上面这些配置:

Transitions(Solo):如果两个状态之间有多条Transition连线指向当前动画状态,勾选这个选项后,只有选中Solo的Transition生效。其他Transition会被禁用。

Transitions(Mute): 勾选这个选项后,该条Transition会被禁用。如果同时选中了Solo和Mute,Mute会优先生效。

:命名框,可以单独给其命名连线动作的名字。

Has Exit Time:指是否有退出时间条件。退出时间是一种特殊的transition条件,它不依赖参数(标志位判断),而是根据设置的退出时间点作为条件进行状态转换。(即当前动作执行到一定时间条件后才判断进入下一个状态,默认是执行完才进入下一状态。)

:如果勾选了Has Exit Time,该参数是可以设置的,设置动画退出的单位化时间。例如设置为0.75,代表动画播放到75%时为true,如果没有其他条件,会直接切换到下一个State。

Exit Time:
如果exit time小于1,那么state每次循环到对应位置的时候(不管动画是否设置为循环,state总是循环的),该条件都会为true。比如第一次播放到75%,第二次播放到75%.......时退出条件都会为true。
如果exit time大于1,该条件只会检测一次。比如exit time为3.5,state的动画会在循环3次后,在播放到第4次的50%时为true。


Fixed Duration:勾选时,下方Transition Duration参数的单位是秒,不勾选时,参数会作为一个百分比。


Transition Duration:transition的过渡时间。两个状态在转换时,一般不会瞬间从一个状态转换到另一个状态,而是会经过平滑混合,这个属性就是设置了平滑混合的时间。可以从下图的两个蓝色箭头看出转换的时间。

Transition Offset:目标状态开始播放的时间偏移。比如设置为0.5,则转换到下一个State时,会从50%的位置开始播放。

Interruption Source、Ordered Interruption:这两个参数可以用来控制transition的打断。

:判断条件。如果Conditions中没有条件,但是勾选了Has exit time,那么exit time会被作为state退出的条件,到达exit time时,会切换到下一个state。
(下面脚本前配置部分会细讲配置)

Preview:可以看当前动画动作的预览,点击播放键即可查看动画,如果拖动进度条可以加快动画预览播放速度。

明白了上述配置后,我们的逻辑就是:

Entry出发,然后到第一个动作(即默认动作),接着我们可以通过后续脚本操作,让它变成走路(Walk)动画,但是走路(Walk)一旦停下,它也必须要有能返回到第一个动作的能力(这就是为什么我们还要连线回来,Run方块同理)

这就说明了,如果你的动画系统越多(比如你还想增加跳跃、摔倒、各种其他的待机状态等等),你就需要合理的安排你的动画连线走向和标志位判断(Condition)。

几个注意事项:

1.这个时候,当你还开启Apply Root Motion时,启动游戏会发生什么?没错,角色会停一下走一下。出现这个情况是因为当我们回看Animator组件工作时,发现Stand再执行一段时间后会跳到Walk上,然后又快速闪回Stand。这是因为我们还没开始写脚本和使用Conditons配置控制它(同时我们还没对Has Exit Time取消勾选),我们应该让角色不做任何操作时一直处于Stand状态。

2.每个动画,都是有帧数长短的,比如WAIT00,它默认只有执行完后才能继续下一个动作,除非你在上述配置里设置了打断条件。(比如我们设置静止不动的时候它是标志0,走路是标志1,在它没有执行完前,如果标志位变成了1,那么它肯定就会中断静止不动的操作,这就是标志位的运用)

3.一个transition至少要有一个条件(Has Exit Time可以作为一个条件),否则transition会被忽略。
 

六.配置脚本前准备

        终于,在大概配置完Animator的一些动画配置后,我们终于可以来到脚本篇了!(芜湖)

        但是,小伙子们,先别着急,其实在上面的Animator配置的最后几个注意事项中,我们是不是说到Stand会变成Walk又快速闪回无限循环,而不能一直保持呢?其实在Animator中,我们还少了设置判断状态(标志位)

如图:

        我们要将这部分设置和脚本一起讲,好让大家知道如何操控标志位来控制动作的动画状态切换。

1.先在上述页面点击“+”号,我们创建一个可以操控标志位的配置(我们选择Int类型,改名为:“BasicMotion”),创建完后如下:

        我们会发现,这里面会有很多种类型的标志位,有Bool(布尔类型)、Float(浮点数类型)、Int(整数类型)和Trigger(触发器类型)。选择什么样类型的触发器是完全自由的,而且不一定只能添加一个,随着你的动画状态切换越来越丰富,那么你应该会想要考虑多种类型的标志位去操控。(这里我们只是给出了示例)

再点击StandWalk这段连线,找到Conditions配置,并点击+号创建一个新判断条件:

我们将Greater(大于)改为Equals(等于)1。

(你也可以选择其他不同的数字,让它们的判断条件到底是小于、大于、等于还是不等于。但由于我们这里选择了Int类型判断器,因此填入的数字必须是整数!)

修改后如下:

其他也同理,我直接以文字描述,如下:

Walk-->Stand:一个判断条件,Equals(等于)0;

Walk-->Run:一个判断条件,Equals(等于)2;

Run-->Walk:一个判断条件,Equals(等于)1;

Run-->Stand:一个判断条件,Equals(等于)0;

Stand-->Run:一个判断条件,Equals(等于)2;

记住:所有状态块连线(Transition)中的Has Exit Time选项记得取消勾选!(等你搞明白了,也可以对这些配置自由变换搞DIY玩)

这时候如果你启动游戏的话,就会发现角色只是站着不动了,让它动起来的操作就在下面的脚本里面!

(如果你想看动画状态是怎么运作的,点击对应的人物角色+打开Animator+点击对应自定义动画配置就可以看到了)

七.(真)脚本配置

        其实老实说,脚本部分对于学习过一部分Unity3D知识的人反而是最简单的一步,因为无非就是这控件那控件,这语句那语句的引用,但是我还是会细致讲明白的,请各位萌新们放心(虽然我也是。。。)

        先附上脚本:

/*Create By JesonHumber_f4*/
/*2023.3.10*/
/*Unity3D Digtal Twin Project*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//[RequireComponent(typeof(组件类型))]的意义是:
//为当前挂载该脚本的游戏物体添加需要的组件(这属于保险做法)
//该操作不需要引入其他命名空间
[RequireComponent(typeof(CharacterController))]

//引入播放动画的组件
[RequireComponent(typeof(Animator))]
public class HandControlCharacter : MonoBehaviour
{
    CharacterController controller;
    Animator animator;

    //人物移动速度(可自行调节)
    public float MoveSpeed;

    //获取键盘水平方向和垂直方向值用(GetAxis()方法)
    public float horizontal;
    public float vertical;

    //用于改变动画状态的变量
    public int move_var;

    //目标朝向
    public Vector3 target_dir = Vector3.zero;  //初始化为(0,0,0),可自行调节

    // Start is called before the first frame update
    void Start()
    {
        //获取“角色控制器”组件(如果你要考虑物理碰撞等操作,就必须有这个组件)
        controller = GetComponent<CharacterController>();

        //获取“动画制作者组件”
        animator = GetComponent<Animator>();

        //初始化人物移动速度
        MoveSpeed = 0;

        //初始化动画状态变量为0(人物静止动画播放)
        move_var = 0;

        //校准“角色控制器”的胶囊体参数(物理碰撞体积)
        controller.center = new Vector3(0, 1, 0);
        controller.radius = 0.5f;
        controller.height = 2;
    }

    // Update is called once per frame
    void Update()
    {
        HandControl_Move();
    }

    public void HandControl_Move()
    {
        //GetAxis("Horizontal");对应的是键盘上的A和D键(水平键)
        horizontal = Input.GetAxis("Horizontal");
        //GetAxis("Vertical");对应的是键盘上的W和S键(垂直键)    
        vertical = Input.GetAxis("Vertical");                        
                                                                    
         //注:这上面的“水平垂直键”所映射的键位实际上可以更改,
         //它们只不过是默认规则,它们的最大值均为1
        if (horizontal != 0 || vertical != 0) //按键(默认:WASD)触发时就进行判断
        {
            //前进
            if (Input.GetKey(KeyCode.W))
            {
                move_var = 1;
                MoveSpeed = 1.5f;
                transform.rotation = Quaternion.LookRotation(target_dir);
                //Quaternion.LookRotation():
                //传入一个向量值使物体朝向向量方向,
                //使物体朝向另一个物体只需要传入两个物体Position之间的Vector3差值即可

                
                //疾跑判断
                if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.W))
                {
                    move_var = 2;
                    MoveSpeed = 3.5f;
                }

            }

            //向后走
            else if (Input.GetKey(KeyCode.S))
            {
                move_var = 1;
                MoveSpeed = 1.5f;
                transform.rotation = Quaternion.LookRotation(target_dir);

                //疾跑判断
                if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.S))
                {
                    move_var = 2;
                    MoveSpeed = 3.5f;
                }
            }

            //向左走
            else if (Input.GetKey(KeyCode.A))
            {
                move_var = 1;
                MoveSpeed = 1.5f;
                transform.rotation = Quaternion.LookRotation(target_dir);

                //疾跑判断
                if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.A))
                {
                    move_var = 2;
                    MoveSpeed = 3.5f;
                }
                //transform.Translate(Vector3.forward * Time.deltaTime);
            }

            //向右走
            else if (Input.GetKey(KeyCode.D))
            {
                move_var = 1;
                MoveSpeed = 1.5f;
                transform.rotation = Quaternion.LookRotation(target_dir);

                //疾跑判断
                if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.D))
                {
                    move_var = 2;
                    MoveSpeed = 3.5f;
                }
            }


            //动画更新
            //这个"BasicMotion"的名字,如果你们的Parameter名字不和我一致
            //你们就得改!
            animator.SetInteger("BasicMotion", move_var);
            //三维坐标方向坐标值更新
            //更新坐标值运用轴坐标参数
            target_dir = new Vector3(horizontal, 0, vertical);
            //人物移动更新
            controller.Move(target_dir * MoveSpeed * Time.deltaTime);

            //controller.Move()方法负责实现人物的移动,它会在给定的方向上移动游戏物体
            //给定方向需要:绝对运动增量值(方向与速度)和帧刷新时间(Time.deltaTime)
            //注:controller.Move()是不使用“重力”的,如果已经上坡,再回来时无法下坡!
            //    如果需要使用重力就必须自己手动写出“模拟重力”的代码。

             #region
            //也可以使用该方法代替controller.Move();
            //this.transform.Translate(dir * MoveSpeed * Time.deltaTime);
            #endregion
        }

        else
        {
            //默认为静止不动
            move_var = 0;

            //动画状态更新
            //这个"BasicMotion"的名字,如果你们的Parameter名字不和我一致
            //你们就得改!
            animator.SetInteger("BasicMotion", 0);
            MoveSpeed = 0;
        }
    }
}
                                                                           

写好脚本后我们挂载脚本(我这里命名为Hand Control Character)给角色:

挂载完就可以跑了。

        小插曲:如果你发现你在走路跑步时,动作状态没有正常跳转,请着重排查Conditions的判断条件都设定对没有?我刚刚就在检查的时候就发现漏了一个线没有改成Equals导致它左右疾跑时没有正确改变成跑步动画。。。。。。(还有就是,你自己设定的动作标号0123这些、Parameter标志位配置的名字这些都改对没有?要细心细心再细心!!!)

        笔者注:本教程时笔者之前和学校老师做项目时搞的其中一环,你们现在看到的界面其实整个完整程序是人物可以避开中间那堵墙然后根据我们旁边X、Y轴实现自动循迹的,如果呼声高的话,我会把这个项目的全部教程公开(虽然笔者认识也不多,初衷只是为了让像我一样的新手倒霉蛋少花时间踩坑,但是如果你想要成为一个个人游戏开发者,那么仅限于该教程是不够的,你需要更多的去花时间系统学习Unity3D这个工具的相关知识,加油吧,各位!!!)

特别篇,完结撒花!!!

  • 40
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值