Unity游戏开发文档(3.1.1):弹窗效果
前言
该文档为《Unity游戏开发文档(3):Dancing Line》的附属文档,亦可看作是单独的技术总结文档。
目录
- 综述
- 对话框的非匀速滑动
- 对话框动画的异步运行
- 最终效果
- 参考资料
综述
无论是在游戏中还是在其他应用程序中,我们都经常使用到 “点击按钮 — 弹出对话框” 这一功能。这个功能最简单的形式就是点击某个按钮,然后对话框直接出现在用户的屏幕上,点击关闭按钮,对话框又直接从屏幕上消失。
在游戏中我们会希望往这一个交互动作中再加入一些特效,例如让对话框从屏幕的边缘滑动到指定的位置,同时辅佐以一些互动音效。此外还会在对话框的滑动上做一些手脚,例如让对话框做一个非匀速运动,刚出现时速度是比较快的,但随着对话框离指定位置越来越近,滑动的速度也随之降低。从而使这一互动显得更加生动有趣。
对话框的非匀速滑动
我们可以使用Untiy中的 动画曲线(Animation Curve) 组件,来实现上述的功能。
动画曲线是一条可由用户自由编辑形状的的曲线,动画曲线的定于域与值域均为 [0,1][0,1][0,1]。用户可以通过在曲线上右键 “add key” 来添加控制曲线形状的键值点。一般情况下,我们会把动画曲线当作是一个连续的 字典(Dictionary) 来使用(标准库提供的字典是离散的),即通过 XXX 值来获取我们所希望得到的 YYY 值。
那么我们如何使用动画曲线来为UI实现非匀速的滑动效果呢?在这里我们可以借助Unity 线性插值函数(Lerp Function) 的力量来实现这一个功能。线性插值函数的数学含义是通过用户提供的起始数值 aaa 和末端数值 bbb 以及插值范围 ttt,计算并返回一个大于 aaa 小于 bbb 且与 ttt 呈对应比例的数值,其数学表达式如下:
Lerp(a,b,t)=a+(b−a)∗tt∈[0,1]Lerp(a, b, t) = a + (b-a)*t \qquad t\in[0,1] Lerp(a,b,t)=a+(b−a)∗tt∈[0,1]
如果我们把UI的初始位置设为 aaa,UI的目标位置设为 bbb,那么通过令 ttt 从 000 递增至 111 便可实现UI从其初始位置滑动到某个特定位置的的效果。如果我们进一步调整 ttt 的递增速度,便可实现UI的非匀速滑动效果。例如令 ttt 以指数形式递增,UI便会以初始慢、结尾快的速度滑动;令 ttt 以对数形式递增,UI则会以初始快、结尾慢的速度滑动。再结合我们刚刚介绍过的动画曲线。如果我们令 ttt 值的变化,与动画曲线 YYY 值的变化一致,便可自由地调整UI滑动的速度了。
以下是具体的实现代码:
private float anime_time = 0.5f;
public AnimationCurve anime_curve;void PopOutAnime(GameObject panel) {float timer = 0.0f;Vector3 origin_pos = panel.transform.position;Vector3 target_pos = panel_pos - new Vector3(0.0f, panel.transform.position.y, 0.0f);while (timer < anime_time) {timer += Time.deltaTime;if (timer > anime_time)timer = anime_time;float lerp_ration = timer / anime_time;panel.transform.position = Vector3.Lerp(origin_pos, target_pos, anime_curve.Evaluate(lerp_ration));}
}
在上述代码中,我们手动设定了面板滑出动画的时间,然后令动画进行时间与动画曲线的 XXX 值呈映射关系,并获取曲线上相对应的 YYY 值来算出面板位置的插值,从而得到了非匀速的滑动效果。
面板消失的实现逻辑与面板弹出是一致的,相当于面板弹出的逆过程。
对话框动画的异步运行
接下来让我们理一理弹窗特效在游戏中的运行逻辑。一般来说我们希望呈现给用户的的效果是:
- 用户点击按钮或其他交互组件。
- 交互组件接收到交互指令,或是被交互指令触发。
- 交互组件唤醒弹窗,并命令弹窗播放特效。
- 用户看到弹窗出现。
顺着上述的思路,并代入到Unity的框架下构思代码实现逻辑,我们首先能想到的是玩家点击按钮后程序立即调用上文中的 PopOutAnime() 函数来播放弹窗特效。但这样存在一个问题是,PopOutAnime() 被调用后会在一帧内执行完毕。也就是说在玩家点击按钮后的下一帧里,对话框会在一帧的时间内走完整个滑动流程。玩家所能看到的是自己点击按钮后,对话框立马凭空出现在屏幕上。这明显是不对的。
我们希望的是玩家点击按钮后,PopOutAnime() 能够“缓慢地”执行,这样玩家才能完整地看到整个弹窗特效。在这种情况下,异步(Asynchronous) 运行的强大之处就得以体现了。 在Unity中,我们可以通过创建 协程(Coroutines) 来异步运行任务。
从定义上来讲,Unity的协程是一个能够暂停执行,在暂停结束后又能立即恢复执行的函数。当我们开启了一个协程后,主函数会开始执行协程中的内容,直到协程被暂停。协程被暂停后会立即返回到主函数,并继续执行主函数的剩余部分,直到暂停状态结束,协程恢复执行。通过协程的这种特性,我们便可以实现 PopOutAnime() 的“缓慢执行”。先上代码:
private float anime_time = 0.5f;
private Button help_button_;
private GameObject help_panel_;
public AnimationCurve anime_curve;void Start() {help_button_.onClick.AddListener(() => {StartCoroutine(PopOutAnime(help_panel_));});
}IEnumerator PopOutAnime(GameObject panel) {float timer = 0.0f;Vector3 panel_pos = panel.transform.position;Vector3 target_pos = panel_pos - new Vector3(0.0f, panel_distance_, 0.0f);while (timer < anime_time) {timer += Time.deltaTime;if (timer > anime_time)timer = anime_time;float lerp_ration = timer / anime_time;panel.transform.position = Vector3.Lerp(panel_pos, target_pos, anime_curve.Evaluate(lerp_ration));yield return null;}yield break;
}
在上述代码中,我们为按钮添加了监听器。当按钮监听到了玩家的点击事件,会就为 PopOutAnime() 开启一个协程。在协程内部,当 while() 循环每执行完一次,协程就会通过 yield return null 指令被暂停,直到当前帧结束,下一帧开始后,协程才会继续执行 while() 循环的剩余部分。当循环结束后,即对话框已经到达了指定位置,协程通过 yield break 结束掉自己,以释放系统资源。
通过这样 PopOutAnime() 函数在每一帧只会令对话框移动一小段距离。最终呈现在玩家面前的就是正常的滑出效果了。
最终效果
参考资料
Unity中协程(IEnumerator)的使用方法介绍: https://blog.csdn.net/beihuanlihe130/article/details/76098844?spm=1001.2014.3001.5502
Unity UGUI 按钮绑定事件的 4 种方式:https://www.cnblogs.com/isayes/p/6370168.html
关于unity中AddListener的传参问题的研究: https://blog.csdn.net/qq_42097011/article/details/103712333?spm=1001.2014.3001.5501
原创博客,不得转载、抄袭
Unity游戏开发文档(3.1.1):弹窗效果相关推荐
- Unity游戏开发文档(3.1.3):滚动式关卡选择菜单
前言 该文档为<Unity游戏开发文档(3):Dancing Line>的附属文档,亦可看作是单独的技术总结文档. 目录 综述 构建滚动菜单 读取关卡信息 填充菜单选项 选项自动 ...
- Unity游戏开发文档(3.1.2):下拉式音乐选择菜单
前言 该文档为<Unity游戏开发文档(3):Dancing Line>的附属文档,亦可看作是单独的技术总结文档. 目录 综述 构建下拉菜单 填充下拉菜单 切换背景音乐 最终效果 ...
- Unity游戏开发文档(1):飞行模拟
前言 本篇的代码是基于Unity3D 系列课程 "Create with Code" 第一章 "Player Control" 改进而来 目录 背景 设 ...
- python飞机大战概要设计_飞机大战游戏开发文档(Android版)
飞机大战游戏 开发文档 (Android版) 课程名称:飞机大战游戏 课程类型:Android游戏编程精彩内容,尽在百度攻略:https://gl.baidu.com 姓名:苏均灿 学号:131342 ...
- 微信小程序游戏开发文档以及开发工具地址
微信小程序开发交流qq群 581478349 承接微信小程序开发.扫码加微信. 正文: 微信官方于 2017 - 12 - 28 日 开发微信小程序 开发小游戏 , 微信小程序小游戏开发官方 ...
- java小组坦克大战游戏开发文档开发日志_java实现坦克大战游戏
本文实例为大家分享了java实现坦克大战游戏的具体代码,供大家参考,具体内容如下 一.实现的功能 1.游戏玩法介绍 2.自定义游戏(选择游戏难度.关卡等) 3.自定义玩家姓名 4.数据的动态显示 二. ...
- php赛车游戏开发文档,React 开发一款简单的赛车游戏
写在开始之前 最近研究egret引擎时,在论坛看到了用egret引擎写的一款赛车游戏 玩法很简单,左右控制赛车躲避来车,碰撞即游戏失败 下面将为大家一步步讲解,如何用React写出一款纯 javasc ...
- 微信小游戏开发文档(4)
微信小游戏系统API: wx.onTouchEnd wx.offTouchEnd wx.onTouchCancel wx.offTouchCancel Touch 触点 微信小游戏数据缓存接口: wx ...
- 火力篮球游戏源码完整版-带游戏开发文档
火力篮球,通过模拟现实中的投篮游戏机,而投篮游戏机又是源于街头篮球,街头篮球起源于美国,现在已经流行于世界的体育竞技项目,将投篮部分独立出来做成投篮游戏机.成为了专门的投篮类游戏设备.而本游戏就是将该 ...
最新文章
- Mysql分页order by数据错乱重复
- 每日命令:(13)more
- Oracle中默认创建的表
- Nginx核心要领五:worker_processes、worker_connections设置
- 视频直播点播nginx-rtmp开发手册中文版
- [html] 如何优化页面的渲染过程?
- mysql 1000万数据读取_插入1000万条数据到mysql数据库表
- Linux下vim常用操作
- Skywalking微服务监控分析
- Java编程基础 - 泛型
- C# WinFrom 对字符进行UTF-8编码
- 机器学习——seaborn可视化
- 1023. Have Fun with Numbers (20)
- fiddler 的AutoRespoder的使用(手动添加测试桩)
- 浅析Linux下的task_struct结构体
- 视频测试皮肤的软件,皮肤检测仪(LEIM魔镜仪)安装及操作视频
- Kaptcha 使用
- Map-Based Indoor Pedestrian Navigation Using an Auxiliary Particle Filter
- 新加坡国立大学计算机系访学,关于选拔本科生2019年春季学期赴新加坡国立大学访学的通知...
- 别让学历限制你,你可能是AI领域的下一个巨星
热门文章
- Linux运维学习历程-第十五天-磁盘管理(二)Raid与LVM逻辑卷
- 【mysql学习篇】为什么mysql用B+Tree?
- LightOJ 1340 Story of Tomisu Ghost
- esxi查看许可过期_解决Vsphere Client 60天过期问题
- 2764和6264地址范围
- 纵横网络靶场社区前四题wp
- android json html标签,Android: Parsing HTML tags in JSON
- Nagios Core/Icinga 基于栈的缓冲区溢出漏洞
- 深入分析Docker镜像原理 (转载)
- C++ 将二叉树叶子结点从左往右顺序串连