导入

此文章的实战部分需要结合我后面的文章:

Unity数据持久化之Json - 张先生的小屋 (klned.com)

Unity之UGUI概述 - 张先生的小屋 (klned.com)

进行实现

模型的制作过程

1.模型的制作过程

美术工种——建模

第一步:建模

第二步:展UV

第三步:材质和纹理贴图

美术工种——动作

第四步:骨骼绑定

第五步:动画制作

具体过程

总结

美术工种——建模

第一步:建模——三角面片拼凑模型

第二步:展UV——展开模型的网格到平面上产生映射关系

第三步:材质和纹理贴图——使用UV信息画贴图选择材质出效果

美术工种——动作

第四步:骨骼绑定——对模型进行骨骼关联

第五步:动画制作——利用模型骨骼制作动画

2D相关

第一节:图片导入设置

图片导入概述

知识点一

Unity支持的图片格式有很多

BMP:是Windows操作系统的标准图像文件格式,特点是几乎不进行压缩,占磁盘空间大

TIF:基本不损失图片信息的图片格式,缺点是体积大

JPG:一般指JPEG格式,属于有损压缩格式,能够让图像压缩在很小的存储空间,一定程度上会损失图片数据,无透明通道

PNG:无损压缩算法的位图格式,压缩比高,生成文件小,有透明通道 。

TGA:支持压缩,使用不失真的压缩算法,还支持编码压缩。体积小,效果清晰,兼备BMP的图像质量和JPG的体积优势,有透明通道

PSD:是PhotoShop(PS)图形处理软件专用的格式,通过一些第三方工具或自制工具可以直接将PSD界面转为UI界面

其它还支持 EXR、GIF、HDR、IFF、PICT等等

其中Unity最常用的图片格式是 JPG、PNG、TGA三种格式

知识点二 图片设置的6大部分

1.纹理类型

2.纹理形状

3.高级设置

4平铺拉伸

5.平台设置

6.预览窗口

纹理类型设置

总体

细节

纹理形状设置

知识点一 纹理形状主要是设置什么?

纹理不仅可以用于模型贴图

还可以用于制作天空盒和反射探针

纹理形状设置 主要就是用于在两种模式之间进行切换

设置讲解

纹理高级设置

知识点一 高级设置是设置什么?

高级设置主要是纹理的一些尺寸规则、读写规则、以及MipMap相关设置

知识点二 参数讲解

知识点三 MipMap是什么?

在三维计算机图形的贴图渲染中有一个常用的技术被称为Mipmapping。

为了加快渲染速度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件

这样的贴图被称为mipmap

Mipmap 需要占用一定的内存空间

Mipmap中每一个层级的小图都是主图的一个特定比例的缩小细节的复制品

虽然在某些必要的视角,主图仍然会被使用,来渲染完整的细节。

但是当贴图被缩小或者只需要从远距离观看时,mipmap就会转换到适当的层级

因为mipmap贴图需要被读取的像素远少于普通贴图,所以渲染的速度得到了提升。

而且操作的时间减少了,因为mipmap的图片已经是做过抗锯齿处理的,从而减少了实时渲染的负担。

放大和缩小也因为mipmap而变得更有效率。

如果贴图的基本尺寸是256x256像素的话,它mipmap就会有8个层级。

每个层级是上一层级的四分之一的大小

依次层级大小就是:128x128;64x64;32x32;16x16;8x8;4x4;2x2;1x1(一个像素)

说人话,开启MipMap功能后,Unity会帮助我们根据图片信息生成n张不同分辨率的图片

在场景中会根据我们离该模型的距离选择合适尺寸的图片用于渲染,提升渲染效率

纹理平台打包

知识点一 平台设置主要设置什么?

平台设置主要设置纹理最终打包时在不同平台的尺寸、格式、压缩方式

它非常的重要,因为它影响了你的包大小和读取性能方面的问题

知识点二 参数相关

第二节:Sprite

Sprite Editor—Single图片编辑

知识点一 SpriteEditor是什么?

顾名思义,SpriteEditor就是 精灵图片编辑器

它主要用于编辑2D游戏开发中使用的Sprite精灵图片

它可以用于编辑 图集中提取元素,设置精灵边框,设置九宫格,设置轴心(中心)点等等功能

知识点二 安装 2D Sprite

新版本Unity 需要安装 2D Sprite包才能使用SpriteEditor

知识点三 Single图片编辑 功能讲解


//Single图片编辑主要讲解的就是在设置图片时
//将精灵图片模式(Sprite Mode)设置为Single的精灵图片在Sprite Editor窗口中如何编辑

//1.Sprite Editor
//  基础图片设置(右下角窗口)
//  主要用于设置单张图片的基础属性

//2.Custom Outline(决定渲染区域)
//  自定义边缘线设置,可以自定义精灵网格的轮廓形状
//  默认情况下不修改都是在矩形网格上渲染,边缘外部透明区域会被渲染,浪费性能
//  使用自定义轮廓,可以调小透明区域,提高性能

//3.Custom Physics Shape(决定碰撞判断区域)
//  自定义精灵图片的物理形状,主要用于设置需要物理碰撞判断的2D图形
//  它决定了之后产生碰撞检测的区域

//4.Secondary Textures(为图片添加特殊效果)
//  次要纹理设置,可以将其它纹理和该精灵图片关联
//  着色器可以得到这些辅助纹理然后用于做一些效果处理
//  让精灵应用其它效果

Sprite Editor—Multiple图片编辑

知识点一 Multiple图集元素分割 当我们的图片资源是图集时

我们需要在设置时将模式设置为Multiple

这时我们可以使用Sprite Editor自带的功能进行图集元素分割

知识点二 参数讲解

Sprite Editor—Polygon多边形图片编辑

知识点一 Polygon是什么

是sprite的一种图片模式,和single模式类似,但是可以自定义一个3-128条边的渲染边框,来渲染多边形图片,实际使用较少。

SpriteRenderer 精灵渲染器

知识点一 Sprite Renderer是什么

顾名思义,Sprite Renderer是精灵渲染器

所有2D游戏中游戏资源(除UI外)都是通过Sprite Renderer让我们看到的

它是2D游戏开发中的一个极为重要的组件

知识点二 代码设置

GameObject obj = new GameObject();
SpriteRenderer sr = obj.AddComponent<SpriteRenderer>();
//动态的改变图片
sr.sprite = Resources.Load<Sprite>("dead1");
//动态的加载 图集中的图
Sprite[] sprs = Resources.LoadAll<Sprite>("RobotBoyIdleSprite");
sr.sprite = sprs[10];

print(sprs[10].name);

知识点三 参数设置

SpriteCreator 精灵创造者

知识点一 Sprite Creator是什么?

顾名思义,Sprite Creator是精灵创造者 我们可以利用Sprite Editor的多边形工具创造出各种多边形 Unity也为我们提供了现成的一些多边形 它的主要作用是2D游戏的替代资源 在等待美术出资源时我们可以用他们作为替代品 有点类似Unity提供的自带几何体 替代资源是做demo和学习时的必备品

知识点二 使用Sprite Creator

在Project窗口右键创建各种形状的Sprite精灵图片

SpriteMask 精灵遮罩

知识点一 SpriteMask是什么?

顾名思义,SpriteMask是精灵遮罩的意思

它的主要作用就是对精灵图片产生遮罩

制作一些特殊的功能,比如只显示图片的一部分让玩家看到

知识点二 参数相关

SortingGroup 排序分组

知识点一 SortingGroup是什么?

顾名思义,SortingGroup是排序分组的意思

它的主要作用就是对多个精灵图片进行分组排序

通常的使用方法是父类加上SortingGroup ,然后子类都会受到父类SortingGroup 层级的影响。

Unity会将同一个排序组中的精灵图片一起排序,就好像他们是单个游戏对象一样 (子对象自己的层级会类似失活的状态)

主要作用是对于需要分层的2D游戏用于整体排序

知识点二 注意事项

1.子排序组,先排子对象 再按父对象和别人一起排 (同层和同层比)

2.多个 挂载排序分组组件的预设体 之间 通过修改 排序索引号来决定前后顺序

SpriteAtlas 精灵图集

知识点一 为什么要打图集

打图集的目的就是减少DrawCall 提高性能

具体DrawCall是什么在NGUI中已有笔记

知识点二 在Unity中打开自带的打图集功能

在工程设置面板中打开功能

Edit——>Project Setting——>Editor

Sprite Packer(精灵包装器,可以通过Unity自带图集工具生成图集)

Disabled:默认设置,不会打包图集

