文章目录
-
-
-
- 13.1 皮皮猫打字机游戏
- 13.2 场景制作
-
- 13.2.1 入口场景
- 13.2.2 游戏场景
- 13.2.3 场景切换
- 13.3 游戏管理器
-
- 13.3.1 数据定义
- 13.3.2 生成字母盘
- 13.3.3 按键判断
- 13.3.4 连击定时器
- 13.4 动画控制器Animator
-
- 13.4.1 添加Animator
- 13.4.2 Animator状态机
-
- 13.4.2.1 Any State状态
- 13.4.2.2 Entry状态
- 13.4.2.3 Exit状态
- 13.4.3 动画状态的属性
- 13.4.4 状态间的过渡关系(Transitions)
- 13.4.5 添加状态控制参数
- 13.4.6 编辑切换状态的条件
- 13.5 猫娘动画状态机
-
- 13.5.1 模型资源下载
- 13.5.2 动画循环设置
- 13.5.3 状态过渡设置
- 13.6 角色动画控制器
-
- 13.6.1 数据定义
- 13.6.2 直接播放动画接口
- 13.6.3 设置变量值
- 13.6.4 根据状态队列设置状态
- 13.7 入口场景脚本
- 13.8 游戏场景脚本
- 13.9 文字特效动画
-
-
简介:我是一名
Unity
游戏开发工程师,皮皮是我养的猫,会讲人话,它接到了喵星的特殊任务:学习编程,学习Unity
游戏开发。于是,发生了一系列有趣的故事。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/d1b0927b1d874a20a499234b2b4c22c6.jpg)
文章图片
13.1 皮皮猫打字机游戏 皮皮:“铲屎官,你为什么打字速度这么快?”
我:“一个字,练。”
皮皮:“教教我,怎么连打字速度。”
我:“来,我给你做一个打字练习游戏吧。”
我:“当你可以一分钟连击180次的时候,你就可以出山了。”
皮皮:“作为猫族,不能被速度打败。”
游戏画面如下:
模块设计如下
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/ddf57bd352be46d187d007729fa5ac38.jpg)
文章图片
本工程使用的
Unity
版本为2020.1.14f1c1 (64-bit)
,工程已上传到GitHub
,感兴趣的同学可以下载下来学习。GitHub
地址:https://github.com/linxinfa/Unity-TypeWriting-Game![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/9f8be172f7494bceb741ea43af0e9eed.jpg)
文章图片
13.2 场景制作 13.2.1 入口场景
EntryScene.unity
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/f3371ad05529461fab2d90db9383a645.jpg)
文章图片
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/2316bd83799e4e7e8d1f294c1a357d69.jpg)
文章图片
一个标题文本(
Text
组件),一个开始按钮(Button
组件),一个难度选择勾选(ToggleGroup
和Toggle
组件)。背景图使用
SpriteRender
组件在3D
摄像机中渲染。难度等级的勾选使用了
ToggleGroup
组件,用来给Toggle
分组。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/6dcbbefa713345dd93d63ad46eb9fd4d.jpg)
文章图片
子节点中的
Toggle
需要指明相同的ToggleGroup
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/9eb5585c5ca74313a58a3edf25b2632e.jpg)
文章图片
实现单选的效果。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/ca95f83b8a764c7e9ffe95a8209209b4.gif)
文章图片
13.2.2 游戏场景
GameScene.unity
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/3b1d82cd47b1488fba1dee21b7430d95.jpg)
文章图片
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/b36c55dc965c43b1b9d73c231459cbbd.jpg)
文章图片
一个血条(
Slider
组件),一个得分(Text
组件),一个字母盘(GridLayoutGroup
、Text
组件)、一个连击(Text
组件),一个角色(SpriteRenderer
、Animator
组件)、一个背景图(SpriteRenderer
组件)。其中字母盘只做一个字母,游戏中进行动态克隆。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/b5d28b7bbece4e149dd17b5d7c47cc61.gif)
文章图片
再做游戏结束面板,提供一个返回和重来的按钮。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/d1ef2898ebda461cbcc995e78c8f3b08.jpg)
文章图片
13.2.3 场景切换 点击菜单
File - Build Settings...
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/82f06cbaeb224c59b5e0365a2a7b0a23.jpg)
文章图片
将场景添加到
Scenes In Build
中。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/ad836eed5e804a8495424567d847925b.jpg)
文章图片
代码中,通过
SceneManager.LoadScene
切换场景,如下// 进入GameScene场景
UnityEngine.SceneManagement.SceneManager.LoadScene(1);
13.3 游戏管理器 游戏管理器
GameMgr
,它需要包括数据和逻辑,如下。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/0a013d7182a846028c66ef62839181af.jpg)
文章图片
13.3.1 数据定义
///
/// 难度等级
///
public int hardLevel { get;
set;
}
///
/// 得分
///
public int score { get;
set;
}
///
/// 最大血量
///
private const int MAX_BLOOD = 1500;
///
/// 血量
///
public int blood
{
get { return m_blood;
}
set
{
m_blood = value;
if (m_blood <= 0)
{
gameOver = true;
// TODO 抛出事件
}
}
}
private int m_blood = 0;
///
/// 连击数量
///
public int comboCnt { get;
set;
}
///
/// 连击定时器
///
public float comboTimer { get;
set;
}
///
/// 游戏结束
///
public bool gameOver { get;
private set;
}
///
/// 按键列表
///
public List keyList { get { return m_keyList;
} }
private List m_keyList = new List();
13.3.2 生成字母盘 生成字母盘(16个字母),要求每个字母都不重复,生成的字母存到
m_keyList
中。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/a230ed21e34b456a89fe3fa14fae1dcd.jpg)
文章图片
///
/// 生成字母盘
///
private void GenKeys()
{
for (int i = 0;
i < 16;
++i)
{
m_keyList.Add(GenOneKey());
}
}///
/// 生成一个字母
///
///
private KeyCode GenOneKey()
{
var key = (KeyCode)UnityEngine.Random.Range((int)KeyCode.A, (int)KeyCode.Z);
for(int i=0,cnt=m_keyList.Count;
i
13.3.3 按键判断 我们需要先判断按键类型,封装一个接口
GetKeyDownCode
。///
/// 获取按键类型
///
///
public KeyCode GetKeyDownCode()
{
if (Input.anyKeyDown)
{
foreach (KeyCode keyCode in Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKeyDown(keyCode))
{
return keyCode;
}
}
}
return KeyCode.None;
}
然后判断按下的按键是否在字母盘中,返回对应的索引,如果不在字母盘中,则返回-1。
///
/// 判断按键是否在字母盘中
///
/// 按键
///
private int IsKeyBingo(KeyCode key)
{
for (int i = 0, cnt = m_keyList.Count;
i < cnt;
++i)
{
if (m_keyList[i] == key)
return i;
}
return -1;
}
按键正确的时候,执行连击计算,加血加分,生成新的字母,抛事件更新
ui
。///
/// 按键正确
///
private void OnKeyBingo(int bingoIndex)
{
// 加连击
++comboCnt;
if (comboCnt >= 3)
{
// 加血加分,连击加持
blood += 150;
if (blood > MAX_BLOOD)
blood = MAX_BLOOD;
score += 20;
}
else
{
// 加血加分
blood += 50;
score += 10;
}
// 生成新的字母
var oldKey = m_keyList[bingoIndex];
var newKey = GenOneKey();
m_keyList[bingoIndex] = newKey;
// TODO 抛事件,更新ui
}
按键错误的时候,连击中断,扣血,抛事件更新
ui
。///
/// 按键错误
///
private void OnKeyError()
{
// 连击中断
comboCnt = 0;
// 扣血
blood -= 30;
// TODO 抛事件,更新ui
}
13.3.4 连击定时器 如下,其中
Time.deltaTime
是一帧的间隔时间。每帧调用UpdateComboTimer
,对comboTimer
进行帧间隔时间递减,通过comboTimer
判断是否超过时间限制,超过则中断连击。///
/// 连击定时器
///
public void UpdateComboTimer()
{
if (comboTimer > 0)
{
comboTimer -= Time.deltaTime;
// 超过时间限制,连击断开
if (comboTimer <= 0)
{
comboCnt = 0;
// TODO 抛事件更新连击ui
}
}
}
13.4 动画控制器Animator
Unity
可以用两种方式控制动画1
Animation
,这种方式简单,直接 Play(“Idle”)
或者CorssFade(“Idle”)
就可以播放动画;
2
Animator
,Unity5.x
之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑。13.4.1 添加Animator 点击菜单
Window - Animation - Animation
,可以打开Animation
窗口,快捷键是Ctrl+6
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/7695e10e4b384d17a18efb987d13a9ca.jpg)
文章图片
选中某个物体后,可以为该物体添加或编辑动画,比如选中一个空物体,由于没有动画,会出现一个
Create
按钮。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/874a88c6d77a4850a3bca42a57f762de.jpg)
文章图片
点击
Create
按钮,会弹出窗口设置文件保存路劲。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/9eb32a2aa96f4c79aa865173848964c4.jpg)
文章图片
创建成功后,物体上会出现一个
Animator
组件。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/3ed094c0c80f4500a81d3ac32e6f8375.jpg)
文章图片
并且我们可以在目录中看到生成了两个文件。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/9ae6a9c5b7a44926a4adcb343558736b.png)
文章图片
.controller
文件是一个动画状态机,在Unity
中双击它会打开Animator
窗口,即可看到里面的内容,我们可以在这个窗口中组织各个动画文件。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/feaf2fac73d5476ca849ec884fb1b7ba.jpg)
文章图片
.anim
是动画文件,在Unity
中双击它会打开Animation
窗口,我们可以在这个窗口中制作动画。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/3e9c6fa9680e4210b5107ee1014cbbed.jpg)
文章图片
13.4.2 Animator状态机 每个
Animator Controller
都会自带三个状态:Any State
, Entry
和 Exit
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/5d9d1d0754c4498dbc15a4e540ffdc24.jpg)
文章图片
13.4.2.1 Any State状态 表示任意状态的特殊状态。例如我们如果希望角色在任何状态下都有可能切换到死亡状态,那么
Any State
就可以帮我们做到。当你发现某个状态可以从任何状态以相同的条件跳转到时,那么你就可以用Any State
来简化过渡关系。13.4.2.2 Entry状态 表示状态机的入口状态。当我们为某个
GameObject
添加上Animator
组件时,这个组件就会开始发挥它的作用。如果
Animator Controller
控制多个Animation
的播放,那么默认情况下Animator
组件会播放哪个动画呢? 由Entry
来决定的。但是
Entry
本身并不包含动画,而是指向某个带有动画的状态,并设置其为默认状态。被设置为默认状态的状态会显示为 橘黄色。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/a7c5e9c580b74487b92b8e5933f56256.jpg)
文章图片
当然,你可以随时在任意一个状态上通过
鼠标右键->Set as Layer Default State
更改默认状态。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/e5e769018c344ec0b080c44feb3b7cfc.jpg)
文章图片
记住,
Entry
在Animator
组件被激活后 无条件 跳转到默认状态,并且每个Layer
有且仅有一个默认状态。13.4.2.3 Exit状态 表示状态机的出口状态,以红色标识。如果你的动画控制器只有一层,那么这个状态可能并没有什么卵用。但是当你需要从子状态机中返回到上一层(
Layer
)时,把状态指向Exit
就可以了。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/e3e831beb92d4bd194d209bc0ae45bc5.jpg)
文章图片
13.4.3 动画状态的属性 我们可以选中某个自定义状态,并在
Inspector
窗口下观察它具有的属性![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/e0e832dec7224e6f9b62f79c6103d190.jpg)
文章图片
属性名 | 描述 |
---|---|
Motion | 状态对应的动画。每个状态的基本属性,直接选择已定义好的动画(Animation Clip)即可 |
Speed | 动画播放的速度。默认值为1,表示速度为原动画的1.0倍。 |
Mutiplier | 勾选右侧的Parameter后可用,即在计算Speed的时考虑 区域1 中定义的某个参数。若选择的参数为smooth, 则动画播放速度的计算公式为 smooth * speed * fps(animation clip中指定) |
Mirror | 仅适用于humanoid animation(人型机动画) |
Cycle Offset | 周期偏移,取值范围为0-1.0,用于控制动画起始的偏移量。把它和正弦函数的offset进行对比就能够理解了,只会影响起始动画的播放位置。 |
Foot IK | 仅适用于humanoid animation(人型机动画) |
Write Default | 最好保持默认,感兴趣可以参考官方手册 |
Transitions | 该状态向其他状态发起的过渡列表,包含了Solo和Mute两个参数,在预览状态机的效果时起作用 |
Add Behaviour | 用于向状态添加“行为 |
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/84751454f920421e9586bad3056754ce.jpg)
文章图片
要创建一个从
状态A
到状态B
的过渡,直接在状态A
上 鼠标右键 - Make Transition
并把出现的箭头拖拽到状态B
上点击鼠标左边即可。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/84b08b7c9a3749fb9d816cae3beb9fd5.gif)
文章图片
13.4.5 添加状态控制参数 参数有
Float
,Int
,Bool
,Trigger
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/b0e9af2b071048e8822c1f17f145b489.gif)
文章图片
Float
、Int
用来控制一个动画状态的参数,比如速度方向等可以用数值量化的东西,Bool
用来控制动画状态的转变,比如从走路转变到跑步,Trigger
本质上也是bool
类型,但它默认为false
,且当程序设置为true
后,它会自动变回false
。如下这里创建一个
Int
类型的参数AnimState
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/fd138dd6805d4bd18addac77a55d6794.jpg)
文章图片
13.4.6 编辑切换状态的条件 点击连线,在
Inspecter
窗口中可以进行设置,在Conditions
栏下可以添加条件,如下图表示当参数AnimState
为0
时会执行这个动画Any State
到New Animation2
的过渡必须在Parameters面板中添加了参数才可以在这里查看到,其次添加的条件为&& ”与” 关系,即必须同时满足。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/fb0616a4fd8b4610b841f719a867bbf9.jpg)
文章图片
13.5 猫娘动画状态机 13.5.1 模型资源下载 从
Assets Store
上下载猫娘模型,资源地址:https://assetstore.unity.com/packages/2d/characters/fancydoll-c000-little-cat-girl-112776![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/1cd0af358ef1472d8f8576f8351692cd.jpg)
文章图片
13.5.2 动画循环设置 模型自带了一些动画
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/8c5f745018784fdc83c193c21d9dfad7.jpg)
文章图片
idle
(站立)、walk
(走路)、run
(跑)需要循环播放,勾选Loop Time
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/bf18b9330a854e0fb60f8042ffee5959.jpg)
文章图片
get_hit
(受击)、die
(阵亡)不需要循环播放,不勾选Loop Time
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/d79be2daff5649be8b36ade8edb18118.jpg)
文章图片
13.5.3 状态过渡设置 【Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)】我们需要通过
Animator
将这些动画进行合理的组织,如下![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/229dfe88275a44aeb1747fadaf085be6.jpg)
文章图片
添加变量
Action
,过渡条件根据Action
的值进行判断。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/a79f7b6f5b834c5d8e249e6cf6f23d8c.jpg)
文章图片
过渡条件如下
状态1 | 状态2 | 条件 |
---|---|---|
Any State | idle | Action == 1 |
Any State | get_hit | Action == 4 |
get_hit | idle | 无 |
Any State | die | Action == 5 |
CharacterAniCtrler
,它需要包括数据和逻辑,如下。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/bf817e71276d494fa352cd076719af78.jpg)
文章图片
运行中的状态过渡
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/f5689272ecc0455eaeb022dc2a24bfc2.gif)
文章图片
13.6.1 数据定义
///
/// 状态定义,默认为Idle状态。
///
public enum CharacterAniId
{
Idle = 1,
Walk = 2,
Run = 3,
Hit = 4,
Death = 5,
}
///
/// 角色动画Animator组件
///
private Animator m_animator;
///
/// 动画队列
///
private Queue m_animQueue = new Queue();
13.6.2 直接播放动画接口
///
/// 立即播放某个动画
///
/// 动画名称
private void PlayAniImmediately(string name)
{
if (IsDeath) return;
m_animator.CrossFade(name, 0.1f, 0);
}
如立即播放走路动画
public void PlayWalk()
{
PlayAniImmediately("walk");
}
13.6.3 设置变量值
// 设置Action变量值为4
m_animator.SetInteger("Action", 4);
封装成接口
private const string STR_ACTION = "Action";
///
/// 播放不同动作ID
///
///
///
public void PlayAnimation(int actionID)
{
if (IsDeath) return;
if (m_animator == null)
return;
if (!m_animator.isInitialized || m_animator.IsInTransition(0))
{
// 如果正在过渡,则先塞到队列中
m_animQueue.Enqueue(actionID);
return;
}
m_animator.SetInteger(STR_ACTION, actionID);
}
13.6.4 根据状态队列设置状态 提供一个
LateUpdate
接口每帧调用,设置了Action
值需要在下一帧的时候重置为0,然后从队列中取下一个状态进行处理。///
/// 每帧调用
///
public void LateUpdate()
{
if (m_animator == null)
{
return;
}
if (!m_animator.isInitialized || m_animator.IsInTransition(0))
{
return;
}
if (null == mClips)
mClips = m_animator.GetCurrentAnimatorClipInfo(0);
if (null == mClips || mClips.Length == 0)
return;
int actionID = m_animator.GetInteger(STR_ACTION);
if (actionID > 0)
{
//将Action复位
m_animator.SetInteger(STR_ACTION, 0);
}//将剩余队列的动作重新拿出来播放
PlayRemainAction();
}///
/// 将剩余队列的动作重新拿出来播放
///
void PlayRemainAction()
{
if (m_animQueue.Count > 0)
{
PlayAnimation(m_animQueue.Dequeue());
}
}
13.7 入口场景脚本 入口场景脚本
EntryScene.cs
挂在Canvas
上,设置Start Game Btn
和Tgl Group
。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/9bd50d7c0197446fa9f93daec4c411c5.jpg)
文章图片
代码如下
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class EntryScene : MonoBehaviour
{
public Button startGameBtn;
public ToggleGroup tglGroup;
void Start()
{
startGameBtn.onClick.AddListener(() =>
{
// 根据勾选,缓存难度等级
foreach (var item in tglGroup.ActiveToggles())
{
GameMgr.Instance.hardLevel = int.Parse(item.name);
break;
}// 进入Game场景
SceneManager.LoadScene(1);
});
}
}
13.8 游戏场景脚本 游戏场景脚本
GameScene.cs
挂在Canvas
上,设置公开的成员对象。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/206b2f7005324a888804ab9160cfc880.jpg)
文章图片
主要根据各种事件更新
ui
。using System;
using UnityEngine;
using UnityEngine.UI;
public class GameScene : MonoBehaviour
{public Animator anitor;
public Text comboText;
public Text scoreText;
public Slider bloodSlider;
public Image bloodImage;
public GameOverDlg gameOverDlg;
public KeyGrid keyGrid;
private CharacterAniCtrler m_aniCtrler;
private void Awake()
{
// 注册事件
EventDispatcher.Instance.Regist(EventNameDef.EVENT_KEY_BINGO_INDEX, OnEventKeyBingoIndex);
EventDispatcher.Instance.Regist(EventNameDef.EVENT_COMBO, OnEventCombo);
EventDispatcher.Instance.Regist(EventNameDef.EVENT_PLAY_ANI, OnEventPlayAni);
EventDispatcher.Instance.Regist(EventNameDef.EVENT_UPDATE_SCORE, OnEventUpdateScore);
EventDispatcher.Instance.Regist(EventNameDef.EVENT_RESTART_GAME, OnEventRestartGame);
EventDispatcher.Instance.Regist(EventNameDef.EVENT_GAMEOVER, OnEventGameOver);
m_aniCtrler = new CharacterAniCtrler();
m_aniCtrler.Init(anitor);
// 开始游戏
StartGame();
}private void OnDestroy()
{
// 注销事件
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_KEY_BINGO_INDEX, OnEventKeyBingoIndex);
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_COMBO, OnEventCombo);
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_PLAY_ANI, OnEventPlayAni);
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_UPDATE_SCORE, OnEventUpdateScore);
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_RESTART_GAME, OnEventRestartGame);
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_GAMEOVER, OnEventGameOver);
}///
/// 开始游戏
///
private void StartGame()
{
GameMgr.Instance.Init();
TextEffect.Init();
// 初始化血量
bloodSlider.maxValue = https://www.it610.com/article/GameMgr.Instance.blood;
bloodSlider.value = GameMgr.Instance.blood;
bloodImage.enabled = true;
// 生成字母盘
keyGrid.CreateKeyList(GameMgr.Instance.keyList);
comboText.gameObject.SetActive(false);
scoreText.text ="0";
gameOverDlg.Hide();
}void Update()
{
if (GameMgr.Instance.gameOver) return;
// 更新连击定时器
GameMgr.Instance.UpdateComboTimer();
// 更新血量ui
bloodSlider.value = https://www.it610.com/article/GameMgr.Instance.blood;
GameMgr.Instance.blood -= GameMgr.Instance.hardLevel;
// 按键判断
var keyCode = GameMgr.Instance.GetKeyDownCode();
if (KeyCode.None == keyCode) return;
GameMgr.Instance.OnKey(keyCode);
}private void LateUpdate()
{
// 更新动画控制器
m_aniCtrler.LateUpdate();
}///
/// 按键正确事件
///
///
private void OnEventKeyBingoIndex(params object[] args)
{
int index = (int)args[0];
KeyCode oldKey = (KeyCode)args[1];
KeyCode newKey = (KeyCode)args[2];
keyGrid.UpdateKeyByIndex(index, oldKey, newKey);
}///
/// 连击事件
///
///
private void OnEventCombo(params object[] args)
{
var combo = (int)args[0];
comboText.text = "连击" + combo;
comboText.gameObject.SetActive(combo >= 3);
}///
/// 播放动画事件
///
///
private void OnEventPlayAni(params object[] args)
{
var ani = (string)args[0];
switch (ani)
{
case "idle": m_aniCtrler.PlayAnimation((int)CharacterAniId.Idle);
break;
case "walk": GameMgr.Instance.comboTimer = 0.5f;
m_aniCtrler.PlayWalk();
break;
case "run": GameMgr.Instance.comboTimer = 0.5f;
m_aniCtrler.PlayRun();
break;
case "hit": m_aniCtrler.PlayAnimation((int)CharacterAniId.Hit);
break;
case "die": m_aniCtrler.PlayDieImmediately();
break;
}
}///
/// 更新得分事件
///
///
private void OnEventUpdateScore(params object[] args)
{
var score = (int)args[0];
scoreText.text = score.ToString();
}///
/// 游戏结束事件
///
///
private void OnEventGameOver(params object[] args)
{
bloodImage.enabled = false;
gameOverDlg.Show(GameMgr.Instance.score);
}///
/// 重新开始游戏事件
///
///
private void OnEventRestartGame(params object[] args)
{
m_aniCtrler.PlayReviveImmediately();
StartGame();
}
}
其中事件定义如下
///
/// 事件定义
///
public class EventNameDef
{
///
/// 按键正确事件
///
public const string EVENT_KEY_BINGO_INDEX = "EVENT_KEY_BINGO_INDEX";
///
/// 连击事件
///
public const string EVENT_COMBO = "EVENT_COMBO";
///
/// 播放动画事件
///
public const string EVENT_PLAY_ANI = "EVENT_PLAY_ANI";
///
/// 游戏结束事件
///
public const string EVENT_GAMEOVER = "EVENT_GAMEOVER";
///
/// 更新得分事件
///
public const string EVENT_UPDATE_SCORE = "EVENT_UPDATE_SCORE";
///
/// 重新开始游戏事件
///
public const string EVENT_RESTART_GAME = "EVENT_RESTART_GAME";
}
13.9 文字特效动画
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/5efce191736241c599a46e8e7e10b5b9.gif)
文章图片
制作一个
TextEffect.prefab
预设,添加动画如下。![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/151ac5e31a6d4afd9e2a1d2d5134014a.gif)
文章图片
由于游戏中需要重复显示这个特效,所以采用对象池方式。
特效动画结束时回收到对象池中,这样可以反复利用。为了监听动画结束,在动画的最后一帧添加帧事件。
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/2f34564d78664fb4b07f88e1e0cbe70c.jpg)
文章图片
创建一个
TextEffect.cs
脚本,挂到预设上,提供一个OnAnimationEnd
共有方法public void OnAnimationEnd()
这样就可以设置帧事件的响应函数了
![Unity3D|《学Unity的猫》——第十三章(Unity使用Animator控制动画播放,皮皮猫打字机游戏)](https://img.it610.com/image/info8/1b19151f25934e2da31ccccb95054a35.jpg)
文章图片
TextEffect.cs
脚本如下using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
///
/// 文本特效
///
public class TextEffect : MonoBehaviour
{///
/// 初始化
///
public static void Init()
{
if(null != s_root)
{
Destroy(s_root.gameObject);
s_root = null;
}s_objPool.Clear();
var canvas = GameObject.Find("Canvas");
if (null != canvas)
{
var rootObj = new GameObject("EffectRoot");
s_root = rootObj.transform;
s_root.SetParent(canvas.transform, false);
}
}///
/// 显示特效
///
///
///
public static void Show(string text, Vector3 pos)
{
if (null == s_prefab)
{
s_prefab = Resources.Load("TextEffect");
}TextEffect bhv = null;
if (s_objPool.Count > 0)
{
// 从对象池中取对象,
bhv = s_objPool.Dequeue();
}
else
{
var obj = Instantiate(s_prefab);
obj.transform.SetParent(s_root, false);
bhv = obj.GetComponent();
}
bhv.gameObject.SetActive(true);
bhv.transform.position = pos;
bhv.keyText.text = text;
}///
/// 动画结束事件的响应函数
///
public void OnAnimationEnd()
{
gameObject.SetActive(false);
// 对象回收
s_objPool.Enqueue(this);
}private static GameObject s_prefab;
///
/// 对象池
///
private static Queue s_objPool = new Queue();
///
/// 根节点
///
private static Transform s_root;
///
/// 文字组件
///
public Text keyText;
}
完成。
如果有什么疑问,欢迎留言或私信。
《学Unity的猫》——第十四章:Unity实现文件上传下载,支持续传,猫后爪的秘密
推荐阅读
- Unity3D|【游戏开发高阶】从零到一教你Unity使用ToLua实现热更新(含Demo工程 | LuaFramework | 增量 | HotUpdate)
- Unity3D|《学Unity的猫》——第十六集(Unity动画使用混合树BlendTree实现动画过渡控制)
- Unity3D|【游戏开发实战】Unity UGUI实现循环复用列表,显示巨量列表信息,含Demo工程源码
- Unity3D|(完结)Unity游戏开发——新发教你做游戏(七)(Animator控制角色动画播放)
- CSS|CSS实现水滴动效
- Unity常见的优化性能设置
- 游戏|元宇宙密室逃脱游戏攻略来啦!
- 每天记录学习的新知识 : ObjectAnimator 基础和用法
- Unity3d|Unity中的层级以及渲染顺序