Unity2D入门—Pixel Adventure 1

第四章 人物动画



文章目录

  • Unity2D入门—Pixel Adventure 1
  • 前言
  • 一、静止动画
  • 二、奔跑动画
  • 三、跳跃动画
  • 四、下落动画
  • 五、动画转换
  • 总结



前言

本章讲解人物动画的相关内容,包括静止动画、奔跑动画、跳跃动画、下落动画,以及这四个动画的相互转化。


一、静止动画

为Player创建动画需要用到 Animation(动画) ,创建动画后我们将其命名为PlayerIdle,即静止状态的动画(也就是为Player赋予上下鬼畜抽动的动画哈哈哈哈,话糙理不糙)

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_ci_02

接着,我们将PlayerIdle的 小三角(Animation Clip, 用来控制动画制作和播放的) 拖到Hierarchy Window上的Playe对象上 (PS:这一步很重要,要使固定对象那个发生固定的动画,必然要将动画挂载在对象上,上一章中使用C#代码操纵角色行为也是相似的操作,后面在开发中可以优先进行这步,养成良好习惯) ,这时在Project Window会出现一个 Animation Controller (用于控制动画之间转换的工具) 。在Player的Inspector Window也可以看到多出了一个Animation的组件。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_ci_03

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_04

完成动画挂载后,我们就可以将我们Idle (静止) 的素材Copy到PlyerIdle中去。这里我们双击PlayerIdle,弹出Animation编辑窗口,但是这边还需要双击Player对象不然窗口就是不可操作的状态( PS: 这里感觉很奇怪,明明已经挂载到Player上了,为什么还需要选中Player才可操作,chatgpt给出的答案是Player对象是动画的目标对象,通过双击Player对象可以将Animation编辑窗口与Player对象进行绑定,使得编辑窗口中的属性和动画播放器实时同步。如果不双击Player对象,编辑窗口将无法与任何对象进行关联,因此无法进行实时预览和编辑。总结下来就是,Animation Editor窗口是独立于动画组件的,上面只是将动画挂载在Player上,Animation Editor并不与Player关联)。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_05

接着,我们将Idle素材拖入Animation Editor右边的 时间轴(这里需要打开Idle, 将所有帧的动画全部选中拖入其中,不会还有人不知道按住Shift点击首个和最后一个就可以选中所有素材吧)

时间轴有两个不同的选择。 其一,为 Dopesheet(关键帧清单时间轴模式) 其提供更紧凑视图,可在单个水平轨道中查看每个属性的关键帧序列。其二, 为 Curves(曲线时间轴模式) 其显示一个可调整大小的图形,其中包含每个动画属性的值如何随时间变化的视图。所有选定属性都叠加显示在同一图形中。在此模式下,可以很好地控制属性值的查看和编辑,以及如何在两者之间进行插值。

FPS(Frame per Second,每秒显示帧数):每秒钟帧数愈多,所显示的动作就会愈流畅。通常,要避免动作不流畅的最低是 30 。 这边就简单介绍一下,像了解更多请参考 link

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_时间轴_06

在 Samples = 60 设置下, 我们通过测试发现角色静止动画鬼畜得非常厉害,而 Samples = 20设置下, 静止动画就相对正常。也就是 Samples =20 相当于正常播放动画,而 Samples = 60 相当于倍速播放。(以作者的水平也只能理解到这,如果有大佬看到这篇文章,麻烦在评论区解释一下这里的Samples与时间轴的关系,不胜感激🙏) 同时,作者还发现时间轴最右边的3点这里还可以调节是Seconds轴还是Frames轴,以及Show Sample Rate的操作,也算是一个小发现了。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_时间轴_07

二、奔跑动画

左右移动动画的创建操作和静止动画的相似,这里就不进行详细操作展示了,只要让对动画的命名明确简单就是,这里我们将创建PlayerRun动画,并挂载在Player上 (如果不挂载在Player上,在Animation Editor上是不会显示的) ,以及将素材拖入时间轴中。注意这里有一个小技巧就是挂载同一个对象上的动画时可以相互切换的。后面因为涉及到动画转换,我们就先将所有的动画都创建出来,最后再来讲解动画之间的转换问题。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_时间轴_08

三、跳跃动画

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_09

四、下落动画

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_10

五、动画转换

到这里,我们已经完成了奔跑动画的创建工作,但是这个时候我们还是只能看到静止的动画,移动时还是不出现我们的素材。这时,我们就要用到上面的 Animation Controller 组件了,用于管理和控制动画状态及其之间的转换。为了使动画可以自由转换,我们需要切换到Parameters,并使用创建一个int类型的参数用于表示不同的动画状态(state)(这里原本视频里讲的是使用bool类型,因为只有两个动画,但动画肯定不止两个,所以提前使用int类型了)。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_11

接着,要实现来回切换,还需要使用Make Transition在两个动画之间建立链接,一般两个动画之间需要两条线。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_ci_12

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_13


下面我们需要用代码去为每一个状态赋值,并且控制动画切换的行为, 代码实现我们再PlayerMovement的C#代码里面实现。大部分代码的解释以注释的形式写在代码中,重点说一下Physics2D.BoxCast()函数。

Physics2D.BoxCast 是 Unity 的 2D 物理引擎中的一个方法,用于执行一个盒子形状的射线投射(raycast)。这个方法用于检测一个盒子形状的区域是否与任何碰撞器(Collider)相交,并且允许你指定哪些层(Layer)应该被考虑在内。
1、coll.bounds.center: 这是射线投射的起始点,即盒子的中心点。在这里,它使用coll.bounds.center 作为起始点,其中 coll 很可能是一个 Collider2D 或其他包含 bounds 属性的对象。
2、coll.bounds.size: 这是盒子的尺寸。它定义了射线投射时盒子的宽度和高度。
3、0f: 这是射线投射的旋转角度。0f 表示盒子没有旋转,是水平的。
4、Vector2.down: 这是射线投射的方向。Vector2.down 是一个指向屏幕下方的向量,表示射线是向下投射的。
5、.1f: 这是射线投射的最大距离。在这里,射线会向下投射 .1f(即0.1单位)的距离。
6、jumpableGround: 这是一个 LayerMask,用于指定哪些层应该被考虑在射线投射的碰撞检测中。在代码中,jumpableGround 被定义为一个可以在 Unity 的 Inspector 窗口中设置的字段,这样开发者就可以指定哪些层是角色可以跳跃到的地面。
这个方法会返回一个 RaycastHit2D 结构体,如果射线与任何碰撞器相交的话。这个结构体包含了关于碰撞的详细信息,比如碰撞点的位置和碰撞的碰撞器。如果没有发生碰撞,那么返回的 RaycastHit2D 的 collider 属性将会是 null。

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

public class PlayerMovement : MonoBehaviour
{
    private Rigidbody2D rb;
    private BoxCollider2D coll;
    private SpriteRenderer sprite;
    private Animator anim;
    //LayerMask: 这是Unity中的一个类型,用于表示多个层(Layers)的集合。
    //在Unity中,你可以为场景中的对象分配不同的层,以便更好地管理和处理它们。
    //LayerMask通常用于射线投射(Raycasting)或碰撞检测(Collision Detection)
    [SerializeField] private LayerMask jumpableGround; //设置只能在地面上跳一次的功能

    private float dirX = 0f;// 用于判断
    //[SerializeField] 可以将moveSpeed和jumpForce直接显示在组件里,方便修改
    //至于moveSpeed和jumpForce就是用来设置水平方向速度和竖直方向速度的
    [SerializeField] private float moveSpeed = 7f;
    [SerializeField] private float jumpForce = 7f;

    private enum MovementState { idle, run, jump, fall }; //这是一个枚举类型的数组idle=0,run=1,jump=2, fall=3


    // Start is called before the first frame update
    void Start()
    {
        // 这一块就是获取组件,方便获取对应数据
        rb = GetComponent<Rigidbody2D>();
        coll = GetComponent<BoxCollider2D>();
        sprite = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        //这一部分和之前差不多,就是速度的部分替换moveSpeed和jumpSpeed
        dirX = Input.GetAxisRaw("Horizontal");
        rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
        // 加入IsGrounded()限制跳跃
        if (Input.GetButtonDown("Jump") && IsGrounded())
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
        }
        //用于获取最终状态值的函数
        UpdateAnimationState();

    }
    private void UpdateAnimationState()
    {
        MovementState state;

        if (dirX > 0f)
        {
            state = MovementState.run;
            sprite.flipX = false;  //翻转画布,防止变成太空步  
        }
        else if (dirX < 0f)
        {
            state = MovementState.run;
            sprite.flipX = true;

        }
        else
        {
            state = MovementState.idle;
        }

        if (rb.velocity.y > .1f)
        {
            state = MovementState.jump;
        }
        else if (rb.velocity.y < -.1f)
        {
            state = MovementState.fall;
        }
        //最后将最终的状态设置到anim组件的state值上
        anim.SetInteger("state", (int)state);
    }

    private bool IsGrounded()
    {
        return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
    }

}

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_ci_14

解释完代码,还差最后一步就可以成功啦。最后一步需要我们在Animation Controller里面将每一条线的数值设置好,例如从PlayerRun — >PlyerIdle, state的值为 equal 0 。其余的按照代码中的枚举对应的数值就行了。并且,要 注意将Has Exit Time叉掉 ,这个选项意味着有退出动画的时间,导致动画切换不流畅了。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_游戏引擎_15

还有一步需要设置的是,我们需要将Tilemap设置成Ground层。需要自己添加一个。并且在Player的Jumpable Ground那里改成我们添加的Ground,不然角色会出现跳不起来的现象。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_unity_16

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_时间轴_17


Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_ci_18

总结

本章我们学会了如何为角色添加动画,以及如何使用C#和Animation Controller去控制多个动画的切换。但是其中还是有一些容易出错的细节需要注意,例如设置Ground层来控制跳跃次数、叉掉Has Exit Time来提升动画切换的流畅度等等。(最近忙着和对象商量五一去哪旅游,学得不是很勤,这一篇写了3天才写完,预算不是很够,希望后面能赚够钱,或者直接来个富婆,今天不如贴个富婆图哈哈哈)。

Unity代码里设置好了帧率构建后还是很慢 unity帧数很低_游戏引擎_19