Enabled For Builds(Legacy Sprite Packer):Unity仅在构建时打包图集,在编辑模式下不会打包图集

Always Enabled(Legacy Sprite Packer):Unity在构建时打包图集,在编辑模式下运行前会打包图集

Legacy Sprite Packer传统打包模式 相对下面两种模式来说 多了一个设置图片之间的间隔距离

Padding Power:选择打包算法在计算打包的精灵之间以及精灵与生成的图集边缘之间的间隔距离

间隔距离(padding)这里的数字 代表2的n次方

Enabled For Build:Unity进在构建时打包图集,在编辑器模式下不会打包

Always Enabled:Unity在构建时打包图集,在编辑模式下运行前会打包图集

知识点三 打图集面板参数相关

知识点四 代码控制

GameObject obj = new GameObject();

SpriteRenderer sr = obj.AddComponent();

//加载图集资源

SpriteAtlas spriteAtlas = Resources.Load(“MyAtlas”);

//加载图集资源中的某一张小图

sr.sprite = spriteAtlas.GetSprite(“dead1”);

知识点五 观察DrawCall数量

打开status后,查看其中的Batches即可

第三节:2D物理系统

刚体

知识点一 学习2D物理系统的前提

学习2D物理系统之前建议先学习Unity入门当中的3D物理系统

因为他们非常的类似

由于我们之前详细讲解了3D物理系统

所以在讲解2D物理系统时会相对简洁一些

一些讲过的知识点就不过多赘述了

知识点二 2D物理系统中的刚体组件

刚体是物理系统中用于帮助我们进行模拟物理碰撞中力的效果的

2D物理系统中的刚体和3D中的刚体基本是一样的

最大的区别是对象只会在XY平面中移动,并且只在垂直于该平面的轴上旋转

知识点三 参数相关

知识点四 如何选择不同类型的刚体

Dynamic动态刚体:受力的作用,要动要碰撞的对象

Kinematic运动学刚体:通过刚体API移动的对象,不受力的作用,但是想要进行碰撞检测

Static静态刚体:不动不受力作用的静态物体,但是想要进行碰撞检测

知识点五 刚体API

//加力

Rigidbody2D rigid = this.GetComponent();

rigid.AddForce(new Vector2(0, 100));

//速度

rigid.velocity = new Vector2(1, 0);

#endregion

碰撞器

知识点一 碰撞器是用来干嘛的?

碰撞器是用于在物理系统中 表示物体体积的的(形状或范围)

刚体通过得到碰撞器的范围信息进行计算

判断两个物体的范围是否接触

如果接触 刚体就会模拟力的效果产生速度和旋转

知识点二 2D碰撞器

1.圆形碰撞器

2.盒状碰撞器

3.多边形碰撞器

4.边界碰撞器

5.胶囊碰撞器

6.复合碰撞器

知识点三 碰撞检测函数

碰撞检测函数 和 3D碰撞检测函数除了名字不同外其他基本一致(多了2D)

物理材质

知识点一 什么是物理材质

物理材质是用于决定在物体产生碰撞时这些物体之间的摩擦和弹性表现的

通过物理材质我们可以做出类似 斜坡不滑落,小球反弹等效果

知识点二 参数讲解

恒定力

知识点一 什么是恒定力?

恒定力是一个特殊的脚本

它可以给一个2D刚体持续添加一个力

在做一些随着时间推移而加速的对象时很适用

比如类似火箭发射等效果

恒定力脚本会线性的为对象添加力和扭矩力 让其移动和旋转

知识点二 参数讲解

效应器

知识点一 2D效应器是什么?

2D效应器是配合2D碰撞器一起使用

可以让游戏对象在相互接触时产生一些特殊的物理作用力

可以通过2D效应器

快捷的实现一些

传送带 互斥 吸引 漂浮 单向碰撞等等效果

知识点二 不同种类2D效应器的使用

1.区域效应器

2.浮力效应器

3.点效应器

4.平台效应器

5.表面效应器

总结

效应器其实只是Unity为我们写好的一些2D游戏中常用功能的一些代码

在实际开发中我们不应该过于依赖效应器

如果发现效应器和自己的游戏需求不太匹配时

我们完全可以自己实现符合需求的“效应器”

第四节:SpriteShape

SpriteShapeProfile 精灵形状概述文件

知识点一 SpriteShape是用来做什么的?

顾名思义,SpriteShape是精灵形状的意思

从名字上看不出到底是用来干什么的

其它它主要是方便我们以节约美术资源为前提

制作2D游戏场景地形或者背景的

知识点二 导入SpriteShape工具

在Package Manager中导入相关工具

知识点三 参数

1.资源面板:SpriteShape:

2.场景面板:精灵形状渲染器和控制器(Sprite Shape Renderer,Sprite Shape Controller):

知识点四 注意

经过测试,最新版的SpriteShape在资源创建不再有open和closed的区别(新版本让open的模板同时管理开放和封闭图像了),只有在场景创建gameobject的时候可以选择(无非是有没有封闭图像的区别),原因可能是closed的资源不好用,用来封闭资源是使用是通过角度判定来选择图像的,不如直接靠每一个点来单独来决定每一段的图形是什么更加灵活。

第5节: Tilemap

瓦片资源

知识点一 什么是Tilemap?

Tilemap一般称之为 瓦片地图或者平铺地图

是Unity2017中新增的功能

主要用于快速编辑2D游戏中的场景

通过复用资源的形式提升地图多样性

工作原理就是用一张张的小图排列组合为一张大地图

它和SpriteShape的异同

共同点:

他们都是用于制作2D游戏的场景或地图的

不同点:

1.SpriteShape可以让地形有弧度,TileMap不行

2.TileMap可以快捷制作有伪“Z”轴的地图,SpriteShape不行

知识点二 Tilemap的最小单位——“瓦片”

方法一:

Assets——>Create——>2D——>Tiles(可以选类型)

方法二:

在Tile Palette瓦片调色板窗口创建

1.首先新建一个瓦片地图编辑文件

2.将资源拖入到窗口中选择要保存的路径

瓦片(rule tiles)参数:

瓦片调色板窗口

知识点一 创建瓦片调色器相关参数

知识点二 TilePalette瓦片调色板窗口基本操作技巧

知识点三 TilePalette瓦片调色板窗口面板基本功能

知识点四 编辑瓦片地图

方法一:通过瓦片调色板文件创建

方法二:直接在场景中进行创建

矩形瓦片地图用于做横版游戏地图

六边形瓦片地图用于做策略游戏地图

等距瓦片地图用于做有"Z"轴的2D游戏

注意:

在编辑等距瓦片地图时

1.需要修改工程的自定义轴排序 以Y轴决定渲染顺序

2.如果地图存在前后关系需要修改TileRenderer的渲染模式

3.可以通过Z轴偏移来控制绘制单个瓦片时的高度

4.精灵纹理的中心点会影响最终的显示效果

等距瓦片地图修改部分:

瓦片地图关键脚本和碰撞器

知识点一 瓦片地图关键脚本参数

知识点二 瓦片地图碰撞器

为挂载TilemapRenerer脚本的对象添加Tilemap Collider2D脚本

会自动添加碰撞器

注意:想要生成碰撞器要对单个瓦片对象的Collider Type类型进行设置,sprite是根据图片类型来设置碰撞器(默认),Grid为固定方块,none为不设置碰撞器

可以用符合碰撞器来合并碰撞器,减少性能消耗。

瓦片地图拓展包-导入

知识点一 官方拓展包

工程地址:

https://github.com/Unity-Technologies/2d-extras

通过阅读文档得知,可以通过Unity pack管理来进行导入和管理

知识点二 了解官方拓展包为Tilemap添加了什么

拓展包为Tilemap添加新的瓦片类型和笔刷类型 帮助我们更加方便的编辑2D场景

注意

Unity实际上在2021后的最新版本里面的tilemap已经集成自带了扩展包的一些内容(比如rule瓦片等一些瓦片类型)。

瓦片地图拓展包—新增瓦片类型

知识点一 规则瓦片 RuleTile

定义不同方向是否存在连接图片的规则

让我们更加快捷的进行地图编辑

知识点二 动画瓦片 AnimatedTile

可以指定序列帧

产生可以播放序列帧动画的瓦片

知识点三 管道瓦片 PipelineTile

根据自己相邻瓦片的数量更换显示的图片

知识点四 随机瓦片 RandomTile

根据你设置的图片,随机从中选一个进行绘制

知识点五 地形瓦片 TerrainTile

有点类似规则瓦片,只不过地形瓦片已经帮助你预先定好了一些常用的规则

知识点六 权重随机瓦片 WeightedRandomTile

