2D Roguelike最终效果
前言
本节我们主要完成以下内容:
您将在本节中学到什么? 1.添加界面UI
2D Roguelike 的 UI 层非常简单。 它由两部分组成:通关时的界面和食物值显示。
1.1 添加通关界面和结束UI
当你第一次进入游戏并移动到EXIT进入下一关时,会出现通关界面。 这些元素是黑色背景图像和显示比赛日期的标题文本。
通过级别界面
这个界面实际上是在游戏结束时使用的,只是文字内容发生了变化。
1.1.1 添加黑色背景LevelImage
打开 Unity 编辑器并添加 Canvas。
添加画布
Canvas画布是承载所有UI元素的区域,所有UI元素都必须是Canvas的子对象。 Canvas 可以被认为是 UI 层的相机。
可以看到,Hierarchy窗口下出现了Canvas和EventSystem(EventSystem主要负责处理和处理事件,本项目中没有使用)。
我们先添加一张黑色背景图片,在Hierarchy窗口下空白处右键-UI-Image,可以看到Image自动成为Canvas的子节点。
添加图片成功
切换到场景窗口,使用鼠标滚轮缩小到适合我们观看的级别(鼠标右键可以移动)。 新添加的Image默认放置在Canvas的中间,颜色为白色。 我们需要将其填充到画布的大小并将其设为黑色。
在Hierarchy窗口中选择Image,点击右侧Inspector的锚点设置(矩形变换),按住Alt键(如果是Mac电脑则为option键)选择右下角进行填充。
选择对齐方式
关于锚点设置的相关知识,可以阅读这篇文章Unity进阶技巧——RectTransform详解
选择黑色作为颜色。
更改背景颜色
效果可以在场景和游戏窗口中看到。 选择“图像”并单击鼠标左键,将其命名为“LevelImage”。
1.1.2 添加关卡文本
LevelText的作用是显示当天和游戏结束信息。 添加文本的方法与添加图像的方法相同。 右键单击 Hierarchy 窗口 - UI - Text 下的空白区域,并将其命名为 LevelText。
LevelText需要以背景板为中心,可以进行文字颜色、大小、字体、文字对齐方式、默认文字内容等设置。
选择LevelText,点击右侧Inspector的锚点设置,按住Alt键(如果是Mac电脑则为option键)选择中间居中对齐。
中心对齐
然后我们将默认的文字内容改为“Day 1”,Font选择PressStart2P-Regular(比较适合这个游戏的字体),将Font Size设置为32,将文字居中对齐,将Color字体颜色改为白色。
但是当我们回到场景时,我们发现文本框已经消失了!
隐形文字
这是因为文本字体超出了文本框的大小。 由于文本长度是不确定的,我们无法通过拉伸文本框来解决这个问题。 选择文本框以允许水平和垂直方向溢出。
选择溢出
在控制LevelImage的显示或隐藏时,我们期望LevelText也会发生相应的变化,所以我们需要将LevelText变成LevelImage的子对象。 将 LevelText 拖至 LevelImage 并释放。
1.1.3 脚本控制LevelImage和LevelText
添加UI元素后,我们需要在脚本中添加代码来控制这些控件。 打开 GameController 脚本并向其中添加以下代码:
代码简读:
Invoke()可以根据时间调用指定的方法,并延迟加载界面,使视觉过渡更加平滑,不那么突兀。
保存代码,返回Unity编辑器,然后尝试运行游戏。
通过这次测试可以发现两个bug:
第一天是第 4 天,正确来说应该是第 1 天。 当移动到退出网格并进入下一个级别时,仍然显示“Day 1”(LevelText 的默认文本),并且不会一路向上添加。 1.1.4 处理“下一个级别”
第一个问题是,当在GameController脚本中声明关卡时,为了方便测试,它被赋值为4。 现在可以改为1。
等级
第二个问题是,进入下一关卡后,程序需要实现两个函数:level+1,以及调用initGame()渲染生成新的关卡。 众所周知,重新加载场景时(单例模式)GameController并不会被销毁,因此不会再次调用Awake(),因此也不会再次调用InitGame()来生成新的关卡图。 那么,我们就需要寻找其他方式来实现新关卡的渲染。
原始教程视频中的 OnLevelWasLoaded() 方法已被放弃。 当前版本提供了SceneManager.sceneLoaded委托函数,调用更加灵活。
我们在GameController中添加以下代码:
SceneManager.sceneLoaded
委托方法需要遵循一定的格式。 例如,对于sceneLoaded,两个参数类型必须是Scene和LoadSceneMode; 但是,方法名称可以自定义。
添加上述代码后,显示游戏角色进入下一关的天数,关卡渲染正常。
1.1.5 增加游戏结束提示
当游戏角色死亡时,需要弹出相应的提醒。 我们将以下代码添加到处理游戏结束的 GameOver 方法中:
游戏结束
将文案更改为“N 天后,你饿死了”。 我以前写“死”,后来发现这家伙是饿死的。
然后激活黑色背景图像进行显示。
个人记录
1.2 增加食物值显示并更改UI
游戏过程中,玩家需要实时看到当前食物的价值,并获得食物价值变化的反馈,以便采取适当的策略来过关。
食物数量显示
如上图所示,我们只需要在界面底部添加一个文本控件,用文本来显示食物的数量和变化。
1.2.1 添加食物文本
返回编辑器,在Hierarchy窗口下的空白处右键-UI-Text,命名为FoodText。
食品文本
FoodText需要底部居中对齐,文本颜色、大小、字体、文本对齐方式、默认文本内容等都要像之前的LevelText一样设置。
选择FoodText,点击右侧Inspector的锚点设置,按住Alt键(如果是Mac电脑则为option键)选择底部中心交点,对齐底部中心。
然后我们将默认文本内容改为“Food:100”,Font选择PressStart2P-Regular,Font Size字体大小为243D道具,Alignment文本对齐居中,Color字体颜色改为白色,文本框允许水平和垂直溢出。
为了让它更漂亮,我们将FoodText向上移动一点,这样它就不会粘在底部边缘。 为了实现这个效果,我们首先看一下锚点当前的位置。
锚(我的名字)
可以看到锚点的位置在底边的中间,文本框FoodText的中心点到锚点的垂直距离为15,水平距离0表示X坐标两点是相同的。
将 Anchors 的 Min 和 Max 的 Y 坐标更改为 0.05(相对于 Canvas 高度的比率)。
可以看到,变化后,散射菊花形锚点向上移动,FoodText中心点与其之间的垂直距离从15变为-13。 将-13改为0,FoodText就会向上移动。
另外,需要注意的是,在显示天数或游戏结束页面时,我们不希望玩家仍然看到Food的数量,这意味着FoodText的级别低于LevelImage及其子节点LevelText ,这样就可以覆盖它了。
只需拖动鼠标并将 FoodText 移动到 LevelImage 即可。
向上移动 FoodText
UI元素的绘制顺序与Hierarchy(层次视图)中的顺序一致,后面的元素会绘制在前面的元素之上。
1.2.2 脚本控制FoodText内容
打开 GameController 脚本并向其中添加以下代码:
然后我们添加相应的代码来更改食物值变化时的文本显示。 一共三个地方,不要错过。
尝试移动()
OnTriggerEnter2D()
失去食物()
保存代码,切换到Unity编辑器,将FoodText拖入Player Script的FoodText选项框中。
开始测试!
UI部分完成
完美~可惜字体不适应屏幕,但这不是本项目教程的重点。
游戏中的音乐一般有两种类型:持续时间较长的循环播放的背景音乐,以及短暂的各种音效(战斗、移动、拾音等)。
2.1 实现背景音乐添加及设置 2.1.1 添加背景音乐
首先,您需要创建一个游戏对象来管理所有音频资源。 在Hierarchy窗口下的空白处右键->Create Empty,创建一个空白的游戏对象,命名为SoundManager,并在其中添加一个Audio Source组件来控制背景音乐的播放。
添加音频源组件
Audio Source是控制指定音乐播放的组件。 您可以通过属性设置来控制音乐的某些效果。
在组件中的AudioClip中选择scavengers_music(背景音乐),勾选Play On Awake和Loop。
设置音频源属性
物业描述:
也就是说,我们选择了背景音乐,并让它在加载场景后自动播放并不断循环。 看起来没有问题,我们来运行游戏测试一下。
(gif无法播放音乐,假装你已经测试过)
这款游戏的背景音乐非常精彩,但是在切换关卡的时候我们会发现一个非常尴尬的事情:音乐从头开始播放。 这是因为切换场景时SoundManager会自动销毁并重新生成,音乐会关闭并重新播放。 和GameController一样,只需要一个SoundManager就可以同时控制所有音乐的播放(如果多个的话就会混乱),所以也必须设置为单例模式。
2.1.2 SoundManager实现单例模式
我们已经在第2章生成关卡时提到了实现单例模式的方法。 在Scripts文件夹中创建一个C# Script脚本文件,命名为SoundManager,并在其中输入以下代码。
声音管理器脚本
切换到Unity编辑器,将SoundManager脚本挂载到SoundManager游戏对象上,然后再次运行游戏测试。
(gif无法播放音乐,假装你已经测试过了)
您可以听到音乐正常循环播放,并且切换级别时不会中断。 接下来我们继续给游戏添加音效吧!
2.2 添加音效
2D Roguelike游戏中的音效有几种类型:角色移动、角色吃食、角色死亡、游戏结束、怪物攻击、角色砸墙等。长期单调重复的音效会让人感到疲倦和无聊,所以你可以对音效的数量和音调进行一些随机化和变化,给人以新鲜感。
2.2.1 添加运动、吃饭、喝水、死亡音效
首先,我们在SoundManager游戏对象中添加一个Audio Source组件来控制各种音效的播放。 请记住取消选中“唤醒时播放”和“循环播放”。 音效不需要自动播放或循环播放。
第二音频源
打开 SoundManager 脚本并添加以下代码。
代码简读:
该方法使用 params 关键字来指定可变数量的参数。 调用时传入指定类型的以逗号分隔的参数数组。
现在我们有了这些方法,那么我们应该在什么情况下使用它们以及在哪里调用它们呢?
打开Player脚本,新增7个AudioClip类型的成员变量,分别代表移动、吃饭、喝水、游戏结束的音效片段。 游戏结束的音效只播放一次,所以不需要创建两个来减少单调。
然后在不同的事件中调用SoundManager方法来播放音效。
【角色移动】:在AttempMove()中,当角色移动时,使用if语句判断Move()是否返回true,即可以移动。 然后调用SoundManager的RandomizeSfx()来选择两种移动音效之一。 玩。
角色动作音效播放
【角色吃喝】:在OnTriggerEnter2D()中,当角色碰撞到Food或Soda时,调用SoundManager的RandomizeSfx()选择对应的两种音效之一进行播放。
播放人物吃饭喝水的音效
【Game Over】:在CheckIfGameOver()中,当food小于等于0时,表示角色已经饿死,游戏即将结束,调用SoundManager的PlaySingle()播放gameOverSound。
游戏结束音效响起
保存代码,返回Unity编辑器,选择SoundManager游戏对象游戏策划,将控制音效的Audio Source拖入Sound Manager组件的Efx Source选项中。
选择Player游戏对象,点击Player脚本组件中7个新项目最右边的点,选择对应的音效片段。
运行游戏测试。
(gif无法播放音乐,假装你测试过)
我们会发现一个问题。 当游戏角色饿死时,会弹出结束面板并播放相应的音效,但游戏背景音乐并没有关闭! 这会给玩家一种很奇怪的感觉,赶紧修复吧!
打开SoundManager脚本,添加AudioSource类型的成员变量musicSource,它代表控制背景音乐播放的Audio Source。
添加了音乐源
打开Player脚本,在检测游戏结束的方法CheckIfGameOver()中调用SoundManager的musicSource,并执行其Stop方法关闭音乐播放。
关闭播放
保存代码,返回Unity编辑器,选择SoundManager游戏对象,将控制背景音乐的Audio Source拖入Sound Manager组件的Music Source选项中。
运行游戏,现在就可以运行了! 接下来别忘了添加角色被怪物攻击的尖叫音效和角色撞墙的音效!
2.2.2 增加角色被攻击、墙裂音效
打开Enemy脚本,添加AudioClip类型的成员变量attackSound1和attackSound2来表示音效。 然后,OnCantMove()触发攻击特效后,调用SoundManager的RandomizeSfx()选择attackSound1和attackSound2之一进行播放。
打开Wall脚本,添加AudioClip类型的成员变量chopSound1和chopSound2来表示劈墙音效。 然后,DamageWall()扣除墙壁的生命后,调用SoundManager的RandomizeSfx()从chopSound1和chopSound2中选择一个进行播放。
保存代码,返回Unity编辑器unity按钮点击音效,打开Prefabs文件夹,同时选择Enemy1和Enemy2预制件,在右侧Enemy脚本组件中的Attack Sound中选择对应的音效。
同时选中Wall1-8预制件,在右侧Wall脚本组件中的Chop Sound中选择对应的音效。
运行游戏测试~
你完成了!
3.本地发布游戏
游戏制作完成后,您可以在本地发布游戏。 保存场景并通过菜单栏File-->Build Settings打开发布页面。
4. 文章完成
细心的朋友还会发现,还有一些内容没有提到:手机或平板触摸控制。 主要有以下几个原因:
[结束语]
本次教程转从第一篇文章到最后一篇文章unity按钮点击音效,一共花了1年3个月零11天。 等待的时间越长,开始就越困难。 抱歉看到一半还让大家久等的孩子们~
在写文章的过程中,因为需要输出知识,所以我要反复研究原视频和游戏本身。 因此,我收获了很多,很多以前只懂了一半的内容都变得更加清晰了。 因此,如果你有空闲时间,建议你将学习Unity过程中掌握的知识整理出来,输出成文章,让自己和他人受益。
学习之路还很漫长。