可以不平均随机选择图片的瓦片

即玮可以规定概率的随机瓦片

知识点七 (高级)规则覆盖瓦片 (Advanced)Rule Override Tile

在规则瓦片的基础上 改变图片或者指定启用的规则

这样可以简便的设定规则相近的规则瓦片

瓦片地图拓展包—新增笔刷类型

知识点一 新建自定义笔刷(创建在资源中的)

1.预设体笔刷——用于快捷刷出想要创建的精灵

2.预设体随机笔刷——用于快捷随机刷出想要创建的精灵

3.随机笔刷——可以指定瓦片进行关联,随机刷出对应瓦片

知识点二 拓展笔刷(调色板直接自带的)

  1. Coordinate Brush 坐标笔刷 —— 可以实时看到格子坐标

  2. GameObject Brush 游戏对象笔刷 —— 可以在场景中选择和擦除游戏对象仅限于选定的游戏对象的子级

  3. Group Brush 组合笔刷 —— 可以设置参数 当点击一个瓦片样式时 会自动取出一个范围内的瓦片

  4. Line Brush 线性笔刷 —— 决定起点和终点画一条线出来

  5. Random Brush 随机笔刷 —— 和之前的自定义随机画笔类似,可以随机画出瓦片

  6. Tint Brush 着色笔刷 —— 可以给瓦片着色 瓦片的颜色锁要开启(Inspector窗口切换Debug模式 修改Flags)

  7. Tint Brush(Smooth) 光滑着色笔刷 —— 可以给瓦片进行渐变着色,需要按要求改变材质

瓦片地图—代码控制

知识点一 获取Tilemap和TileBase和Grid

Tilemap组件:用于管理瓦片地图

TileBase组件:瓦片资源对象基类

Grid组件:用于坐标转换

使用他们需要引用命名空间

知识点二 重要API

1.清空瓦片地图

map.ClearAllTiles();

2.获取指定坐标格子

TileBase tmp = map.GetTile(Vector3Int.zero)

print(tmp);

3.设置删除瓦片

map.SetTile(new Vector3Int(0, 2, 0), tileBase);

map.SetTile(new Vector3Int(1, 0, 0), null);

map.SetTiles()

4.替换瓦片(将所有相同瓦片进行替换)

map.SwapTile(tmp, tileBase);

5.世界坐标转格子坐标

可以用来让鼠标和画面进行互动

世界坐标转格子坐标

传入的参数是世界坐标

//grid.WorldToCell()

动画基础

第1节: Animation动画窗口

认识Animation动画窗口

知识点一 打开Animation窗口

Window——>Animation——>Animation

知识点二 Animation窗口是用来干啥的

Animation窗口 直译就是动画窗口

它主要用于在Unity内部创建和修改动画

所有在场景中的对象都可以通过Animation窗口为其制作动画

原理:

制作动画时:记录在固定时间点对象挂载的脚本的变量变化

播放动画时:将制作动画时记录的数据在固定时间点进行改变,产生动画效果

知识点三 关键词说明

动画时间轴:

每一个动画文件都有自己的一个生命周期,从动画开始到结束

我们可以在动画时间轴上编辑每一个动画生命周期中变化

动画中的帧:

假设某个动画的帧率为60帧每秒,意味着该动画1秒钟最多会有60次改变机会

每一帧的间隔时间是 1s/60 ≈ 16.67毫秒

也就是说 我们最快可以每16.67毫秒改变一次对象状态

关键帧:

动画在时间轴上的某一个时间节点上处于的状态

知识点四 认识Animation窗口功能

创建编辑Animation动画

知识点一 创建动画

1.在场景中选中想要创建动画的对象

2.在Animation窗口中点击创建

3.选择动画文件将要保存到的位置

保存动画文件时,Unity会帮助我们完成以下操作

1.创建一个 Animator Controller(动画控制器或称之为动画状态机) 资源(新动画系统)

2.将新创建的动画文件添加到Animator Controller中

3.为动画对象添加Animator组件

4.为Animator组件关联创建的Animator Controller文件

知识点二 窗口上的变化

知识点三 关键帧模式下编辑动画

给物体加上关键帧后,可以设定物体在当前帧数下的变量值,Unity会自动将中间的变化过程进行衔接(具体变化方式可以通过曲线模式进行微调)

知识点四 曲线模式下编辑动画

通过点击Animation窗口左下角的Curves进行切换

线条颜色和变量颜色对应

可以微调物体在不同帧之间衔接的细节(如匀速 先快后满还是先满后快)

知识点五 动画文件界面参数

代码控制动画(老动画系统)

知识点一 什么是老动画系统

Unity中有两套动画系统

新:Mecanim动画系统——主要用Animator组件控制动画

老:Animation动画系统——主要用Animation组件控制动画(Unity4之前的版本可能会用到)

目前我们为对象在Animation窗口创建的动画都会被新动画系统支配

有特殊需求或者针对一些简易动画,才会使用老动画系统

知识点二 老动画系统控制动画播放

注意:

在创建动画之前为对象添加Animation组件之后再制作动画

这时制作出的动画和之前的动画格式是有区别的

Animation参数

知识点三 代码控制播放

animation = this.GetComponent();

1.播放动画

2.淡入播放,自动产生过渡效果

3.前一个播完再播放下一个

4.停止播放所有动画

5.是否在播放某个动画

6.播放模式设置

7.其它(了解即可,新动画系统中会详细讲解)

层级和权重以及混合(老动画系统需要通过代码来达到动画的遮罩、融合等效果)

设置层级

设置权重

混合模式 叠加还是混合

设置混组相关骨骼信息

知识点四 动画事件

动画事件主要用于处理 当动画播放到某一时刻想要触发某些逻辑

比如进行伤害检测、发射子弹、特效播放等等

总结

老动画系统主要用于处理老版本项目和简单的一些自制动画

新项目都不建议大家使用了

关键组件:Animation

第2节: Animator动画状态机

有限状态机概念

知识点一 什么是有限状态机

有限状态机(Finite - state machine, FSM)

又称有限状态自动机,简称状态机

是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型

有限:表示是有限度的不是无限的

状态:指所拥有的所有状态

举例说明:

假设我们人会做很多个动作,也就是有很多种状态

这些状态包括 站立、走路、跑步、攻击、防守、睡觉等等

我们每天都会在这些状态中切换,而且这些状态虽然多但是是有限的

当达到某种条件时,我们就会在这些状态中进行切换

而且这种切换时随时可能发生的

知识点二 有限状态机对于我们的意义

游戏开发中有很多功能系统都是有限状态机

最典型的状态机系统

动作系统 —— 当满足某个条件切换一个动作,且动作是有限的

AI(人工智能)系统 —— 当满足某个条件切换一个状态,且状态时有限的

所以状态机是游戏开发中一个必不可少的概念

知识点三 最简单的状态机实现

最简单的状态机实现代码就是基于switch的实现

假设我们只有一个值来控制当前玩家的状态

string animName = “idle”;

switch (animName)

{

case “idle”:

//待机动作逻辑

break;

case “move”:

//移动动作逻辑

break;

case “run”:

//跑步动作逻辑

break;

case “atk”:

//攻击动作逻辑

break;

}

总结

游戏开发中某些系统中存在有限种状态的切换变化时

我们可以使用有限状态机的设计思路来进行逻辑编写

Animator Controller动画控制器(状态机)

知识点一 创建动画状态机

1.通过为场景中物体创建动画时自动创建

2.手动创建动画状态机文件

知识点二 基础使用——添加动画

1.自动添加——为对象创建动画后会自动将动画添加到状态机中

2.手动添加1——将动画文件拖入到状态机中(注意:老动画拖入会有警告)

3.手动添加2——右键创建状态,再关联动画

知识点三 基础使用——添加切换条件

在左侧面板点击参数页签

可以在这里添加4中类型的切换条件

知识点四 状态机参数

代码控制动画状态机切换

知识点一 关键组件Animator

参数相关

知识点二 Animator中的API

我们用代码控制状态机切换主要使用的就是Animator提供给我们的API

我们知道一共有四种切换条件 int float bool trigger

所以对应的API也是和这四种类型有关系的

animator = this.GetComponent();

1.通过状态机条件切换动画

//animator.SetFloat(“条件名”, 1.2f);

//animator.SetInteger(“条件名”, 5);

//animator.SetBool(“条件名”, true);

//animator.SetTrigger(“条件名”);

//animator.GetFloat(“条件名”);

//animator.GetInteger(“条件名”);

//animator.GetBool(“条件名”);

2.直接切换动画 除非特殊情况 不然一般不使用

//animator.Play(“状态名”);

2D动画

第1节: 序列帧动画

2D序列帧动画

知识点一 什么是序列帧动画

我们最常见的序列帧动画就是我们看的 日本动画片

以固定时间间隔 按序列切换图片 就是 序列帧动画的本质

当固定时间间隔足够短时 我们肉眼就会认为图片是连续动态的 进而形成动画(会动的画面)

它的本质和游戏的帧率概念有点类似

原理就是在一个循环中按一定时间间隔不停的切换显示的图片

知识点二 代码制作序列帧动画

我们先尝试用原理 通过代码来实现序列帧动画

sr = this.GetComponent();

sr.sprite = sprs[nowIndex];

知识点三 Animation窗口制作序列帧动画

方法一:

1.创建一个空物体

2.创建一个动画

3.直接将某一个动作的序列帧拖入窗口中

方法二:

直接将图片拖入Hierarchy层级窗口中

注意:需要修改动画帧率 来控制动画的播放速度

第2节: 骨骼动画——2D Animation

单张图片骨骼编辑

知识点一 什么是2D骨骼动画

首先回顾一下序列帧动画

传统的序列帧动画为了达到好的动画效果

理论上来说,图片越多,动作越流畅

往往需要较多的美术资源,虽然效果好但是资源占用较多

而2D骨骼动画是利用3D骨骼动画的制作原理进行制作的

将一张2D图片分割成n个部位,为每个部位绑上骨骼,控制骨骼旋转移动

达到用最少的2D美术资源做出流畅的2D动画效果

知识点二 Unity中如何制作2D骨骼动画

主要方式有两种

1.使用Unity2018新加功能 2D Animation 工具制作

2.使用跨平台骨骼动画制作工具 Spine 制作

知识点三 导入2D Animation工具

在Package Manager窗口 搜索 2D Animation并安装

知识点四 面板讲解

导入工具后 在Sprite Editor窗口会多一个选项 Skinning Editor

参数讲解:

图集图片骨骼编辑

知识点一 用法

和单张图片基本类似。只不过经常是多个部位被切割开来单独建立骨骼

1.设置Sprite为图集模式

2.对图集图片进行切片

3.分别设置骨骼

4.在场景中按照骨骼的父子顺序建立完整的人物(例如腰部脊椎带动全身,上半身脊椎控制头部和手臂)。

5.完成对应的动画进行使用

图二中注意骨骼对应的父子关系。

psb图片骨骼编辑

知识点一 认识PSB文件

认识PSB之前先认识PS

PS(photoshop)是一款强大的图像处理软件

在各领域都被广泛使用

在游戏行业中也是美术同学使用最多的图像处理软件之一

PSD和PSB两种格式,都是PS这款软件用于保存图像处理数据的文件格式

PSD和PSB两种格式并没有太大的区别

最大的区别是PSD格式兼容除PS以外的其它一些软件

而PSB只能用PS打开

在Unity中官方建议使用psb格式

知识点二 在Unity中使用PSB文件

需要在Packages Manager窗口中引入 2D PSD Importer工具包

知识点三 设置PSB文件关键参数

知识点四 为PSB文件编辑骨骼信息

由于PSB文件自带分层(注意左侧多出的Sprite可以直接快速选取分层的图片)分层后,untiy并不知道骨骼和图层之间的对应关系,所以,我们创建完整体骨骼后,需要对 各层的图层与骨骼之间 使用sprite influence对各大骨骼进行各自对应单独的绑定

知识点五 为PSB文件制作骨骼动画

与上文类似,需要注意的是,psd预制体拖动到场景后,会直接自动创建对应的骨骼,如果想要修改图层直接的父子关系(如为了让下图的法杖放到人物手上),需要unlock解绑预制体。

注意:建议PSD对象都放置在一个父类空物体下面,比较方便管理

反向动力学IK(重点)

知识点一 什么是IK?

在骨骼动画中,构建骨骼的方法被称为正向动力学

它的表现形式是,子骨骼(关节)的位置根据父骨骼(关节)的旋转而改变

用我们人体举例子

当我们抬起手臂时,是肩部关节带动的整个手臂的运动,用父子骨骼理解的话就是父带动了子

而IK全称是Inverse Kinematics,翻译过来的意思就是反向动力学的意思

它和正向动力学恰恰相反

它的表现形式是,子骨骼(关节)末端的位置改变会带动自己以及自己的父骨骼(关节)旋转

用我们人体举例子

当我们拿起一个杯子的时候是用手掌去拿,以杯子为参照物,我们移动杯子的位置,手臂会随着杯子一起移动

用父子骨骼理解的话就是子带动了父

博主注:不妨想象为正向动力学为主动用肌肉牵引关节,反向动力学为有外力拽着你的身体部位在移动从而导致你的其他部位也被牵引。前者需要多方面的力(做一个动作需要动所有的关节开发效率更低,但是做的好貌似表现更棒)后者只有一个外界的力(开发动作的时候效率更快,只需要动一个部位,但是如果处理不好有一种说不出来的僵硬感,类似尸体被牵动?)

知识点二 2D IK包引入

在Package Manager窗口中引入2D IK工具包

需要在Advanced高级选项中选中Show preview packages(显示预览包)

这样才能看到2D IK相关内容

注意:如果在引入包时报错,需要在Windows防火墙中添加入站规则,而且新版本已经集成该包

知识点三 2D IK的使用

CCD无法全体关节完全反向(类似锁链)FABRIK则可以完全反向(类似炮塔旋转)

知识点四 IK对于我们的意义

1.瞄准功能

2.头部朝向功能

3.拾取物品功能

等等有指向性的功能时 我们都可以通过IK来达到目的

最大的作用,可以方便我们进行动画制作

换装

知识点一 如何在不同psb文件中制作换装资源

1.保证个部位在PS文件中的统一

2.基础部位可选择性隐藏

知识点二 编辑换装资源的骨骼信息

注意事项:

不同文件的骨骼信息必须统一,所以我们直接使用复制的方式

复制粘贴的时候,只需要粘贴骨骼即可,蒙皮不太可能完全相同,事后自己在进行蒙皮即可。

并且在使用SpriteResolver时会产生一些精灵皮肤被不知名骨骼错位拉伸的问题,需要勾选Sprite Skin的Auto ReBind参数(经过对比仅有Unity2021版本以上才具有这个参数),勾选之后才可以解决精灵被不知名骨骼错误的拉伸的问题。

知识点三 手动添加关键组件和数据文件

1.首先创建SpriteLibraryAsset数据文件

2.为跟对象添加SpriteLibrary并关联数据文件

3.为换装部位关联SpriteResolver

总结 如何选择 同一文件和 不同文件 制作换装资源两种方案

换装较少的游戏 比如只有面部表情更换 可以使用同一psb文件方案

换装较多的游戏 比如各部位有n种装备 可以使用不同psb文件方案

不同psb文件 拓展性更强

知识点四 代码实例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.U2D.Animation;
 
public class ArmourController : MonoBehaviour
{
//获得所有的SpriteResolver脚本列表
    public List<SpriteResolver> spriteResolvers = new List<SpriteResolver>();
    
    void Start()
    {
//获得所有的SpriteResolver脚本
        foreach (var resolver in FindObjectsOfType<SpriteResolver>())
        {
            spriteResolvers.Add(resolver);
 
        }
    }
 
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.E))
        {
            foreach (var resolver in FindObjectsOfType<SpriteResolver>())
            {
                //在SpriteResolver脚本中设置组为当前组resolver.GetCategory(),标签为"fire"
                resolver.SetCategoryAndLabel(resolver.GetCategory(), "fire");
            }
 
        }
    }
}

重要提示

在Unity2021版本之后的蒙皮编辑器里面的不再那么方便地提供皮肤分组功能,需要我们自己手动创建Sprite Library Asset文件然后手动关联精灵皮肤,还要手动为这些精灵皮肤对象添加Sprite Resolutions脚本,这也间接导致了同一psb文件方案的简便换装失效(但是同一psb依然可以使用SpriteLibraryAsset方案)

实际上,使用Sprite Library Asset将极大的增加换装的扩展性

换装可用的重点是部位关联骨骼名必须得一一对应,因为换装后会直接修改对应精灵和骨骼,如果骨骼名和数量对不上就会报错。

补充 实战实例

(17条消息) 18.Unity2D 横版 骨骼动画 之 可扩展简单角色换装_unity 2d骨骼替换_ζั͡ ั͡雾 ั͡狼 ั͡✾的博客-CSDN博客

第3节: 骨骼动画——Spine

spine运行库导入

知识点一 Spine是什么?

Spine是一个收费的跨平台的2D骨骼动画制作工具

它支持Unity,UE,Cocos2D,Cocos2D-x等等游戏引擎

相对Unity2018才推出的 2D Animation

Spine是目前商业游戏中较为常用的骨骼动画制作方案 稳定且高效

官方地址:zh.esotericsoftware.com/

知识点二 如何学习Spine

制作骨骼动画时美术人员的工作

除非你是要做独立游戏,美术程序一人包

那么我们没有必要去学习如何通过Spine制作骨骼动画

我们只需要学习如何在Unity中通过程序使用Spine制作的资源

如果想要学习如何制作Spine骨骼动画,可以根据官网提供的教学内容进行学习

知识点三 导入Unity使用的Spine运行库

有了Spine提供的支持Unity开发的运行库

我们才能在Unity中使用Spine制作的骨骼动画

你可以简单理解其实就是官方写好的识别文件处理文件呈现效果的代码

我们只需要学习如何使用它提供的API即可

Spine骨骼动画文件的使用

知识点一 Spine导出的Unity资源

Spine导出的资源有3个文件

.json 存储了骨骼信息

.png 使用的图片图集

.atlas.txt 图片在图集中的位置信息

当我们把这三个资源导入到已经引入了Spine运行库的Unity工程后

会自动为我们生成

_Atlas 材质和.atlas.txt文件的引用配置文件

_Material 材质文件

_SkeletonData json和_Atlas资源的引用配置文件

知识点二 使用Spine导出的骨骼动画

1.直接将_SkeletonData文件 拖入到场景中

选择创建 SkeletonAnimation对象

2.创建空对象 然后手动添加脚本进行关联

Unity会自动创建对应的网格和骨骼信息

Spine骨骼动画参数相关

知识点一 骨骼数据文件参数相关

知识点二 骨骼动画脚本参数相关

附带动画功能的脚本(如果使用unity原版动画创建 脚本名字会不一样):

点击Advanced可以进入高级设置面板:

在高级设置面板点击debug,可以进入debug调试面板:

Spine骨骼动画代码相关

知识点一 动画播放

方法一:直接改变SkeletonAnimation中参数

sa.loop = true;

sa.AnimationName = “jump”;

方法二:使用SkeletonAnimation中动画状态改变的函数

马上播放

sa.AnimationState.SetAnimation(0, jumpName, false);

排队播放

sa.AnimationState.AddAnimation(0, “walk”, true, 0);

知识点二 转向

sa.skeleton.ScaleX = -1;

知识点三 动画事件

动画开始播放

sa.AnimationState.Start += (t) =>

{

print( sa.AnimationName + “动画开始播放”);

};

动画被中断或者清除

sa.AnimationState.End += (t) =>

{

print(sa.AnimationName + “动画中断或者清除”);

};

播放完成

sa.AnimationState.Complete += (t) =>

{

print(sa.AnimationName + “动画播放完成”);

};

做动画时添加的自定义事件

sa.AnimationState.Event += (t, e) =>

{

print(sa.AnimationName + “自定义事件”);

};

知识点四 便捷特性

动画特性

[SpineAnimation]

骨骼特性

[SpineBone]

插槽特性

[SpineSlot]

附件特性

[SpineAttachment]

知识点五 获取骨骼、设置插槽附件

获取骨骼

Bone b = sa.skeleton.FindBone(boneName);

sa.skeleton.SetAttachment(slotName, attachmentName);

知识点六 在UI中使用

SkeletonGraphic(UnityUI)

博主总结

上面就是spine有关的相关内容,实际上,spine允许玩家使用untiy自带的animator来对动画进行管理,我个人来说,其实大部分情况下建议用animator统一动画系统,可以免去使用spine特有api的项目管理成本。当然,因人而异,对于熟练使用spine运行库的人来说,spine有一些自带的特有特性,某些地方也许会更出色和方便。

模型导入相关

第1节: 模型导入概述

模型导入概述

知识点一 Unity中使用的模型

Unity支持很多模型格式

比如

.fbx

.dae

.3ds

.dxf

.obj等等

99%的模型都不是在Unity中制作的,都是美术人员在建模软件中制作

如 3DMax、Maya等等

当他们制作完模型后,虽然Unity支持很多模型格式

但是官方建议是将模型在建模软件中导出为FBX格式后再使用

使用FBX模型格式的优势

1.减少不必要数据,提升导入效率

2.不需要再每台计算机上安装建模软件的授权副本

3.对Unity版本无要求,使用原始3D模型格式可能会因为版本不同导致错误或意外

如果美术同学不知道如何导出FBX格式的模型和导出规范

可以参考Unity官网文档或者百度谷歌

美术同学在导出模型时需要注意

1.https: docs.unity.cn/cn/2019.4/Manual/CreatingDCCAssets.html

2.坐标轴,人物面朝向为Z轴正方向,Y轴正方向为头顶方向,X轴正方向为人物右侧

知识点二 导入模型的基本流程

1.美术同学用3D建模软件制作好模型导出FBX格式模型资源

2.程序将这些模型资源导入到Unity的资源文件夹中

3.在Unity内部对这些模型进行基础设置——模型、骨骼、动作、材质

知识点三 如何在Unity中设置模型相关内容

在Project窗口选中导入的模型

在Inspector窗口进行相关设置

4个页签分别是

1.Model 模型页签

2.Rig 操纵(骨骼)页签

3.Animation 动画页签

4.Materials 材质纹理页签

通过这4个页签对模型动作相关信息设置完成后

之后我们才能在场景中更好的使用这些模型资源

第2节: Model模型页签

Model模型页签代码参数相关

知识点一 Model模型页签是设置什么的

该页签主要是用于设置

比如

模型比例设置

是否使导入模型中的摄像机和光源

网格压缩方式 等等相关信息

修改模型中存储的各种元素和属性

最终会影响在Unity中使用模型时的一些表现

知识点二 参数讲解

第3节: Rig操纵(骨骼)页签

Rig 操纵(骨骼)页签 知识点

知识点一 Rig操纵(骨骼)页签是用来干啥的

该页签主要是用于设置

如何将骨骼映射到导入模型中的网格,以便能够将其动画化

对于人形角色模型,需要分配或创建Avatar(替身信息)

对于非人形角色模型,需要在骨骼中确定根骨骼

简单来说Rig页签主要是设置骨骼和替身系统相关信息的

设置了他们,动画才能正常的播放

知识点二 面板基础参数讲解

知识点三 Avatar化身系统是什么

理解化身系统首先要知道骨骼动画是什么

通过我们之前基础知识的讲解和2D骨骼动画的讲解

相信大家已经了解骨骼动画是什么

3D动画的本质 也是骨骼动画

为制作好的模型绑定骨骼制作动画是模型动画的制作流程

形象的理解

对于人来说

人的整体结构都是一致的

另一个人能做的动作理论上来说我们是完全可以模仿出来的

而化身系统的本质,就是动作的模仿(复用)

我们可以把一个标准人形动作通过化身系统复用到其它人形模型上

只要保证他们的关节点对应关系是一致的

而这节课要学习的就是如何设置人形模型在化身系统中关节的对应关系

知识点四 化身系统设置讲解

总结(博主)

骨骼系统里面的人形可以当做Unity内置了一套骨骼动画,只要合理的绑定对应关节,同一个动作就可以在多套模型上复用。

第4节: Animation动画页签

Animation动画页签概述

知识点一 Animation动画页签是用来干啥的

当我们选中包含动画剪辑的的模型时

该页签将显示动画设置相关的内容

动画剪辑是Unity动画的最小构成元素

代表一个单独的动作

当美术同学做好动画导出时建议将模型和动画文件分别导出

1.导出包含网格信息不包含动作信息模型

2.导出不包含网格信息包含动作信息的动作(模型)文件

具体的导出规则可以参考

1.如何导入外部创建的模型资源

https:docs.unity.cn/cn/2019.4/Manual/CreatingDCCAssets.html

2.使用多个模型文件来导入动画

https:docs.unity.cn/cn/2019.4/Manual/Splittinganimations.html

知识点二 Animation动画页签的4大部分

1.基础信息设置

2.动画剪辑属性基本设置

3.动画剪辑属性其它设置

4.预览窗口

Animation页签 基础信息设置

参数

Animation动画页签 动画剪辑属性基本设置

参数

参考文献

(17条消息) 【Unity3D】Generic 动画中 Root Motion的概念和使用_为什么要烘焙root_天生爱赞美的博客-CSDN博客

(17条消息) 根运动 (Root Motion) – 工作原理_Arrow的博客-CSDN博客

较为通俗有用:

(17条消息) Unity动画系统学习笔记(二)根运动、动画事件与状态机行为_unity 根运动_夜槿笙歌的博客-CSDN博客

总结(博主)

重点在于3个烘培为姿势(bake into pose),如果不勾选后骨骼就会确确实实的移动(根运动),发生位移旋转,勾选的话就只是单纯的姿势(方便代码进行控制位移)。

Animation动画页签 动画剪辑其它信息设置

参数

总:

分:

总结(博主)

这里面比较重点的功能是遮罩和事件。其中,面板里的事件可以理解为通用的事件(比如声音之类的,只要使用这个动作都一定会触发的事件),如果你需要给不同gameobject定制不同事件(不同物体用这个动作的表现会有所不同),那还是采用animation窗口里面的添加事件来给每一个物体动画进行特制。

动画预览窗口

参数

第5节: Materials材质纹理页签

材质纹理页签 知识点

参数

3D动画相关

第1节: 3D动画的使用

3D动画的使用

知识点一 使用导入的3D动画

1.将模型拖入场景中

2.为模型对象添加Animator脚本

3.为其撞见Animator Controller动画控制器(状态机)

4.将想要使用的相关动作 拖入Animator Controller动画控制器(状态机)窗口

5.在Animator Controller动画控制器(状态机)窗口编辑动画关系(使用之前学习的状态机相关知识)

6.代码控制状态切换

知识点二 状态设置相关参数

我们可以选中状态机窗口中的某一个状态为其设置相关参数

我们可以称之为动画状态设置

主要设置的是 当前状态的播放速度等等细节

知识点三 连线设置相关参数

我们可以选中状态机窗口中的某一条箭头为其设置相关参数

我们可以称之为动画过渡设置

主要设置的是 从一个状态切换到另一个状态时 的表现效果和切换条件

总结

注意点

1.Has Exit Time是否启用 如果希望瞬间切换动画不需过多等待,取消该选项

2.Can Transition To self是否启用 如果希望自己不要打断自己,方便的处理方式是直接取消该选项,避免这种情况的最佳方法是将用于转换的 Paramaeters 标志、值等保留在转换条件之外。 例如,如果存在 Dead 标志,则可以通过在检查动画过渡后立即将该标志设置为 false 来纠正错误行为。

3.speed设置为-1可以让动画倒放(甚至位移也会反过来,可以让前进动作变成后退)。

第2节: 动画分层和遮罩

动画分层和遮罩

知识点一 动画分层的主要目的

动画分层的作用

游戏中会有这样的需求

人物健康状态时播放正常动画

人物非健康状态时播放特殊动画

比如血量低于一定界限,人物的大部分动作将表现为虚弱状态

我们可以利用动画分层来快速实现这样的功能

动画分层和动画遮罩结合使用

3D游戏中我们常常会面对这样的需求

人物站立时会有开枪动作

人物跑动时会有开枪动作

人物蹲下时会有开枪动作

从表现上来看光是开枪动作可能就有3种

如果要让美术同学做3种开枪动作费时又费资源

我们是否可以这样做

比如开枪动画只影响上半身

下半身根据实际情况播放站立,跑动,蹲下动作

通过上下半身播放不同的动画就可以达到动画的组合播放

动画分层的主要就是达到这两个目的

1.两套不同层动作的切换

2.结合动画遮罩让两个动画叠加在一起播放

提升动画多样性,节约资源

知识点二 如何使用动画分层

1.新建一个动画层

2.设置动画层参数

3.在该层中设置状态机

4.根据需求创建动画遮罩

animator = this.GetComponent();

animator.SetLayerWeight(animator.GetLayerIndex(“MyLayer2”), 1);

知识点三 参数

总结

利用动画分层我们可以做到

1.上下半身播放两个动画进行组合,比如上半身扔炸弹,下半身待机移动蹲下

2.快速制作正常状态和受伤状态的动作切换

重要用法:

1.当我们使用遮罩层的时候,我们通常会把默认状态设置为Null状态(没有动画),以免该层对默认层进行不必要的干扰,比如实现开枪效果之类的,肯定得鼠标右键才会触发上半身举枪效果,如下图)

2.使用Sync可以轻松的做出:两个层逻辑相同(实际上逻辑也可以改,你可以认为只是copy了一层的所有动作和逻辑连线,方便修改权重,不过你动作得重新加),动作不同的效果,可以广泛使用于角色受伤或者进化后会更换一套动画之类的场合

参考文献:

(17条消息) Unity中的动画系统和Timeline(4) AvatarMask和IK动画_穆玄的博客-CSDN博客

第3节: 动画1D混合

动画1D混合

知识点一 什么是动画混合

游戏动画中常见的功能就是在两个或者多个相似运动之间进行混合

比如

1.根据角色的速度来混合行走和奔跑动画

2.根据角色的转向来混合向左或向右倾斜的动作

你可以理解是高级版的动画过渡

之前我们学习的动画过渡是处理两个不同类型动作之间切换的过渡效果

而动画混合是允许合并多个动画来使动画平滑混合

知识点二 如何在状态机窗口创建动画混合状态

在Animator Controller窗口 右键->Create State->From New Blend Tree

知识点三 1D混合的使用

1D混合就是通过一个参数来混合子运动

注意:

往混合树里面加入动作时需要找到动画文件进行关联

参数

第4节: 动画2D混合

动画2D混合

知识点一 1D混合和2D混合

1D混合是用一个参数控制动画的混合,之所以叫1D是因为一个参数可以看做是1维线性的

2D混合你可以简单理解是用两个参数控制动画的混合,之所以叫2D是因为两个参数可以看做是2维平面xy轴的感觉

知识点二 2D混合的种类

1.2D Simple Directional 2D简单定向模式 运动表示不同方向时使用 比如向前、后、左、右走

2.2D Freeform Directional 2D自由形式定向模式 同上 运动表示不同方向时使用 但是可以在同一方向上有多个运动 比如向前跑和走

3.2D Freeform Cartesian 2D自由形式笛卡尔坐标模式 运动不表示不同方向时使用 比如向前走不拐弯 向前跑不拐弯 向前走右转 向前跑右转

4.Direct 直接模式 自由控制每个节点权重,一般做表情动作等

知识点三 详细简介

2D Simple Directional:最好在运动表示不同方向(例如“向前走”、“向后退”、“向左走”和“向右走”或者“向上瞄准”、“向下瞄准”、“向左瞄准”和“向右瞄准”)时使用。根据需要可以包括位置 (0, 0) 处的单个运动,例如“空闲”或“瞄准”。在 Simple Directional 类型中,在同一方向上_不_应该有多个运动,例如“向前走”和“向前跑”。

2D Freeform Directional:运动表示不同方向时,也使用此混合类型,但是您可以在同一方向上有多个运动,例如“向前走”和“向前跑”。在 Freeform Directional 类型中,运动集应始终包括位置 (0, 0) 处的单个运动,例如“空闲”。

2D Freeform Cartesian:最好在运动不表示不同方向时使用。凭借 Freeform Cartesian,X 参数和 Y 参数可以表示不同概念,例如角速度和线速度。一个示例是诸如“向前走不转弯”、“向前跑不转弯”、“向前走右转”、“向前跑右转”之类的运动。

Direct:此类型的混合树让用户直接控制每个节点的权重。适用于面部形状或随机空闲混合。

出处:Unity-2D 混合 - 哔哩哔哩 (bilibili.com)

知识点四 总结

前三种方式只是针对动作的不同采用不同的算法来进行混合的

第四种可以用多个参数进行融合

混合树中还可以再嵌入混合树,使用上是一致的,根据实际情况选择性使用

第5节: 动画子状态机

动画子状态机

知识点一 什么是子状态机

子状态机顾名思义就是在状态机里还有一个状态机

它的主要作用就是某一个状态时由多个动作状态组合而成的复杂状态

比如某一个技能它是由3段动作组合而成的,蹲下,开火,站起

当我们释放这个技能时会连续播放这3个动作

那么我们完全可以把他们放到一个子状态机中

知识点二 创建子状态机

在Animator Controller窗口中右键->Create Sub-State Machine

知识点三 编辑子状态机

注意:子状态机和外部状态的相互连接方式,连接外部的时候可以选择是通往默认动作还是指定的一个动作,同时,通往外部的线条以及条件直接在子状态机内设置,外部主动设置的线将会无效化。

第6节: 动画IK控制

动画IK控制

知识点一 什么是IK?

在骨骼动画中,构建骨骼的方法被称为正向动力学

它的表现形式是,子骨骼(关节)的位置根据父骨骼(关节)的旋转而改变

用我们人体举例子

当我们抬起手臂时,是肩部关节带动的整个手臂的运动,用父子骨骼理解的话就是父带动了子

而IK全称是Inverse Kinematics,翻译过来的意思就是反向动力学的意思

它和正向动力学恰恰相反

它的表现形式是,子骨骼(关节)末端的位置改变会带动自己以及自己的父骨骼(关节)旋转

用我们人体举例子

当我们拿起一个杯子的时候是用手掌去拿,以杯子为参照物,我们移动杯子的位置,手臂会随着杯子一起移动

用父子骨骼理解的话就是子带动了父

知识点二 如何进行IK控制

1.在状态机的层级设置中 开启 IK 通道

2.继承MonoBehavior的类中

Unity定义了一个IK回调函数:OnAnimatorIK

我们可以在该函数中调用Unity提供的IK相关API来控制IK

3.Animator中的IK相关API

SetLookAtWeight 设置头部IK权重

SetLookAtPosition 设置头部IK看向位置

SetIKPositionWeight 设置IK位置权重

SetIKRotationWeight 设置IK旋转权重

SetIKPosition 设置IK对应的位置

SetIKRotation 设置IK对应的角度

AvatarIKGoal枚举 四肢末端IK枚举

animator = this.GetComponent();

知识点三 IK反向动力学控制对于我们的意义

IK在游戏开发中的应用

1.拾取某一件物品

2.持枪或持弓箭瞄准某一个对象

等等

知识点四 关于OnAnimatorIK和OnAnimatorMove两个函数的理解

我们可以简单理解这两个函数是两个和动画相关的特殊生命周期函数

他们在Update之后LateUpdate之前调用

他们会在每帧的状态机和动画处理完后调用

OnAnimatorIK在OnAnimatorMove之前调用

OnAnimatorIK中主要处理 IK运动相关逻辑

OnAnimatorMove主要处理 动画移动以修改根运动的回调逻辑

他们存在的目的只是多了一个调用时机,当每帧的动画和状态机逻辑处理完后再调用

第7节: 动画目标匹配

动画目标匹配

知识点一 什么是动画目标匹配

动画目标匹配主要指的是

当游戏中角色要以某种动作移动,该动作播放完毕后,人物的手或者脚必须落在某一个地方

比如:角色需要跳过踏脚石或者跳跃并抓住房梁

那么这时我们就需要动作目标匹配来达到想要的效果

知识点二 如何实现动画目标匹配

Unity中的Animator提供了对应的函数来完成该功能

使用步骤是

1.找到动作关键点位置信息(比如起跳点,落地点,简单理解就是真正可能产生位移的动画表现部分)

2.将关键信息传入MatchTargetAPI中

animator = this.GetComponent();

知识点四 重要参数

private void MatchTarget()//此为动画过程中的事件
{
    //参数一:目标位置
    //参数二:目标角度
    //参数三:匹配的骨骼位置
    //参数四:位置角度权重
    //参数五:开始位移动作的百分比
    //参数六:结束位移动作的百分比
    animator.MatchTarget(targetPos.position, targetPos.rotation, AvatarTarget.RightFoot, new MatchTargetWeightMask(Vector3.one, 1), 0.4f, 0.64f);
}

知识点三 注意

调用匹配动画的时机有一些限制

1.必须保证动画已经切换到了目标动画上

2.必须保证调用时动画并不是处于过度阶段而真正在播放目标动画

如果发现匹配不正确,往往都是这两个原因造成的

说人话就是你使用该API的时候,你得保证正在进行你期望进行的动画

由于大部分动画都有过渡的原因,基本没办法直接在update里面做到

所以,我们通常是采用把MatchTargetAPI写到动画进行过程中的事件内

3.需要开启Apply Root Motion

第8节: 状态机行为脚本

状态机行为脚本

知识点一 状态机行为脚本是什么?

状态机行为脚本时一类特殊的脚本,继承指定的基类

它主要用于关联到状态机中的状态矩形上

我们可以按照一定规则编写脚本

当进入、退出、保持在某一个特定状态时我们可以进行一些逻辑处理

简单解释就是为Animator Controller状态机窗口中的某一个状态添加一个脚本

利用这个脚本我们可以做一些特殊功能

比如

1.进入或退出某一状态时播放声音

2.仅在某些状态下检测一些逻辑,比如是否接触地面等等

3.激活和控制某些状态相关的特效

知识点二 如何使用状态机脚本

1.新建一个脚本继承StateMachineBehaviour基类

2.实现其中的特定方法进行状态行为监听

OnStateEnter 进入状态时,第一个Update中调用

OnStateExit 退出状态时,最后一个Update中调用

OnStateIK OnAnimatorIK后调用

OnStateMove OnAnimatorMove后调用

OnStateUpdate 除第一帧和最后一帧,每个Update上调用

OnStateMachineEnter 子状态机进入时调用,第一个Update中调用

OnStateMachineExit 子状态机退出时调用,最后一个Update中调用

3.处理对应逻辑

知识点三 状态机行为脚本和动画事件如何选择

状态机行为脚本相对动画事件来说更准确(特别是在刚进入状态之类的时候,由于动画大部分有过渡,在过渡阶段使用事件可能会出现意想不到的问题,如MatchTargetAPI

但是使用起来稍微麻烦一些

根据实际需求选择使用

第9节: 状态机复用

状态机复用

知识点一 状态机复用是什么?

游戏开发时经常遇到这样的情况

有n个玩家和n个怪物,他们的动画状态机行为都是一致的,只是对应的动作不同而已

这时如果我们为他们每一个对象都创建一个状态机进行状态设置和过渡设置无疑是浪费时间的

所以状态机复用就是解决这一问题的方案

主要用于为不同对象使用共同的状态机行为

减少工作量 提升开发效率

知识点二 如何复用状态机

1.在Project窗口右键Create->Animator Override Controller

2.为Animator Override Controller文件在Inspector窗口关联基础的Animator Controller文件

3.关联需要的动画

博主注:复用状态机无法对animator页面进行修改,使用前得确保不再需要修改任何逻辑,而且基本上动画过渡条件代码也得复用过来。等于增加了方便性,放弃了灵活性。

第10节: 角色控制器

角色控制器

知识点一 角色控制器是什么?

角色控制器是让角色可以受制于碰撞,但是不会被刚体所牵制

如果我们对角色使用刚体判断碰撞,可能会出现一些奇怪的表现

比如:

1.在斜坡上往下滑动

2.不加约束的情况碰撞可能让自己被撞飞

等等

而角色控制器会让角色表现的更加稳定

Unity提供了角色控制器脚本专门用于控制角色

注意:

添加角色控制器后,不用再添加刚体

能检测碰撞函数

能检测触发器函数

能被射线检测

知识点二 角色控制器的使用

1.参数相关

2.代码相关

cc = this.GetComponent();

animator = this.GetComponent();

关键参数

是否接触了地面

if ( cc.isGrounded )

{

print(“接触地面了”);

}

关键方法

受重力作用的移动

cc.SimpleMove(Vector3.forward 10 Time.deltaTime);

不受重力作用的移动

cc.Move(Vector3.forward 10 Time.deltaTime);

update中使用SimpleMove就可以获得重力效果。

知识点三 角色控制中碰撞函数相关讲解

//当角色控制器想要判断和别的碰撞器产生碰撞时 使用该函数
private void OnControllerColliderHit(ControllerColliderHit hit)
{
    print(hit.collider.gameObject.name);
}

//对角色控制器没用 
//private void OnCollisionEnter(Collision collision)
//{
//    print("碰撞触发");
//}

//可以检测触发器
private void OnTriggerEnter(Collider other)
{
    print("触发器触发");
}

总结:触发器可以正常触发,碰撞器则需要用特殊api,原版的碰撞器api失效。

导航寻路系统

寻路导航系统概述

知识点一 什么是导航寻路系统

Unity中的导航寻路系统是能够让我们在游戏世界当中

让角色能够从一个起点准确的到达另一个终点

并且能够自动避开两个点之间的障碍物选择最近最合理的路径进行前往

Unity中的导航寻路系统的本质

就是在A星寻路算法的基础上进行了拓展和优化

知识点二 我们要学习那些内容

1.导航网格(NavMesh)的生成——要想角色能够在场景中自动寻路产生行进路径,那么必须得先有场景地形数据,导航网格生成就是生成用于寻路的地形数据

2.导航网格寻路组件(NavMesh Agent)——寻路组件就是帮助我们根据地形数据计算路径让角色动起来的关键

3.导航网格连接组件(Off-Mesh Link)——当地形中间有断层,想让角色能从一个平面跳向另一个平面,网格连接组件时关键

4.导航网格动态障碍物组件(NavMesh Obstacle)——地形中可能存在的可以移动或动态销毁的障碍物需要挂载的组件

注意:Unity2022以上的导航寻路系统

Unity2022及以上版本

将导航寻路系统从Unity中剥离,需要在Package Manager窗口中添加对应内容

切换页签

搜索AI相关

点击安装

安装成功后

Unity2022加入了一些新的规则和功能,为了方便我们的学习

我们还是使用老的一套方案

打开Navigation(Obsolete)窗口进行烘焙即可

新版本中,不能单独设置物体的寻路静态属性

只需要直接将参与烘焙的物体设置为静态对象即可

导航网格生成

知识点一 准备地形

在进行导航寻路网格生成时

第一步是需要有地形

地形需要我们主动来进行烘焙

知识点二 打开导航网络窗口

2022以上新版本可能需要前置包,具体可以看上文

Windows->AI->Navigation 打开Unity内置的导航网格生成窗口

知识点三 参数相关

Ojbect场景对象设置页签:

Bake导航数据烘焙页签:

Areas导航地区页签(配合Object页签使用):

Agents代理页签(用于配置寻路代理信息):

导航网格寻路组件

知识点一 导航网格寻路组件是用来干什么的?

通过上节课导航网格生成知识点的学习

我们已经准备好了地形相关的数据

知道地形上哪些地方可以到达,哪些不能

那么寻路组件的作用就是帮助我们让角色可以在地形上准确的移动起来

寻路组件的本质就是根据烘焙出的寻路网格信息

通过基于A星寻路的算法计算出行进路径让我们在该路径上移动起来

知识点二 寻路组件参数相关

导航网格寻路组件

Nav Mesh Agent(导航网格代理人)

知识点三 寻路组件代码相关

使用网格相关脚本需要引用命名空间

UnityEngine.AI

常用内容

自动寻路设置目标点

agent.SetDestination()

停止寻路

agent.isStopped = true;

不常用内容

变量

关键变量

1.面板参数相关 速度 加速度 旋转速度等等

print(agent.speed);

print(agent.acceleration);

print(agent.angularSpeed);

2.其它重要属性

2-1当前是否有路径

if( agent.hasPath )

{

}

2-2代理目标点 可以设置 也可以得到

print(agent.destination);

2-3是否停止 可以得到也可以设置

print(agent.isStopped);

2-4当前路径

print(agent.path);

2-5路径是否在计算中

if( agent.pathPending )

{

}

2-6路径状态

print(agent.pathStatus);

2-7是否更新位置

agent.updatePosition = true;

2-8是否更新角度

agent.updateRotation = true;

2-9代理速度

print(agent.velocity);

方法:

手动寻路

计算生成路径

NavMeshPath path = new NavMeshPath();

if( agent.CalculatePath(Vector3.zero, path) )

{

}

设置新路径

if(agent.SetPath(path))

{

}

清除路径

agent.ResetPath();

调整到指定点位置

agent.Warp(Vector3.zero);

实战:鼠标点击进行移动

void Update()
{
    if( Input.GetMouseButtonDown(0) )
    {
        RaycastHit hit;
        if( Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit ) )//hit是值类型,所以我们out获取更新内容
        {
            print(hit.collider.name);
            //取消停止移动
            agent.isStopped = false;
            //让对象朝目标点移动 先生成行进路径 然后再移动
            agent.SetDestination(hit.point);
        }
    }

//按空格可以停止移动
    if( Input.GetKeyDown(KeyCode.Space) )
    {
        agent.isStopped = true;
    }
}

导航网格外连接组件

知识点一 网格外连接组件是什么?

我们在烘焙地形数据的时候

可以生成网格外连接

但是它是满足条件的都会生成

而且是要在编辑模式下生成

如果我们只希望两个未连接的平面之间只有有限条连接路径可以跳跃过去

并且运行时可以动态添加

就可以使用网格外连接组件

达到“指哪打哪”的效果

知识点二 网格外连接组件的使用

1.使用两个对象作为两个平面之间的连接点(起点和终点)

2.添加Off Mesh Link脚本进行关联

3.设置参数

agent = this.GetComponent();

总结(博主)

比起烘焙的连接点,这种连接点数量可控,可以规定单向双向和开启与否,并且可以随时改变两个链接点的位置,更加的灵活好用。

导航网格动态障碍组件

知识点一 导航网格动态障碍组件用来干啥?

在游戏中常常会有这样的一个功能

场景中有一道门,如果这道门没有被破坏是不能自动导航到门后场景的

只有当这道门被破坏了,才可以通过此处前往下一场景

而类似这样的物体本身是不需要进行寻路的所以没有必要为它添加NavMeshAgent脚本

这时就会使用动态障碍组件实现该功能

知识点二 导航动态障碍物组件的使用

1.为需要进行动态阻挡的对象添加NavMeshObstacle组件

2.设置相关参数

3.代码逻辑控制其的移动或者显隐

知识点三 参数相关

基础知识点总结

总结(实战项目:丧尸围城)

项目介绍

此项目主要设计了一款可以通过炮塔和角色自己的攻击,来抵御僵尸入侵的3D游戏。

难点和经验总结

1.通过动画系统可以实现很多有趣的效果,如开头UI可以让相机旋转后再显示UI。

2.活用invoke延时函数,可以完成和事件强相关的功能,如本项目中的僵尸波数。

3.尽量不要写死代码,活用配表,制作可迭代可维护的游戏。

4.涉及到重复使用的全局使用的功能的时候,活用单例功能制作管理器,如UI管理器,关卡管理器,摄像机管理器等。

重点代码:

使用invoke实现的出怪点类:

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

public class MonsterPoint : MonoBehaviour
{
    //怪物有多少波
    public int maxWave;
    //每波怪物有多少只
    public int monsterNumOneWave;
    //用于记录 当前波的怪物还有多少只没有创建
    private int nowNum;

    //怪物ID 允许有多个 这样就可以随机创建不同的怪物 更具多样性
    public List<int> monsterIDs;
    //用于记录 当前波 要创建什么ID的怪物
    private int nowID;

    //单只怪物创建间隔时间
    public float createOffsetTime;

    //波与波之间的间隔时间
    public float delayTime;

    //第一波怪物创建的间隔时间
    public float firstDelayTime;

    // Start is called before the first frame update
    void Start()
    {
//开始游戏firstDelayTime秒后,进行第一波出怪
        Invoke("CreateWave", firstDelayTime);

        //记录出怪点
        GameLevelMgr.Instance.AddMonsterPoint(this);
        //更新最大波数
        GameLevelMgr.Instance.UpdatgeMaxNum(maxWave);
    }

    /// <summary>
    /// 开始创建一波的怪物
    /// </summary>
    private void CreateWave()
    {
        //得到当前波怪物的ID是什么
        nowID = monsterIDs[Random.Range(0, monsterIDs.Count)];
        //当前波怪物有多少只
        nowNum = monsterNumOneWave;
        //创建怪物
        CreateMonster();
        //减少波数
        --maxWave;
        //通知关卡管理器 出了一波怪
        GameLevelMgr.Instance.ChangeNowWaveNum(1);
    }

    /// <summary>
    /// 创建怪物
    /// </summary>
    private void CreateMonster()
    {
        //直接创建怪物
        //取出怪物数据
        MonsterInfo info = GameDataMgr.Instance.monsterInfoList[nowID - 1];

        //创建怪物预设体
        GameObject obj = Instantiate(Resources.Load<GameObject>(info.res), this.transform.position, Quaternion.identity);
        //为我们创建出的怪物预设体 添加怪物脚本 进行初始化
        MonsterObject monsterObj = obj.AddComponent<MonsterObject>();
        monsterObj.InitInfo(info);

        //告诉管理器 怪物数量加1
        //GameLevelMgr.Instance.ChangeMonsterNum(1);
        //记录怪物到列表中
        GameLevelMgr.Instance.AddMonster(monsterObj);

        //创建完一只怪物后 减去要创建的怪物数量1
        --nowNum;
        if( nowNum == 0 )
        {
            if (maxWave > 0)
                Invoke("CreateWave", delayTime);
        }
        else
        {
            Invoke("CreateMonster", createOffsetTime);
        }
    }

    /// <summary>
    /// 出怪点是否出怪结束
    /// </summary>
    /// <returns></returns>
    public bool CheckOver()
    {
        return nowNum == 0 && maxWave == 0;
    }
}