安卓 Unity 游戏开发学习手册(一)

原文:Learn Unity for Android Game Development

协议:CC BY-NC-SA 4.0

一、为什么这是一个为 Android 开发游戏的激动人心的时刻

这是独立游戏开发商的黄金时代。

以前也有过这样的时候。那是在家用电脑的早期——ZX 频谱和 Amstrad 的时代。由于技术的限制,那时的游戏非常简单。不管你的开发团队或预算有多大,你用那个硬件能做的也就那么多了!这使得每个人都处于一个公平的竞争环境中,这意味着一个敏锐的程序员可以在他们的地下室舒适地获得像 Arkanoid 这样的名副其实的成功(见图 1-1 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1。

Arkanoid, from a time when all games were indie

然后技术在发展,游戏产业在成长,我们看到了 AAA 级游戏的出现。游戏成了比好莱坞电影更大的赚钱机器,硬件也突飞猛进。一个开发者不可能与光环或侠盗猎车手这样的公司竞争。不仅像这样的游戏中的每个模型都需要从头开始设计,每一行对话都需要记录,而且简单地编写决定事物爆炸方式的物理量对于一个单独的开发者来说是不可能完成的任务。

然后命运介入了。iOS 和 Android 等移动设备和操作系统的增长引入了新的“低规格”设备。与此同时,更好的分销渠道,如谷歌 Play 商店、iTunes 应用商店,甚至 Steam,都帮助小开发者发现了他们的创作。

慢慢地,越来越多的独立开发者开始发布游戏并获得好评,随着时间的推移,这最终转化为商业上的成功。像《洞穴探险》这样的早期作品!显示了伟大的游戏性和创造性的想法可以胜过 AAA 级的生产价值。后来,像 Limbo 或 Fotonica 这样的艺术尝试表明,风格化的视觉效果可以像超真实的图形一样引人注目。很快,像《超级肉仔》和《愤怒的小鸟》这样的游戏开始在销量上与顶级工作室竞争。事实上,《我的世界》,一个世界著名的独立游戏和家喻户晓的名字,现在实际上是有史以来第二畅销的游戏(仅次于俄罗斯方块)。《无人天空》是 Steam 上有史以来最畅销的游戏之一——它也来自一家独立工作室。

这一运动近年来势头越来越大。随着许多游戏玩家逐渐对过度刺激的《使命召唤》(Call of Duty)等普通的大预算续作变得漠不关心,独立游戏为自己打造了一个利基市场,并因能够提供更具创意和大胆的体验而赢得了声誉。有时候,这些经历甚至挑战了传统的游戏“游戏”的概念著名的例子是最近越来越受欢迎的“行走的模拟人生”。

输入 Unity

虽然许多因素促成了独立游戏的快速增长,但 Unity(图 1-2 )等工具也对这一运动做出了巨大贡献。Unity 是一个游戏引擎,它让开发变得特别容易,让初学者可以开始创建自己的程序。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2。

The Unity logo

游戏引擎是软件的主干,它提供了游戏运行所需的许多基本元素。这些元素包括显示(渲染)3D 和 2D 图形的能力,处理基本物理(称为物理引擎),检测游戏对象之间的“碰撞”(碰撞引擎),甚至提供基本的人工智能脚本或其他现成的素材。

像 Unity 这样的工具允许一个开发团队专注于使他们的游戏独特的元素,然后简单地将它们插入到工作环境中,而不是从头开始创建游戏。Unity 将这一点与便捷的界面和跨平台功能相结合,从而节省了数以千计的时间,否则从零开始构建一个完全实现的游戏并将其移植到 Android、iOS 和 Windows 是必要的(图 1-3 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3。

Unity saves developers a huge amount of time

在这一点上,你可能想知道使用像 Unity 这样的工具在某种程度上是否是“欺骗”。如果 Unity 为你的物理学提供了底层代码,那么你真的“制作”了这个游戏吗?如果它提供了一个用户友好的图形界面来拖放预先制作的游戏资源,它与“游戏制作者”有什么不同呢?和《超级马里奥制造》差那么远吗?

毫无疑问:Unity 是一个全面的工具,被成千上万大大小小的开发者所使用。许多你在 Android(和其他地方)上最喜欢的游戏很可能是用 Unity 开发的,包括:

  • 神庙逃亡
  • 坏猪
  • Lara Croft:走吧
  • 双人舞:秋天
  • 逃跑计划
  • 银河战士系列在线版
  • 超级英雄
  • 幸运的故事
  • 纪念碑谷
  • 库法达
  • 奥里和盲林
  • 布洛费
  • 倾斜画笔

简而言之,Unity 是一款专业级软件,已经被用于创建一些最大的独立游戏,甚至一些最大的 3a 游戏。使用现成的素材远不是不专业的标志;事实上,它是编码中最重要和最受鼓励的策略之一。任何优秀的程序员都遵循的一个关键原则是:不要重新发明轮子。换句话说,不要花大量的时间在物理引擎、人工智能甚至 3D 模型上,因为这些工作已经存在并可供使用。简单地这样做不是对时间的好利用,随着游戏变得越来越复杂和雄心勃勃,共享资源和代码不仅是明智的,而且是必要的。专业的开发者知道这一点,业余的也应该效仿。

当 Unity 是一个被证实的量时——当你知道它能够产生大量的热门歌曲时——你为什么要忽视它而使自己的生活更加困难呢?

共享素材

分享的风气是现代发展的重要组成部分,只需要快速的谷歌搜索就能意识到这一点。Unity 消除了许多复杂编码的需要,否则你必须自己处理,如果你想做一个非常基本的 2D 平台,那么你几乎不用写任何代码。当你不得不写代码时,如果你在论坛或其他地方提出这个问题,你通常会找到愿意帮助你的人。当然,这本书应该为你提供你需要的所有基本代码,以及理解如何创建更多的代码。

有时,您会需要 Unity 本身没有的代码,并且您不想从头开始创建这些代码——例如,特定的视觉效果或高级控制方案。幸运的是,这就是共享再次派上用场的地方。Unity 实际上在软件本身中构建了一个解决方案——不需要搜索网页或下载文件并将其导入到您的项目中。Unity 素材商店(图 1-4 )是一个资源,你可以在这里下载脚本、模型、精灵、纹理、特效等等,所有这些都是由社区或 Unity Technologies 本身提供的。下载这些组件会自动将其集成到您的项目中。更好的是,许多素材是免费的;其他的花费相对较少。通过充分利用这一特性,您几乎只需编写一行代码就可以创建任何您能想到的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4。

The Unity Assets Store, where you can find all the scripts, sprites, effects, and more

这种开源的分享精神是最近帮助独立开发如此大规模起飞的另一件事。通过众包和借用游戏元素,开发者可以在原本需要的很短时间内构建出具有专业水准的巨大世界。

最好的部分?Unity 本身对业余爱好者和小型独立开发者也是免费的。你可以下载它,立即开始,无限制地发布到 Steam 或谷歌 Play 商店,直到你的游戏开始每年超过 10 万美元,这时你需要支付许可证费用(这仍然是非常合理的)。如果你每年的投资超过 20 万美元,你也需要付费,如果你打算将你的应用想法带到 Kickstarter,你需要记住这一点。有些功能也只对付费账户开放,但是大多数首次开发者不需要担心这个(我会在第二章详细介绍)。

此时你应该感到兴奋!通过使用 Unity,你可以用最近一些最大的开发者使用的完全相同的工具来构建一个游戏。构建一些基本的东西几乎不需要任何编码,当你确实需要独特的元素时,你通常可以在线获得它们。考虑到你将能够开发的游戏的质量,这里的学习曲线是非常宽松的——而且它是完全免费的(只要你坚持在免费许可证的限制之内)。

如果你一直梦想成为一名游戏开发者,但觉得遥不可及,那就再想想吧。从来没有这么容易过,有了 Unity 和这本书在手,没有什么能阻止你。

为什么移动设备非常适合独立项目

Unity 的另一个优点是它是跨平台的。你可以在你的 Windows PC 上制作一款游戏,然后在 Android、iOS、Xbox、Playstation、Unity(图 1-5 )等平台上销售。其中一些要求您申请开发人员许可证,购买开发工具包,或者面临其他限制。然而,理论上,跨平台的可能性是无限的。正如你将在本书后面看到的,Unity 甚至支持虚拟现实平台,如三星 Gear VR、Oculus Rift、HTC Vive 和谷歌 Daydream。当你按照这些页面中的说明进行操作时,如果你愿意,你可以选择将你的游戏移植到所有这些平台上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5。

Indie titles are highly popular on Steam

但这本书的重点将是 Android。这是因为 Android 是所有这些平台中最开源和最大的。它的进入门槛也最低,你会发现它通常是最容易成功的平台。

再回头看看用 Unity 制作的大型游戏列表,你会发现很多都是手机游戏。其中一个原因是 Unity 和移动平台都吸引了独立开发者。有两个原因说明移动设备是印度的理想之选:

  • 手机让你通过一个简单的分销渠道接触到大量的受众。
  • 移动降低了人们对游戏的期望,因此也降低了游戏创作的工作量。

简单来说,如果你为 Xbox One 开发一款游戏,它将与《使命召唤》和《侠盗猎车手》等游戏竞争。虽然 Xbox 上有蓬勃发展的独立场景,但潜在的图形保真度仍然要高得多,甚至输入也更加复杂。

这就是为什么《无尽的奔跑吧》在手机上如此受欢迎,但在其他平台上却不太成功的原因。无尽的奔跑是主角向前奔跑的游戏…无止境…玩家所要做的就是在正确的时间点击“跳”。偶尔,他们可能还需要滑动来改变车道或点击另一个按钮来执行另一个动作。但最终,游戏由随机生成的障碍、最少的输入组成,没有传统意义上的“阶段”。在移动设备上,这是可以接受的,因为当你在银行排队时,它提供了理想的两分钟分心。但是大多数人都不想坐下来玩一段时间的无休止的跑步,因此他们在游戏机和个人电脑上相对较少。

现在问问你自己:作为一个新的开发者,你更愿意做一个超真实的 3D 角色扮演游戏(RPG)——还是一个无止境的跑步者?

当然,这并不意味着你可以制造垃圾。这只是意味着手机游戏玩家更加宽容,更喜欢小规模的娱乐活动。这意味着你可以用一些精致但相对简单简短的东西取得成功。显然,这种一口吃掉的性质通常会反映在价格上,但这只是意味着你可能会卖出更高的数量。当然,如果你想变得更有野心,没有什么能阻止你。像《侠盗猎车手》系列中的几款游戏这样的完整游戏已经成功移植到手机上,双截棍射手、RPG 和其他游戏也是如此(见图 1-6 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-6。

Playing Geometry Wars 3 on an Android device

然而,批量销售把我们带到了下一点。移动平台如此受欢迎的另一个原因是它们拥有如此庞大的受众群体。如今,大多数人都有某种智能手机,可能运行 iOS 或 Android,这包括各种不同的人口统计数据。从祖父母到年幼的孩子,每个人都可以享受像愤怒的小鸟、糖果粉碎或与朋友交谈这样的游戏,这给了你大量的观众。

如果你把制作 Android 游戏作为一种爱好,你将能够与朋友分享它们,并获得大量反馈。如果你制作它们的目的是为了潜在的销售,那么你将拥有广泛的受众来推销它们。

为什么对开发者来说 Android 比 iOS 好

所以,手机很棒,但安卓更棒。为什么?首先,除了智能手机和平板电脑,Android 应用现在也可以出现在一系列设备上。Android 是一个完全开放的操作系统,这意味着 OEM(原始设备制造商)可以对其进行修改,以在电视、智能手表、电子书阅读器、洗衣机和其他各种硬件上运行。

好吧,所以大多数游戏短期内不会在洗衣机上运行。但是你当然可以创建一个在智能电视上运行的游戏,或者更好的是,像 Nvidia Shield 这样的游戏。更有可能的是,你将能够利用 Chromebooks 新的交叉兼容性。Chromebooks 是运行 Chrome OS 的计算机,Chrome OS 是一种基于浏览器的轻量级操作系统,自 2016 年以来一直能够原生运行 Android 应用。我会在后面的章节中详细讨论如何最大限度地兼容你的应用。

Android 相对于 iOS 的实际优势

选择 Android 而不是 iOS 也有实际优势。除此之外,当你选择 Android 时,整个过程要简单得多。目前,将应用上传到 Play Store 仍然是一个相对简单的过程,任何人都可以管理,不需要花费超过几个小时。你可以想出一个应用的想法,把一些东西放在一起,并让它在 24 小时内上线。

要想在安卓系统的游戏上赚到真金白银,你需要尝试进入谷歌 Play 商店(图 1-7 ),用户可以在那里搜索并下载应用。这样做需要一次性支付 25 美元的费用,并且全部自动处理。你只需打包并签署你的 APK 文件(图 1-8——别担心,我会告诉你怎么做)并使用简单的屏幕指示上传它。该应用然后上传并通过自动批准过程,几个小时内人们就可以开始下载它。你可以多次这样做,而不需要再次付费,并且你的应用只有在违反谷歌政策的情况下才会被删除。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-8。

Success is just a click away

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-7。

Games in the Google Play Store

与苹果的流程相比,这是一件轻而易举的事情,苹果的流程首先需要每年 99 美元的重复费用。即使你只有一个应用,每个月下载几次,你仍然需要每年支付 99 美元来维持它的运行。此外,iOS 应用需要经过一个审批过程,其中涉及真正的人类版主和更严格的限制。许多应用就是不允许在 iTunes 上运行,给出的原因往往有些模糊或武断。我知道至少有一个开发人员拒绝了一个笑话应用,因为它“不够有趣”那肯定是个人品味的问题!

当然,苹果的做法确实会让 iTunes 商店的应用整体质量有所提高。一般来说,iTunes 上的应用至少会达到最低质量,而一些相当严重的糟粕会进入 Play Store(这不是我们的目标!).然而,iOS 的风险在于,你花了几个月的时间创建了一个你非常满意的应用,结果却是它被拒绝,永远见不到天日。更重要的是,当涉及到应用的内容和性质时,使用 Android 只会给你更多的创作自由和更多的选择。

哦,还有一件事:为了开发 iOS,你需要给自己买一台 Mac 电脑和一台 iOS 设备来测试。这与为 Android 开发形成对比,理论上你甚至可以不需要 Android 手机就可以使用模拟器。这些必需的购买增加了开始使用 iOS 所需的投资。

Android 与 iOS 的价格为$$$

如果你对创作游戏主要是为了赚钱感兴趣,你可能不太关心创作自由,而更关注哪个平台能让你赚最多的钱。这样的话,苹果确实有一点点优势。

首先是好消息:Android 用户比 iOS 用户多得多,但 iOS 用户在应用上的花费可能是 Android 用户的两倍半。简单来说,iOS 用户往往口袋里的钱多一点,也更倾向于使用它。实际上,这个 2.5 倍相当于每个应用 1.08 美元,而不是 0.43 美元。iOS 用户进行应用内购买的可能性也增加了 50%(根据 AppsFlyer 在 2016 年发布的应用内支出全球和区域基准状况),7.1%的 iOS 用户每月至少进行一次应用相关支付,而 Android 用户只有 4.6%。

有一类应用是 Android 有优势的,但不幸的是,它对我们这些游戏开发者来说毫无用处:这一类是实用程序(图 1-9 )。Android 用户更有可能在实用程序上花钱,这很可能是因为开发者和应用所有者在这方面获得了更大的自由,允许他们创建自定义启动器、内存/电池管理工具、多任务应用等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-9。

Multiscreen Multitasking, an old utility app I developed for Android several years ago

AppsFlyer 的报告还揭示了其他有趣的数据:例如,与其他地区相比,亚洲用户在应用内购买上的支出高出 40%。如果你打算使用免费增值商业模式,瞄准亚洲市场可能是一个不错的策略。后面的章节将更多地讨论如何最大化你的收益。

现在的问题是:考虑到 iOS 提供了更大的收入潜力,你还应该为 Android 开发吗?当然,这是你的决定,但对许多人来说,为 Android 开发的好处大于坏处。为 iOS 开发需要太多的投资和风险,进入门槛太高。另一方面,Android 允许你立即开始开发游戏,并以更多的创作自由和更少的创作被拒绝的机会接触到更多的观众。最重要的是,Android 的市场份额在不断增长,而 iOS 的市场份额在萎缩。考虑到成千上万的原始设备制造商正在生产 Android 设备,而只有一家制造商在生产 iOS 设备,这是显而易见的。总体而言,应用支出也在上升。这使得 Android 成为更“面向未来”的市场,因为你的受众(和收入)可能会随着时间的推移而增加。

因此,尽管 iOS 可能是利润稍高的平台,但为 Android 开发也很有可能赚很多钱。到目前为止,比平台更重要的是应用的性质、营销和推广。在本书的其余部分,你将学会如何熟练地处理所有这些。

Android 和 Unity:天作之合

希望你现在相信 Android 是独立游戏开发的首选平台。选择 Android,你可以通过消除限制和前期费用让自己的生活变得非常简单,这意味着在 Play Store 中有一个可用的应用并开始推广它之前,时间会更短。

我们战略的另一个关键部分是 Unity 3D。我们已经看到了 Unity 提供的一些令人难以置信的优势,通过选择使用 Unity 为 Android 开发,您大大降低了成为开发人员的门槛。在第二章你会学到更多关于 Unity 的工作原理。现在,请记住它是一个游戏制作工具,与其他工具相比,它可以让你在很短的时间内制作出更专业的游戏。有了 Unity,你可以在几天之内真实地组装一个无限转轮或太空射击游戏,它看起来就像一个经验丰富的大型发行商的任何东西一样令人印象深刻(如果你玩得好的话)。

Unity 的界面对初学者非常友好,允许你根据需要简单地在屏幕上拖放许多元素(图 1-10 显示了该界面的预览)。如果你担心编程,考虑一下你实际上可以完全避免使用前面提到的 Unity Assets Store 进行编码,尽管这样做在很大程度上限制了可能性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-10。

Developing with Unity

正如我们已经看到的,Unity 也是跨平台的,允许您只需轻触一个按钮就可以发布多种格式。因此,所有关于是针对 Android 还是 iOS 的辩论都不太相关,因为你可以简单地创建一个游戏,然后按一下按钮就发布到两个平台。事实上,您还可以发布到 PC (Windows Store 和 Steam)、Windows Phone、Linux、Xbox 等等。

创建你的游戏的过程在不同的平台上几乎是一样的,所以即使是 iOS 开发者也能从我们在这里讨论的内容中受益。

如何选择你的第一个项目

使用 Unity 3D,可能性几乎是无限的。您可以创建任何东西,从简单的益智游戏到完全实现的 3D 第一人称射击游戏。由于摩尔定律,现在普通智能手机的功能已经接近游戏机质量,可以放在我们的口袋里。

但这并不意味着你应该开始下一次使命召唤。使用 Unity 完全有可能为 Android 开发一个非常详细的 3D 游戏(见图 1-11 ),但这并不意味着你应该这样做。这是绝大多数第一次开发的人会犯的错误,也是你需要从这本书中学到的最重要的信息之一。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-11。

Full 3D is also easy in Unity

简单地说:大多数第一次开发的人都有远远超过他们能力的抱负——他们只是忽略了在他们的第一个项目中控制他们抱负的需要。我并不想踩在任何人的梦想上,但这是一个更好的策略,开始创造一个可实现的和现实的目标,而不是承诺一个不可能的项目,最终占用你多年的生活,永远不会被看到完成。

想一想开发一个 3a 风格的标题所涉及的巨大事业。在一个城市环境中创建一个 3D 关卡,你需要 3D 建模每一个路人、每一辆车、每一个灯柱、垃圾箱、信箱、电话亭、街道上的垃圾、建筑物、敌人……不胜枚举。这些项目中的每一个都需要真实的物理、流体动画和相关的声音效果。你将需要过场动画、画外音、音乐、广阔的游戏区、多层次…对一个人来说,这是一个可能需要很多年的项目。到那时,技术将会继续发展,你所创造的一切可能会看起来过时。这就是发生在《毁灭公爵:永远》上的事情,这是一款背后有着经验丰富的大型工作室的游戏。这就是为什么最成功的独立游戏往往没有最逼真的图形;相反,他们选择吸引眼球的原创艺术风格,同时减轻创作者的工作量。

创造一个成功的独立作品的最佳策略

看看类似 Limbo 的东西,一款适用于 Xbox、Playstation、Windows 和 mobile 的游戏。这是一款早期的独立游戏,卖得非常好,在游戏社区引起了巨大的轰动。这在一定程度上要归功于完全使用剪影的艺术风格。这符合游戏的基调和形象,同时看起来令人惊叹,视觉上也很有趣。开发商(Playdead)无法通过使用超真实图形与顶级出版商竞争,而是走了一条完全不同的路线,提出了一些独特而非常有吸引力的东西。这些截图在应用商店滚动的过程中会非常突出,足以激起购物者的兴趣,并有可能让他们购买。

更好的是,通过选择使用轮廓,Playdead 大大减少了精灵和游戏元素所需的细节数量。游戏有绝对华丽的动画,这真的有助于销售的气氛,但这可能是唯一可能的,因为缺乏细节使团队能够将注意力集中在该地区。

当然,不是每个游戏都可以使用剪影,但是你需要跳出框框思考,变得有创意。一个特别受欢迎的选择是使用“像素艺术”。这是一种复古风格,模仿旧的 8 位和 16 位游戏机的图形,具有非常怀旧的吸引力。同样,它限制了所需的工作量。像《超级兄弟:剑与武器》EP 这样的游戏展示了这种风格是如何被运用到非常漂亮的效果中的。

考虑游戏性

同样的方法也应该用在游戏中,尤其是你的第一个项目。与其致力于制作需要你创建 3D 模型和充满细节的大地图的第一人称射击游戏,不如尝试一些 2D,最好是用程序生成或其他技术来减少你的工作量。(程序化生成是指游戏元素根据算法随机添加,去除了手动创建关卡的必要性。)

如前所述,无尽的奔跑在移动平台上非常受欢迎,这要归功于它们简单的游戏性和缺乏复杂的控制。在这里,当主角向前奔跑时,你所做的就是点击跳跃,这允许你躲避即将到来的障碍和敌人。所述障碍和平台是随着游戏向前滚动而随机产生的,并且玩家持续的时间越长,游戏的速度越快。可重复性来自于努力达到最高分,也来自于没有两次“跑”是完全相同的这一事实。像雷曼嘉年华运行,卡纳巴尔特和马里奥运行这样的游戏已经用这个非常简单的公式卖出了大量的游戏。Flappy Bird 也可以被视为传统无限转轮公式的变体。

其他游戏使用更简单的游戏机制。Terry Cavanagh 的神奇超级六边形利用了非常有创意的图形,由向屏幕中心移动的六边形组成(这产生了一种非常迷幻的效果),以及一个简单的目标,即按下屏幕的左右两侧,尝试将您的化身移动到每层的小间隙中。这个游戏看起来非常独特和催眠,难度使它非常吸引人。这足以使它成为一个巨大的成功,特里不需要设计一个单独的精灵或关卡地图。

或者山羊模拟器怎么样?这是一个独立游戏,正如它的名字所说:它允许你控制一只山羊,同时在沙盒环境中制造各种混乱。这款游戏是 3D 的,但是它愚蠢的本质意味着没有人会期待真实的图形或物理,甚至是挑战关卡设计。尽管如此,这款游戏还是非常成功,这要归功于其核心理念的吸引力以及所有游戏片段对 YouTuber 的友好性。在这种情况下,光是这个想法就胜过了对任何技术成就的需求。Android 上有许多游戏声称是“世界上最难的游戏”,这些游戏之所以成功是因为同样的原因:它们的概念天生就很吸引人,这促使人们下载。

如果你想把开发游戏作为一种爱好,那就随意摆弄你喜欢的任何夸张的项目。但是,如果你想赚些钱,或者至少从真实用户那里得到一些积极的反馈,寻找“容易的胜利”——至少在开始的时候。

所以这是我们要做的

暂时搁置那个改变世界的角色扮演游戏,转而考虑在你的第一个项目中做一些更小的东西。忘记 3D 屠龙者:史诗般的探索,多想想复古的抓捕游戏。

一个简单的益智游戏,一个基本的 2D 平台,或者一个你可以在几周内完成的无限跑者,将会给你机会将一些具体的东西带到这个世界,并在你前进的过程中发展你的技能。这样,你就不会在一些可能永远不会成功的事情上投入太多的时间和精力,你就能很快开始受益并完善你的策略。好消息是 Unity 有一个 2D“模式”,使得这个策略简单了很多,并且改变了用户界面和特性来更好地支持 2D 游戏开发。

在商业中,这种方法被称为快速失败。你不是创造一个需要多年研发和数千美元投资的产品,而是创造简单、容易、不需要成功的产品。如果产品失败了,你只需继续你的下一个想法。但是,如果它在市场上获得了牵引力,那么你就要花一些时间来发展这个想法,并进一步发展。

没有什么比把你生命中的岁月倾注在一款游戏上,只为了它获得十次下载和一星评价更能摧毁灵魂的了。所以,创建一个 MVP(最低可行产品),让它进入 Play Store,然后只有在它找到受众的情况下才能开发它。

如果你的艺术风格足够独特,游戏玩法足够新颖,你的营销技巧足够强大,你会惊讶于一个相对简单的游戏所能产生的影响。

你将从这本书中学到什么

考虑到所有这些,这本书将带你经历使用 Unity 设计、构建和发布一款全功能 Android 游戏的整个过程。具体来说,它带你通过创建一个 2D 平台或一个无止境的跑步者的基础,这包括从建立物理和精灵到签署你的 APK 准备上传到游戏商店的一切。

你将要做的项目将足够基本,你可以很容易地修改它以适应你自己的目的,通过改变几个精灵并给它一个新的标题,你将准备在几周内发布你的第一个游戏。游戏将会很简单,但是会有足够的功能来帮助你掌握 Unity 游戏开发的核心概念,这样你就可以将它们应用到未来的项目中。

您将发现以下内容:

  • 如何安装和设置 Unity
  • 如何使用 Android SDK(软件开发工具包)
  • 如何在 Unity IDE(集成开发环境)中找到自己的路
  • 如何创建和添加精灵
  • 如何添加动画
  • 如何用刚体 2D 介绍物理学
  • 如何使用 Visual Studio 用 C++ 和 Java 编程
  • 如何添加收藏品、音效、敌人、游戏机制等等
  • 如何添加关卡、分数、关卡选择、菜单等等
  • 如何添加动态摄像机
  • 如何设计有趣且具有挑战性的关卡
  • 如何创建已签名的 APK 文件以备上传
  • 如何将应用发布到谷歌 Play 商店
  • 如何为你的应用定价以获得最大利润
  • 如何推广您的游戏并获得更多下载

在整个过程中,我们将使用少量的代码和大量的媒体(精灵、音乐、音效和背景),所有这些都将供您在自己的项目中使用,进行逆向工程,或者进行您认为合适的编辑。

在这本书的过程中,我们也将看到你可以用 Unity 创造和构建的各种不同的东西。目的不是限制你,所以你会发现如何在 3D 中工作,甚至为 Gear VR(图 1-12 )、Google Cardboard 和 Google Daydream 制作虚拟现实应用。这将给你一个坚实的知识基础,如果你想拓展自己的发展,并在未来承担更具挑战性的项目,这将成为你的起点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-12。

Developing for the Gear VR with Unity

是的,Unity 3D 可以用来创建应用和实用程序,如果你愿意,你在本书中学到的技能也可以让你这样做。

TLDR;这是成为独立开发者的大好时机。Android 和 Unity 为想要在 Play Store 中推出具体产品的初学者提供了完美的组合。这本书带领你完成一个简单游戏的开发,并提供你需要知道的一切,让你的第一个项目起步,并帮助你在未来成长为一名开发者。

准备好了吗?是时候开始了,玩家 1!

二、Unity 简介和设置

为 Android 开发已经对初学者和寻求赚钱的独立开发者有很大的意义。但 Unity 3D 让一切变得不同,因为它让这一切变得简单而实用。Unity 是一个令人难以置信的强大工具,它可以让你更快更容易地创建一些令人敬畏的游戏。

在这一章中,你将对 Unity 有一个更好的了解,它是什么,它从哪里来,以及你如何着手设置它,以便你可以开始使用它。

什么是 Unity?

第一章简要介绍了 Unity,但现在是时候更深入地了解 Unity 能为你做什么,以及它将如何影响你的工作流程。本章涵盖了什么是游戏引擎,什么是 IDE,以及如何设置和运行它。到这一章结束时,你将掌握基本知识,并准备开始动手实践。如果你已经熟悉了 Unity,并且它已经安装在你的电脑上,你可以跳过这一章。

作为游戏引擎的 Unity

从本质上来说,Unity 是一个游戏引擎,已经发展成为一个 IDE/快速开发工具。如果这一切听起来像天书,不要担心,我会分解它。

说得更详细一点,游戏引擎本质上是大量的代码,处理让游戏运行的所有无聊的部分。值得注意的是,这包括物理以及渲染,照明,基本的相机功能,等等。虚幻引擎是游戏引擎的另一个例子,CryENGINE 3 也是。其他的还有 Torque、Lumberyard、Ogre3D、Blender、JavaFX 等等。

如果你完全从零开始编写一个游戏,而不使用预先存在的游戏引擎,你将需要自己编写每一个细节,这意味着在你开始添加关卡等东西之前,需要进行大量的开发。当一个木箱已经被你处理好的时候,再去编码它应该如何坠落和破碎是没有任何好处的。

同样,这也是我们看到独立开发者复兴的原因。回到 ZX 光谱和 Amstrad 的时代,游戏引擎可以简单得多,大多数精灵是由大约 50 像素组成的。如果没有 Unity 这样的解决方案,当今游戏的复杂性将使一个人不可能单干。

Unity 也是交叉兼容的,这意味着它可以作为你的代码和你的目标设备之间的桥梁。编译您的游戏会压缩所有资源,并将其转换为正确的文件格式,以便添加到相应的分发平台。

简而言之,Unity 为你处理所有幕后的事情,并允许你开发一个伟大的游戏,而不用担心重新发明轮子或担心光线应该如何通过各种材料折射(见图 2-1 中我愉快地编码)。就好像宇宙的规律已经被创造出来了,你要做的就是把它填满。然后 Unity 会处理最后的必要的跑腿工作,把你的世界变成一个真正的游戏准备发行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-1。

Unity streamlines development (photo by Sophie Bunce)

今天,绝大多数开发人员——甚至是大工作室——都使用像 Unity 或 Unreal 这样的现成 ide。偶尔,一个游戏会使用一个定制的引擎(如“节奏暴力”游戏 Thumper),但这些通常有独特的游戏机制,保证创建一个定制的引擎,他们通常花很长时间进行开发。

因为 Unity 使生活变得更容易,而没有引入任何主要限制,所以没有理由不使用它(或类似的选项,如 Unreal)。“单干”只会让挑战变得更加困难,没有任何实际的好处。

Unity 作为 IDE

然而,让 Unity 成为开发者福音的是,它同时是一个游戏引擎和游戏制造商,拥有用户友好的界面,允许元素在屏幕上轻松拖放(图 2-2 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-2。

An IDE is a single environment for developers to handle every aspect of creating their game

用更专业的语言来说,Unity 不是一个游戏制造商,而是一个 IDE。IDE 是 Integrated Development Environment(集成开发环境)的首字母缩写,它本质上是一套用于开发的综合工具,通过一个简单的界面就可以查看和修改一个程序的各个方面。如果你要创建一个没有 Unity 的 Android 应用,你需要使用另一个 IDE——很可能是 Android Studio,它将允许你查看代码、你的素材文件夹、调试信息、图形预览等等。在 Unity 的情况下,你可以看到场景的视图(本质上是关卡),场景中所有元素的层次结构(称为游戏对象),你选择关注的任何项目的细节,你的素材文件夹等等。我们将很快看看 Unity 提供的所有不同的窗口和视图。

统一 vs 虚幻 4(及其他)

我说过没有理由不使用 Unity,但这并不完全正确。有一个很好的理由让你选择不使用 Unity,那就是如果你打算使用其他各种游戏引擎/制造商的话。

或许最接近的比较可以用虚幻 4 来画(图 2-3 ),有很多相似的特点。两者都功能齐全,限制很少,这一点——加上它们相对简单——使它们成为独立工作室最受欢迎的两个 ide。那么两者哪个平台更好呢?为什么选择 Unity?一如既往,答案取决于你打算开发什么类型的游戏。在我们的例子中,我们打算为 Android 制作一个 2D 游戏,对于这个特定的任务,Unity 是首选。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-3。

The Unreal logo (boo!)

虽然它并不多——而且往往只是归结于个人偏好——Unity 可以说对手机游戏开发和 2D 游戏开发有更好的内置支持。Unity 是手机上最受欢迎的游戏引擎,这反映了它的能力。这也确保了有一个巨大的社区为创作者提供支持,以及素材商店中几乎无限的定制素材,这可以大大加快开发速度。

许多人也喜欢 Unity 的流程,它允许你使用实体(游戏对象)和组件(脚本)的简单系统来构建游戏。这当然是一个见仁见智的问题,但足以说,Unity 在很大程度上是非常直观的,初学者也很容易使用。另一方面,虚幻的学习曲线更陡,组织性也不是很好。但虚幻 4 有更好的图形功能来开发 3a 外观的游戏。它也是开源的,这实际上意味着您可以访问源代码并对引擎本身进行更改。对于以移动设备为目标的独立开发者来说,这些都不是问题。所以 Unity 就是胜利。

统一的起源

Unity 由一家名为 Unity Technologies SF 的公司开发,该公司于 2004 年由大卫·赫尔加松、尼古拉斯·弗朗西斯和约阿希姆·安特在丹麦哥本哈根创立。图 2-4 为撰写时的官网。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-4。

The Unity home page today

在此之前,这三位开发者自称为 Over the Edge Entertainment,并为 Mac 开发了一款名为 GooBall 的游戏,其游戏玩法类似于超级猴子球。尽管这款游戏没能引起轰动,但团队意识到该引擎可能对其他开发者有价值。因此,他们在 2006 年的 WWDC 贸易展上宣布为 OS X 推出 Unity 3D。

从那时起,Unity 经历了多次迭代和开发,现在就其支持的平台和包含的特性而言,已经更加全面了。1.1 版支持为微软视窗和浏览器创建游戏,同时支持 C/C++ 插件。2.0 版本增加了对微软 DirectX 的支持,2008 年发布了 Unity iPhone。

2010 年发布的 3.0 版本是另一个重要步骤,因为该团队希望该程序能够在 Windows 上运行,这需要从头开始重建。因此,3.0 版本整合了 Windows、iPhone,以及对 Wii 和许多其他平台的支持,而这些平台以前只能由单独的独立编辑器支持。现在 Unity 这个名字终于有意义了。是的,这也是我们支持 Android 的时候。

unity 4.3 版本见证了另一个重要的更新:Unity2D 包含了开箱即用的 2D 支持。到目前为止,开发人员基本上不得不通过使用固定的相机角度和向平面添加纹理来创建背景,从而“侵入”IDE 以支持 2D。现在,创作者可以更快更容易地利用精灵和其他更传统的方法来构建真正的 2D 游戏。

据 Unity Technologies 称,Unity 5.0 将是最大和最重要的版本,具有更好的全面性能,并对动画系统、混音器、着色器等进行了重大更新。因此,现在许多人把 Unity 称为统一。在撰写本文时,Unity 的最新版本是 5.5.0。它特别为 Android 做了许多改进,应该会提高性能。

如果你有新版本的 Unity 怎么办?

值得注意的是,Unity 正在不断开发其平台,并添加新的功能和改进。因此,根据你阅读这本书的时间,你可能会发现一些元素与这里描述的不同。也许你正在阅读遥远的未来,你正在使用 Unity 200。如果有,我希望你有一辆会飞的汽车。

然而,更有可能的是,你遇到的任何变化都是微小的。当然,像 Unity Technologies 这样的中间件开发人员努力避免在未来的更新中破坏代码,这意味着大多数基本功能仍然可以工作。

但在一些罕见的情况下,一行代码可能会在 Unity 中突出显示,并被描述为被否决。这意味着它被支持但不被鼓励。如果你注意到了这一点,快速的谷歌搜索会帮助你找到新的、正确的方法来处理这个功能。

执照

似乎 Unity 还不够棒,最棒的是它还可以完全免费使用(大部分情况下)。在未来,随着你的野心增长,你可能会发现自己需要额外的功能或收入超过 10 万美元的门槛,但大多数新手都会很好,除非他们的游戏大获成功。这是最糟糕的情况。

基本上,您可以创建几种不同类型的账户,如图 2-5 所示,每种账户都有不同的定价和不同的限制。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-5。

For most people, the free personal plan will more than suffice

个人的

你首先要用的免费账户是个人账户。这个账号不用花钱,Unity 连版税都不拿。唯一的限制是你每年在这个许可证上的收入不能超过 10 万美元。不过,这没关系,因为一旦你开始交出大数字,你可以简单地切换到其他许可协议之一。请记住,这个 10 万美元的限制也适用于筹集的资金,这意味着如果你在 Kickstarter 上筹集的资金超过 10 万美元,那就算数。这条规则也适用于其他来源的利润,包括点击付费广告或应用内购买。

个人帐户还有一些缺失的功能和限制。例如,当游戏启动时,使用个人帐户的创作者被要求显示 Unity 闪屏(向用户显示你在 Unity 中制作游戏),而你将无法访问实时开发者分析或云构建。对于多人在线游戏,个人帐户一次只允许 20 名玩家。

Unity Plus

Unity Plus 目前每月收费 35 美元,取消了闪屏,同时将收入上限提高到每财年 20 万美元。它还增加了对大型开发人员有用的额外支持和功能,比如支持 50 个并发用户和打折的素材包。

Unity Pro

Unity Pro 将价格提高到每月 125 美元,并完全取消了收入上限,这意味着如果你愿意,你无需支付更多费用就可以变得非常富有。它还提供了许多专业服务,包括支持多达 200 个并发玩家,更多的分析和性能,支持大型团队,等等。

Unity 企业

最后,企业成员资格允许您挑选功能,以创建一个针对您的独立需求的定制开发平台。这是最高级的选择,价格实际上根本没有列出——这表明它非常昂贵。简而言之,大多数阅读本书的人暂时还不需要担心这个问题。事实上,对于绝大多数人来说,基本的个人帐户已经足够了,应该能够提供您需要的所有功能和灵活性。

Note

这些是我写这篇文章时的价格,但它们当然会有变化。也可以通过按年付费来省钱,如果你想买一个更高级的账户,你应该做进一步的研究。

下面是一个方便的表格,比较了各种功能:

| 个人的 | 加 | 赞成 | | --- | --- | --- | | 所有发动机特性 | 所有发动机特性 | 所有发动机特性 | | 所有平台 | 所有平台 | 所有平台 | | 持续更新 | 持续更新 | 持续更新 | | 免版税 | 免版税 | 免版税 | | MWU 闪屏 | 自定义闪屏 | 自定义闪屏 | | 收入上限为 10 万美元 | 收入上限为 20 万美元 | 没有收入上限 | | Unity 云构建的标准队列 | Unity 云构建的优先级队列 | Unity 云构建的并发构建 | | 个人分析 | Plus 分析 | 专业分析 | | 20 名并发玩家 | 50 个并发玩家 | 200 个并发玩家 | | Unity 应用内购买 | Unity 应用内购买 | Unity 应用内购买 | | 统一广告 | 统一广告 | 统一广告 | | Beta 访问 | Beta 访问 | Beta 访问 | |   | 专业编辑用户界面皮肤 | 专业编辑用户界面皮肤 | |   | 绩效报告 | 绩效报告 | |   | 灵活的座位管理 | 灵活的座位管理 | |   | 素材套件八折优惠 | 素材套件 40%折扣 | |   | Unity 认证课件 1 个月使用权 | Unity 认证课件 3 个月使用权 | |   |   | 源代码访问(美元) | |   |   | 特优支持(美元) |

下载 Unity 和所需组件

好吧,我想我已经说得够多了。让我们从技术层面开始吧。你当然需要设置 Unity 并让它在你的电脑上运行。这在很大程度上足够简单,但是请记住,您还需要一些额外的软件。具体来说,您需要下载并安装以下软件:

  • Unity 本身
  • Android SDK(以及 Android Studio 2.3)
  • 爪哇 JDK
  • 可视化工作室

Android SDK 是 Android 软件开发工具包。这是 Google 提供的一套软件工具,可以作为访问硬件功能的桥梁。换句话说,它提供了 Unity 需要的源代码,以使您的游戏在 Android 平台上兼容。它还包含一些其他工具,可能在未来对你有用——包括一个模拟器,允许你在桌面上测试 Android 应用。你还需要选择安装 Android 构建支持,但你是通过 Unity 安装程序来完成的,所以没有必要单独下载。

Java JDK(图 2-6 )是另一个开发工具包,这次是针对 Java 的。这是你的计算机支持 Java 开发所需要的,因为 Java 是 Android 的主要语言,你需要它来继续。我们会先下载这个。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-6。

The Java logo

Visual Studio 是您在 Unity 中用来处理实际编程的工具。当您开始编写脚本时,您将在一个单独的 Visual Studio 窗口中编辑这些脚本——但是我们可以稍后再考虑这个问题。请注意,您实际上并不需要 Visual Studio,也可以使用 MonoDevelop 之类的替代选项。但是 Visual Studio 肯定是这两者中的首选,并且会让您的生活变得轻松一些。

下载 Unity

要开始下载 Unity,首先前往 Unity3D.com(https://unity3d.com),然后点击立即获取 Unity。然后你可以选择你想要的计划(大多数情况下是个人的),在那里你只需点击立即下载,然后在下一页下载安装程序(图 2-7 )。一旦你这样做,下载将开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-7。

This is where you will find Unity

您不需要单独下载 Visual Studio,因为您可以通过 Unity Downloader 来完成。这为你节省了一点时间和麻烦。

下载 Java JDK

如果你觉得有点不知所措,不要担心。一旦你安装了所有这些小部件,它们就会在后台自己运行,你可以把它们忘得一干二净。这是一个一次性的过程(除非你在一台新电脑上安装 Unity ),你再也不用担心了。

Java JDK 允许你的计算机和 Unity 理解和解释 Java 代码。前往 www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html 并下载 Java SE 开发工具包(图 2-8 )。如果您的计算机支持 x64 版本,请确保选择该版本。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-8。

The Java JDK download page

下载 Android SDK

要下载 Android SDK,请前往 https://developer.android.com/studio/index.html (图 2-9 )。点击下载 Android Studio 按钮,接受条款和条件,开始下载。如果您运行的电脑硬盘相对较小,请点按“下载选项”。Android Studio 是用于创建常规应用的标准 Android IDE,使用 Unity 实际上并不需要它。为了节省大量不必要的文件,您可以下载命令行工具,然后使用附带的 SDKManager 来下载 SDK 的其余部分。你可以在 Android Studio 网站上找到如何做到这一点的说明。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-9。

It’s easiest to download Android Studio and the Android SDK at the same time

不过这要复杂得多,Android Studio 肯定是一个有用的东西,所以如果你能负担得起空间,我建议你一旦有了 Java 就安装整个包。

安装 Unity 3D

一旦所有东西都下载完毕,开始安装就非常容易了。首先找到保存它们的文件,然后依次双击每个文件。从哪一个开始并不重要,所有必要的步骤都将在本节中解释。

一致

当您双击 Unity 安装程序并接受许可协议条款时,您需要选择下载哪个版本的 Unity:64 位或 32 位。最佳版本将取决于您的 Windows 版本,因为并非所有计算机都支持 64 位。要检查您是否拥有 x64 或 x32 位处理器,请前往这台 PC,右键单击,然后转到属性(图 2-10 )。如果您的计算机是 64 位的,它将显示:“64 位操作系统,基于 x64 的处理器。”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-10。

This Surface Pro 3 is 64-bit

如果你能支持 64 位,那么这是一个去,因为它将启用控制台支持和其他功能。您将看到的下一个屏幕是下载助手屏幕。这可以让你选择你想安装的组件,它会显示你需要多少空间在你的电脑上。

在左边,很多不同的选项都被勾选了,还有一些框没有被勾选。默认情况下,您应该会发现选择了以下内容:

  • Unity 5.5 0f3
  • 文件
  • 标准素材
  • Microsoft Visual Studio 社区 2015

它看起来应该如图 2-11 所示。让这些都保持原样,因为它们都很重要。Unity 和文档是不言自明的,而 Microsoft Visual Studio Community 2015 将允许您在游戏中创建和编辑脚本(如前所述)。标准资源选项不是强制性的,但会非常方便——这是一个大的预制脚本、精灵、3D 模型、纹理等选择,您可以在自己的游戏中自由使用。如果你有空间,那么添加这些是一个非常好的主意。如果你认为你想为所列的任何其他平台开发(并且你有空间),那就去做吧,也勾选这些选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-11。

Tick these boxes for smooth sailing later on

不过,还有一个默认情况下没有选中的选项,您希望确保获得:Android 构建支持。这将确保您可以创建 APK 文件并上传到 Play Store,并且在您测试和完成项目时将需要这些文件。确保勾选了。

您还会注意到这里的 iOS 构建支持,以及 Mac 构建支持、Windows 应用商店选项等。好消息是,如果需要,您可以稍后再回来添加这些内容。您会注意到需要多少空间(在撰写本文时大约为 10.3 GB),如果您的硬盘上有可用的空间,您可以继续操作并再次单击 Next。

现在选择您希望 Unity 安装在计算机上的位置。这完全是个人喜好的问题,但是一定要记住这一点。接受更多的协议条款,再次点击下一步,然后等待 Unity 安装。

去给自己冲杯咖啡吧,因为这的确会花去不少时间。

爪哇 JDK

安装 Java JDK 非常简单。只需双击文件,点击下一步两次,就开始了(图 2-12 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-12。

The JDK installer

在几个进度条被填满后,你可以选择一个目标文件夹。写的时候默认是 C:\ Program Files \ Java \ JRE 1 . 8 . 0 _ 111(图 2-13 )。就这样吧,但你可能想记下来,以备后用。再次单击 Next,安装程序将完成,您将准备好进行下一步:安装 Android SDK。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-13。

Set your destination folder

Android SDK

最后,你需要安装 Android SDK。为此,您需要安装 Android-Studio-Bundle。双击。然后单击欢迎屏幕上的下一步(图 2-14 )进入第一组选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-14。

The Android Studio installer

在这里您将选择您想要安装的内容(图 2-15 )。恼人的是,你不能取消选择 Android Studio(因为谷歌),但你可以决定你是否想要 Android SDK 和虚拟设备。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-15。

Decide whether you need the AVD

SDK 是我们需要的主要部分,所以请确保勾选它。同时,Android 虚拟设备是一个模拟器,你可以用它来运行应用。除非你正在制作一个非常简单的益智游戏,或者你有一个非常强大的游戏装备(这里我们说的是两个 4 GHz CPU 的 GTX1080s),否则你可能无法使用这么多来测试你完全实现的游戏。你也可以在你的 Android 设备上进行实时测试,所以如果你想为自己节省 1 GB 的数据,你可能需要取消选中这个。也就是说,它可以用于其他测试目的(例如,试验屏幕尺寸),所以这是你的电话。

无论哪种方式,单击下一步,然后同意条款和条件。在下一个屏幕上(图 2-16 ,您可以选择安装 SDK 和 Android Studio 的位置。如果后者比较迟钝(默认情况下,可能是:C:\ Users \ rushd \ AppData \ Local \ Android \ SDK),那么找一个更简单的地方安装它,那里有 3.2 GB+的空闲空间。记下这是哪里,因为您稍后会需要路径。我选择了 C:\AndroidSDK,因为路径不允许包含空格(很烦人)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-16。

Finally, set your destination folder

在下一个屏幕上再次单击 Next,然后安装将开始。

硬件和工作流程

在下载所有这些东西的同时,让我们利用这个短暂的插曲来考虑创建游戏和实现最佳设置的最佳硬件。

好消息是,你的电脑不需要特别强大来处理 Unity,但你至少需要相当现代的东西。我个人在 Dominator Pro GT72 6RE 和 Surface Pro 3 上运行 Unity(图 2-17 )。Dominator Pro 是一款非常新的 VR 游戏笔记本电脑,配有 GTX1070 GPU,在 Unity 上没有任何困难。就使用 Unity 进行 Android 开发的理想规格而言,Surface Pro 3 肯定处于低端。虽然我从来没有做不了任何事情,但当我编码时,系统确实变得相当热,一些 3D 游戏可以看到帧速率下降。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-17。

A device like the Surface lets you work on the move

基于这一点,我想说 Surface Pro 3 (i5)型号代表了你想要使用的最低规格。这意味着:

  • 1.9 GHz 处理器(睿频加速至 2.6 GHz)
  • 集成显卡
  • 4GB RAM

不过,Unity 网站推荐更高的版本,并建议开发者至少拥有某种形式的专用显卡或具有 9.3 功能级别的 DX11。更大的内存也是更好的选择,尤其是如果你打算使用其他软件如 Photoshop(或免费的替代品如 Fusion、DaVinci 或 GIMP)来创建大图像和在工具之间进行多任务处理。如果你计划用模拟器测试你的游戏,你也会想要更高的规格,尽管你甚至在使用非常强大的机器时也会为此而挣扎。

GPU 是一种图形处理器,用于更快地渲染 3D 场景。如果你主要在 2D 开发(这本书的大部分内容都将致力于此),这可能不是一个大问题,但是给自己一些选择肯定没有坏处。同样,它对使用 Blender 进行 3D 建模的部分也很有用。

除了 GPU,另一个有用的附加功能是同时拥有 HDD 和 SSD 硬盘。固态硬盘是固态硬盘,是硬盘驱动器的替代产品,速度非常快,但通常比速度较慢的老式硬盘要小一些。得到 128 GB 或 256 GB 左右的固态硬盘是标准配置。因为 Unity、Android SDK 和 Android Studio 都占用大量空间,所以为了加快速度,在硬盘上保留至少一些文件,同时在 SSD 上保留操作系统和游戏文件可能会很方便。不过,这是一个偏好,而不是一个要求。

简而言之,可以用一台中档电脑凑合,但使用某种游戏装备肯定会更好。除此之外,拥有一个能够玩游戏的装备对于研究来说是非常有用的。

创建你的战斗站(工作设置)

考虑你的实际设置和工作环境也是值得的,因为这可以给你在开发过程中带来很大的不同,并且可以让你以后不再头疼。例如,一个很大的优势是拥有一个大显示器,甚至可能是一个超宽的 21:9 显示器(图 2-18 )。Unity 有很多不同的窗口和面板,我们将在第三章中看到,能够同时看到所有这些是一个很大的优势,这样你可以更容易地处理任务。大屏幕将大大提高您的多任务处理能力,帮助您避免眼睛疲劳,并提高沉浸感(消除分心)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-18。

A superior setup

如果你喜欢在笔记本电脑上工作,确保它有更大的屏幕(18.3 英寸或更大),并且有足够的马力来应对。在咖啡馆边喝咖啡边工作是有好处的(我发现它能提高生产率),但为此,你最好想要一台雷蛇、华硕、戴尔、惠普、联想或东芝的新款笔记本电脑。Surface Book 或 MacBook 也能很好地完成这项工作。当然,我们的安装说明是针对 Windows 用户的,所以如果你将在 Mac 上运行,你需要经历一个稍微不同的过程来启动和运行。

当然,你需要一个舒适的键盘,一个精确的鼠标来打字和拖放。在电脑上测试游戏时,有线键盘更有利于提高响应速度。如果你是为了创造最好的设置而花钱,像海盗船游戏键盘这样的东西不仅可以用来打字,还可以用来测试和玩游戏。

否则,确保你有一把舒适的椅子,理想的是一个大的桌子空间来展开和安排笔记和草图,以及一个尽可能不受干扰的房间。如果你做到了这些,你就可以开始工作了,你会发现你的工作尽可能的顺利和愉快。如果你计划做大量的开发工作,投资一个好的工作空间是一个花钱的好方法,并且会更快地完成更好的最终产品。

开始你的第一个项目

安装完成?太好了。

此时,您应该已经在您的计算机上安装了 Unity 和它所需的所有必要组件,并准备就绪。希望你迫不及待地投入进来并开始行动。在这种情况下,让我们第一次启动 Unity,并做最后一点设置。

首先,您需要登录您在网站上创建的帐户。如果您还没有这样做,请单击链接(创建一个),您将被带到相关页面,在那里您可以设置一个。然后,你可以使用新的 Unity ID 登录,如果你想继续使用免费帐户,你需要确认你的公司的收入低于阈值。

一旦你通过了那个屏幕,你会看到一个窗口,让你从现有项目中选择或者开始一个新的项目。你现在可能什么都没有,因为这是你第一次使用它。因此,单击 New 并为您的项目选择一个名称和位置(图 2-19 )。你还需要确保你选择了 2D,这样游戏将自动支持 2D 格式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-19。

Starting your first project

在这一点上,你如何称呼游戏并不重要——这只是文件夹的名称。以后你可以把 APK 的名字改成你喜欢的任何名字。现在,我们姑且称之为简单的平台玩家。输入,勾选 2D,然后点击创建项目。稍等片刻,迎接你的将是一个相当空洞的 Unity 项目。有许多窗口,在这一点上可能看起来有点混乱,但是不要担心,我们将在下一章中讨论每件事情的作用。

设置路径

让我们做最后一点设置,告诉 Unity Android SDK 在我们系统上的位置。前往顶部菜单,找到编辑➤首选项➤外部工具。然后你会找到一个空间来输入 Android SDK(主文件夹)和 Java JDK(文件)的位置,如图 2-20 所示。如果您之前记下了这些路径,请将其复制并粘贴到此处。否则,点击浏览并导航到正确的位置。如果您的文件夹位于 AppData 中,它可能是隐藏的,所以告诉文件资源管理器显示隐藏的项目(在视图选项卡下),然后手动跟踪它。它就在某个地方——继续找。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-20。

Setting up your paths

在你第一次来测试你的应用之前,你实际上不需要担心这个,但是在我们开始之前做好一切准备是很好的。如果你愿意,你现在可以跳过这个阶段,但是一定要在你的游戏第一次发布时再回来。

完成后,Unity 现在已经建立并准备就绪。是兴奋的时候了,因为在第三章我们将开始实际使用它,安排一些游戏对象,甚至介绍非常基础的物理学。

三、在 Unity 中寻找答案

因此,Unity 现在已经启动并运行,没有什么可以阻挡您。该走了。

在您构建任何东西之前,让我们首先让您熟悉不同的 UI 元素、控件和选项。你将在这里呆很长时间,所以熟悉一下是个好主意。

这是什么?熟悉 IDE

当你第一次看到 Unity(图 3-1 )时,它可能会因为许多不同的窗口、菜单和选项而显得相当混乱。幸运的是,一旦你开始行动,一切都比看起来简单得多。我们将在本章的课程中讨论这些不同视图的用途,同时我们将能够测试我们的第一个非常简单的应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1。

Welcome to Unity! You’ll be spending a lot of time here

首先是观点。

事件

Unity 的正中央是一个名为 Scene 的视图。这是你完成大量工作的地方,也是你移动各种游戏对象和安排一切的窗口。这将显示您在任何给定时间正在处理的级别/菜单屏幕的视图,并允许您选择和重新定位屏幕周围的元素。你可以放大和缩小,如果你在 3D 模式下,你还可以将相机移动 360 度。

素材商店

在场景窗口的顶部(图 3-2 )有两个选项卡,允许你在两个不同的功能之间切换。点击 Asset Store 选项卡,正如您所预料的,场景视图将被更改为 Asset Store 视图。在素材存储中,您可以浏览各种素材,包括脚本、游戏对象、精灵、效果等,并将其包含在您自己的应用中。这些素材由其他 Unity 开发者以及 Unity Technologies 开发。有些是免费的,有些是要花钱的;有些是对现有项目非常简单的补充,而另一些实际上是完全现成的游戏,供你随意编辑。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-2。

Scene, Game, and Asset Store tabs

简而言之,通过确保您不需要手动创建每个脚本和精灵,素材存储使您的生活变得更加容易。

也就是说,这是你暂时不需要的东西,所以现在保持这个状态,不要担心它。

比赛

该窗口上可能还有第三个选项卡,如上图所示,名为 Game。在这个视图中,您可以看到真实的游戏,就像它在直播时一样。当你玩游戏时,这就是它的位置(除非你在玩游戏时选择最大化游戏)。

如果游戏不在同一个地方,它会在那里的某个地方。你可以自由地改变窗口的位置,有时在更新后,默认设置会改变。大多数人应该会发现所有东西都在同一个地方,他们可以按照这些指示去做。如果没有,您应该能够很快找到每个元素。

你不能将元素拖放到游戏视图中(就像在场景视图中一样),也不能选择或移动它们。也就是说,在很大程度上,游戏视图会反映你在场景视图中看到的一些不同。首先,视角将固定在游戏中的摄像头上,这意味着你将看到你的玩家在启动游戏时会看到的东西。同样,当有多个项目共享相同的 X 和 Y 坐标时,顶部的项目将是沿 Z 轴最靠近相机的项目,而不是被选择的项目。

如果这一切听起来有点混乱,不要担心——一旦你看到它是如何工作的,就明白了(这适用于所有的窗口)。

服务

通常位于场景视图右侧的是服务选项卡,它与检查器共享一个窗口。这包括诸如盈利广告、了解玩家如何享受游戏的分析、多人游戏等等。请注意,如果您有免费版本,这些功能中的一些将会丢失或受到限制。

现在,您可以完全忽略这个窗口。这些服务将主要在更雄心勃勃的项目中生效,并且只有在这些应用在 Play Store 中上线后才会生效。

检查员

接下来是经常与服务共享窗口的选项卡:检查器(图 3-3 )。检查器是你用来查看和编辑游戏对象细节的工具。因此,当你在场景视图中选择一个游戏对象,比如精灵,你就可以使用检查器来查看对象的名称、尺寸、可能附加的脚本等等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-3。

Inspector and Services

你会经常用到这个检查器,所以把它放在你能看到的地方。但是现在,它将会是完全空白的。

项目

通常位于屏幕底部的是项目和控制台标签的窗口(有时游戏也会在这里)。默认情况下,项目选项卡应该是打开的,在这里您可以看到与您的项目相关联的所有单个文件。窗口左侧是您可以选择文件夹的目录,右侧是该文件夹的内容。现在,您的项目只有一个名为 Assets 的文件夹。文件夹里什么都没有。

当你工作时,这将是一个有用的窗口,因为它允许你找到你用其他软件创建的精灵,并重命名或删除你游戏中需要的文件。

安慰

项目选项卡旁边是控制台选项卡(图 3-4 )。在这里,您可以获得有关 Unity 和您的应用状态的信息。您将能够看到调试信息、崩溃报告和错误,这可以帮助您识别代码中的问题或找出游戏无法运行或编译的原因。这将派上用场,但我们暂时不需要担心它,所以现在让 Project 在它前面可见。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-4。

The Hierarchy and Console

等级制度

最后,UI 中最重要的元素之一是层级(如图 3-4 所示),它几乎总是位于场景视图的左侧。层级显示了在任何给定时间场景中所有游戏对象的列表,当你选择其中一个时,场景视图将集中在它上面;它也将在检查器中打开。这可以让你快速找到特定的游戏对象进行编辑,这也是你选择像检查点这样的“不可见”对象的唯一方法。当您想要选择多个对象(例如,可能是您的所有收藏品)时,层次结构也非常方便,并且具有用于快速检索特定项目的有用搜索工具。

保持一个整洁的层次结构是一个很好的实践,它将帮助你更快更有效地工作。

家政

在大多数情况下,我建议您保留窗口的默认配置。它们被这样安排是有原因的(它是有效的),这将使你更容易按照书中的指示去做。控制台或其他窗口可能不在同一个地方,但我们现在主要使用场景、游戏、项目和检查器窗口。其他的不用担心。

但是如果你发现用户界面感觉狭窄,或者你不喜欢它在任何一点的排列方式,你可以将鼠标指针悬停在任何分割线上来改变相对大小。您也可以将标签从一个窗口拖到另一个窗口,完全关闭它们,或者使用窗口菜单中的选项将它们带回来。你可能已经注意到,在窗口菜单中还有其他可以打开的窗口,包括混音器、动画器和精灵打包器。其中一些我们以后会用到,但是现在你不需要担心它们;您应该能够使用层次、场景、项目、游戏、素材存储、控制台和检查器窗口做几乎所有的事情。

接触物品和场景

理论到此为止——是时候付诸实践了。要真正理解这些窗口是如何工作的,以及你需要做些什么来开始,最好的办法是开始构建一些东西。一旦你这样做了,你将直接看到所有的东西是如何一起工作的,以及一旦你开始开发,你将如何管理你的工作流程。

添加精灵

为了开始,让我们从添加我们的第一个游戏对象开始。这将是一个简单的 2D 广场。

与处理 3D 对象不同,在 2D 中没有简单的形状可供您插入。这意味着你引入的任何 2D 物体必须首先被创建为精灵。创建一个正方形非常简单:我们可以创建一个新的 MSPaint 文件,将其大小调整为 50 x 50 像素,然后用一种颜色填充空间。将该文件保存为 PNG 文件,并将其从保存位置拖动到项目文件夹中。为简单起见,称它为正方形。图 3-5 可以看到我的正方形。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-5。

Square. Not quite triple-A graphics.

为了帮助我们尽早养成良好的习惯,我们将首先在项目中专门为精灵创建一个文件夹。本着好习惯和好命名的精神,我们将把这个文件夹称为精灵。为此,右键单击项目窗口中的素材文件夹,然后创建➤文件夹(图 3-6 )并将文件夹命名为精灵。一旦你完成,它应该看起来像图 3-7 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-7。

Your Sprites folder should look like this. It’s a folder. Called sprites.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-6。

Creating new folders is very simple

随着我们的进行,我们将为我们的脚本、声音、场景等创建更多的文件夹——创建大量文件夹来帮助将所有东西分开是明智的,这样我们可以在任何给定时间快速检索我们需要的文件类型。

一旦你创建了这个文件夹,你可以简单的把 square.png 文件从 Windows 资源管理器拖到你的 Sprites 文件夹中。请注意,在任何时候,您都可以右键单击项目窗口并选择 Show in Explorer。这将向您显示项目中的素材目录,并且一旦您刷新视图,您在此处输入的任何内容都将显示在项目窗口中。

这样,精灵现在是你的项目的一部分。你可以使用完全相同的过程,无论你想添加树精灵,收藏品,敌人,或其他任何东西到你的水平。真的就这么简单。

引入游戏对象的两种方式

有两种方法可以将这个简单的游戏对象添加到场景中,我们将在这里介绍这两种方法,因为我觉得这是一个很好的学习机会。

最简单的方法就是在你的项目窗口中点击精灵,然后把它直接拖到你的场景中。然后你会看到它出现在你的场景视图中,并且在你的右边的层次中列出(图 3-8 )。如果选择了它,有关方块的详细信息也会显示在您的检查器窗口中。点击你的游戏视图,你会看到背景中有不同蓝色阴影的方块。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-8。

The scene, now with the square

另一种给你的场景添加精灵的方法是打开顶部菜单,然后点击游戏对象➤ 2D 对象➤精灵(图 3-9 )。当你这样做的时候,一个新的精灵将会出现在你的层次窗口中,但是你将不能在场景视图中看到它,因为它当前没有一个相关的图像文件。然而,每当它被选中时,它的坐标周围会有一个半透明的圆圈。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-9。

The second way to insert your sprite

在层次中选择新的 Sprite 后,打开检查器窗口,注意名为 Sprite Rendered 的部分。在这里,第一行写着“Sprite: None (Sprite)”您可以简单地将您的方形文件拖放到此处,或者您可以单击框旁边的小圆形按钮,从文件选择器对话框中选择它(图 3-10 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-10。

Using the Sprite Renderer

当你在检查器中的时候,为什么不借此机会把你的第二个精灵(现在是新精灵)的名字改成更有趣的名字…比如 Square 2。

尝试这两种方法,你会在场景窗口的屏幕上有两个不同的精灵:方块 1 和方块 2。它看起来应该如图 3-11 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-11。

If it looks something like this, you’re doing well

操纵游戏对象

正如你可能已经猜到的,你可以很容易地在场景视图中移动你的新精灵,只需点击它们并在屏幕上拖动它们。执行此操作时,您会注意到检查器中的坐标发生了变化。在变换下,位置的 X 和 Y 值随着你移动方块而改变,正如我在图 3-12 中所做的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-12。

Change the X and Y coordinates in the Inspector to move your sprites

这意味着您可以通过在检查器中输入数字来轻松更改位置。如果你需要完美地排列东西或者把它们放在一个非常特殊的位置(你会经常做的事情),这将会很方便。我们稍后会看到,虽然也有更有效的方法来确保一切都保持良好的排列,并在我们工作时捕捉到网格。

“那 Z 呢?”我听到你问了!嗯,在制作 2D 游戏时,Z 轴在很大程度上是多余的,尽管不是完全多余。我们将在后面看到,你可以使用这个选项来创建一个视差滚动效果,并且当有多个精灵位于同一个位置时,它也可以用于定义应该渲染哪个精灵给玩家看。这也可以通过改变 Z 顺序来控制,我们稍后也会看到。

旋转和缩放

您可能已经注意到,在检查器的“变换”下还有两个更有趣的选项:旋转和缩放。他们几乎做他们所说的,并允许你改变你的精灵的旋转和大小。我们现在将忽略旋转,因为我们暂时不需要它。但是你会发现,如果你把 X 和 Y 的缩放比例从 1 改为 2,你的精灵尺寸会翻倍。

在场景视图中操纵游戏对象

如果您想徒手完成此操作,您可以选择使用屏幕顶部的工具,就在层次窗口上方的左侧。这些工具包括一只手和做不同事情的各种箭头,如图 3-13 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-13。

The tools you’ll be using in the Scene view

这些工具改变了您与场景视图的交互方式。您只需单击想要缩进的工具并选择它:

  • 最左边的那只手可以让你拖动屏幕,移动你的视图,这对于滚动一个大的级别很有用。

  • The tool that looks like four arrows on a compass is what you use to move specific GameObjects around the screen (see Figure 3-14). You can simply click the GameObject and start moving it around freely in the Scene view, or you can select it and then drag either the red or green arrow to move it solely in the X or Y axis respectively.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 3-14。

    The drag tool

  • 两个弯曲的箭头表示旋转工具。选择此选项,一个圆圈将出现在所选的游戏对象周围,这将允许您在两个维度上旋转它。

  • 然后你有缩放工具,它再次给你两个箭头,你可以用它来沿着每个轴缩放对象。

  • 最后一个工具是你的万能工具。它可以让你拖动游戏对象,通过拖动角来调整它们的大小,或者画正方形来一次选择多个对象。

无论是使用工具徒手移动对象,还是在检查器中更改数字,您都可以按照自己喜欢的方式排列精灵,并创建一些好看的风景。

但是我们不要想得太多…

测试游戏和使用相机

如果 UI 中有一个控件很可能吸引了你的眼球,那就是播放按钮。好消息是,这正是你所希望的:它允许你测试游戏。

点击播放按钮,你的游戏将在游戏窗口中运行,显示两个位于浅蓝色背景上的方块。它可能不会风靡全球,但恭喜你,你刚刚运行了你的第一个工作程序(图 3-15 )!这是我们的“Hello World”,从这里开始,事情只会变得更加有趣。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-15。

Your first “game”—congrats!

当游戏正在进行时,你可以在游戏视图中查看它(图 3-15 ),并且你可以通过检查器或在场景窗口中继续进行编辑。只要记住,当你这样做的时候,什么也救不了。如果你在游戏运行的时候移动精灵,当你再次停止它的时候,它会跳回到它最后的位置。使用它可以“实时”预览更改,但不能对代码进行永久性修改。试着现在就把这个记在你的脑子里。搬了一堆东西,改了一堆代码,却发现忘了先停止游戏运行,全输了,这种情况并不少见。

要随时停止游戏,只需再次点击播放按钮。请注意,如果您希望游戏在您点击播放时全屏显示,您可以点击播放时最大化。当你正确地测试你的游戏,或者你只是想好好玩一玩的时候,这是很有用的。图 3-16 是我们的游戏目前放大后的样子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-16。

The same game, only massive

照相机

细心的读者可能已经注意到在层次视图中有不止两个游戏对象。第三个对象叫做主相机,如果你选择它,你会看到这个白色的相机图标在你的场景视图中浮动。

主相机是一个游戏对象,就像你的精灵一样,但是有一个相机组件而不是精灵。当你在一个场景中添加一个这样的东西时,它定义了玩家的视角在哪里,以及他们将在屏幕上看到什么。试着四处移动相机,然后点击播放,你会发现屏幕上方块出现的位置发生了变化——方块没有移动,但你的视角发生了变化。

你的相机被当作精灵一样对待,这可能会让人觉得奇怪,但这是你需要了解的关于 Unity 的事情:一切都是游戏对象。除非附加到游戏对象上,否则脚本不会运行,如果你习惯了其他语言,这可能需要你重新考虑你的代码。但是一旦你掌握了它,它就是一种强大而灵活的工作方式。

附注:这不是面向对象编程的含义。这是相关的…但是我会在接下来的章节中解释更多。

既然我们在看摄像机,让我们编辑一些你可能会觉得沮丧的东西:你的游戏视图的背景颜色。点按相机,您会在检查器中看到一个名为背景的设置,当前为蓝色。如果您选择颜色,您将有机会将其设置为新的颜色。选择黑色——这样你的蓝色方块会更加醒目。

保存项目和场景

鉴于你可能对这个惊人的创造感到难以置信的高兴,是时候去拯救它了,以确保不会有什么不好的事情发生。

这里其实需要保存两个东西:项目和场景。场景就是你通过场景窗口看到的东西,它包含了你现在层次中的所有东西(两个方块和一个摄像机)。对于所有范围和目的,场景在大多数情况下是一个级别,尽管它也可以指标题屏幕或选项菜单。它本质上是你想在游戏中的某个时刻载入的游戏对象和脚本的集合。

要保存您的项目,请使用顶部的菜单并选择文件➤保存项目。

要保存场景,首先需要在“资源”文件夹中创建一个新的子文件夹,将其命名为 Scenes。现在转到文件➤保存场景(图 3-17 )。当对话框出现时,选择刚刚创建的场景文件夹,并将文件命名为 Level 1。当您的项目中有多个场景时,您只需在场景文件夹中双击它们,就可以在它们之间切换。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-17。

Saving our scene

更有条理一点

因为我们是如此的有条理,并且很早就养成了好习惯,所以在我们继续之前,让我们再做一个文件夹。右键单击层次中的任何空白区域,然后单击创建空白区域。这将创建一个“空”的游戏对象,称为游戏对象。它应该已经被选中了,所以到层次结构,并重新命名为广场。理论上,你可以通过点击添加组件,然后选择相机组件或精灵渲染器,将这个空的游戏对象转换成任何其他类型的游戏对象。相反,我们保持它为空,这将允许我们附加其他游戏对象到它,从而使用它作为一个临时的分组(图 3-18 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-18。

Start organizing your Hierarchy now and you’ll be very glad you did

将你的两个方块从它们所在的地方拖到你的空游戏对象上,它们现在会被归档到它下面。空游戏对象旁边的箭头现在也允许你展开和折叠这些项目。这不是真的有必要在这一点上,但相信我,当你有 200 个可收集的硬币,30 个敌人,和 700 个瓷砖在你的屏幕上,你会为这个组织感到高兴。

最后一件要设置的事情:捕捉网格设置

在第四章中,事情将会变得令人兴奋:我们将会在我们的方块中加入物理元素,这样它们就可以落下和反弹,这仅仅是个开始。但是,在我们这样做之前,我们应该处理更多的设置,并解释更多的 UI。

你可能已经注意到在你的场景视图中有一个网格,并想知道这是怎么回事。这个网格是由单元组成的,为了帮助你在屏幕上组织你的精灵,它们可以代表你想要的任何东西。你把一个充满单元的程序叫做什么?Unity!(好吧,这并不是这个名字的真正来源…)

现在,你会注意到你的正方形和单位没有关系。要改变这种情况,首先将两个方块上的比例 X 和比例 Y 设置回 1。现在打开你的精灵文件夹,选择正方形精灵,这样它会在你的检查器中打开(不要只是点击一个正方形的游戏对象,因为那不起作用)。

您应该注意到每单位像素的一个选项,默认情况下可能设置为 100。将该值更改为 50——不要忘记单击右下角的“应用”——您应该会发现两个方块现在立即变为与网格上的方块相同的大小(如图 3-19 )。记住,当我们制作这些精灵时,我们把它们制作成 50 x 50 像素。通过这样做,1 个单位= 50 个像素,我们现在有了完美大小的正方形。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-19。

Make sure to set your pixels per unit for every new sprite

另一个有用的技巧是让精灵就位。拖动精灵时,按住 Ctrl,你会发现它从一点跳到另一点,而不是平滑移动。您可以通过选择编辑➤捕捉设置来更改这些点之间的距离。你会发现,对于 X 轴和 Y 轴,这可能分别被设置为 1。如果不是,则进行更改(参见图 3-20 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-20。

Snap settings

关闭该对话框,自由移动其中一个方块,使其正好位于其中一个方格的边界内。现在按 Ctrl + C(复制),然后按 Ctrl + V(粘贴)。这将复制你的正方形游戏对象,在完全相同的地方创建一个完全相同的副本。按住 Ctrl 并向右拖动正方形。它应该恰好移动一个方块的宽度,与前一个方块齐平。你也可以通过右击并从层次视图中选择复制来复制和粘贴游戏对象。这样做几次,你就可以创建楼梯和其他结构。

在这一点上,这可能感觉很无趣,但实际上这是一项非常重要的技能。在游戏中创建关卡时,非常重要的一点是,所有的方块都要完美地相邻放置,并且它们之间不能有像素宽的缝隙。

为什么不试着用一个稍微复杂一点的精灵来制作一些看起来像关卡基础的东西呢?我在图 3-21 中做了一些草台阶。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-21。

We’ll learn how to create sprites and even pixel art in future chapters

嘿,你看那个…我们有进展了。

现在让我们让这个世界充满活力,好吗?

四、添加物理学并开始编程

在这一点上,你现在有了一个看起来有点像传统电脑游戏关卡的世界。在这一章中,我们将通过添加一些基本的物理和运动来让它像传统的电脑游戏一样玩。为此,你将第一次尝试编码。祝你好运!

因此,我们有平铺的精灵,它们有草的图案,为了混合一些东西,我还创建了一个精灵来代表草下面的地面,这样我就可以用我的关卡设计来增加一点创造性(见图 4-1 和 4-2 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-2。

Some tiles just ready to be climbed on!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-1。

The second ground tile

我用和第一个完全一样的方法创建了第二个污垢精灵,然后在我的草地表面下任何我需要的地方复制它。您也可以这样做,只需记住按住 Ctrl 键,使用“捕捉到网格”功能来保持完美的距离。

现在我们要做一些更令人兴奋的事情:创造一个游戏角色,把他放到我们的世界里。首先,我们要做一个尽可能简单的角色精灵,这是另一个正方形。为了让事情变得更有趣,我们还会给他眼睛。

见方(图 4-3 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-3。

Squarey, mate, you don’t look so good

Squarey 可以是你喜欢的任何尺寸,但为了简单起见,我建议保持与地面瓷砖相同的尺寸。

现在将 Squarey 添加到你的精灵文件夹中,就像你对其他的一样。确保你记得再次设置每单位像素为 50,然后把他拖到你的场景中。将这个新的游戏对象命名为 Player,并将其与 Squares 文件夹分开。你想把他拖到关卡的哪个位置并不重要,但我选择把他放在我创建的山顶(图 4-4 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-4。

Squarey surveys his domain

恭喜你!你现在有一个主角了。问题是,他实际上什么也没做。

所以,接下来我们要做的是应用一些物理知识,让重力和其他东西影响我们的性格。你不会相信 Unity 让这一切变得多么容易。

使用刚体 2D

如前所述,使用 Unity 这样的物理引擎的全部意义在于,我们可以访问现成的脚本和元素,避免自己从头开始编写代码。这使得添加类似重力的东西变得非常简单:我们所要做的就是把一个脚本拖到我们的游戏对象上,让它生效。

选择播放器后,点按检查器中的“添加组件”。现在点击物理二维➤刚体二维。刚体 2D 是一个脚本的名字,它作用于 2D 精灵,并应用了我们想要的所有基本物理,如重力、摩擦力、动量、碰撞等等。

然而,最简单的方法就是把它付诸行动。所以在场景窗口中拖动 Squarey 稍微高一点,然后点击 play。如果一切都按计划进行,我们现在有一个看起来很悲伤的正方形,他只是从屏幕的顶部和底部掉了下来。Squarey,来见见地心引力!

使用对撞机

精明的人会注意到这里缺少了什么。当然,我们实际上并不希望 Squarey 从他下面的地面掉下去;我们想让他着陆。幸运的是,这也是一个简单的解决方法。

只需再次点击 Squarey,然后添加组件➤物理 2D ➤盒碰撞器。你现在应该可以在检查器中看到刚体 2D 和 2D。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-5。

The green outline shows Squarey’s collider

此外,您还应该注意到 Squarey 周围有一条细细的绿色轮廓。这是碰撞器,它本质上定义了你的精灵的边界,并告诉刚体 2D 组成角色的物质开始和停止的位置。

点击播放,你会看到角色仍然从下面的地面掉下来。希望你已经猜到了,这是因为我们的贴图也需要附加碰撞器。为此,使用鼠标在场景视图中拖动一个方块,以便一次选择所有图块。你可以选择桌面上的一堆图标(图 4-6 ),或者在按住 Shift 键的同时点击层级中的第一个项目,然后点击最后一个项目。您也可以使用 Ctrl 进行批量选择,就像在大多数 Windows 程序中一样。这是一个经常会派上用场的技巧,尽管还有另一种方法来进行大规模更改,我们很快就会看到。确保取消选择相机,然后在检查器中添加一个碰撞器。这将会同时应用到所有选中的游戏对象上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-6。

Later we will discuss using prefabs to avoid having to select multiple GameObjects

请注意,我们没有将刚体 2D 添加到地面瓷砖中。那是因为我们不想让它们从屏幕上掉下来。

现在点击 play,如果一切按计划进行,我们的角色将会摔倒并落在地上(图 4-7 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-7。

Success!

如果你想测试刚体 2D 有多详细,把它放在正方形的位置,让它部分悬在一个台阶的边缘,然后再次点击播放。当他落地的时候,他应该给小费,然后滚下楼梯。

在这一点上,我们现在已经有了一个按照我们期望的方式运行的游戏。下一步可能是让它具有交互性。准备好:这是实际编码的地方。

C#编程入门

在您开始编码之前,我们首先需要创建一个文件夹来包含 Assets 目录中的所有脚本。在项目视图中右键单击并选择创建➤文件夹,就像创建精灵和场景文件夹一样。调用这个新文件夹脚本,然后打开它。

在这里,您将再次右键单击,这次选择“创建➤ C#脚本”。呼叫此玩家,然后双击打开它。现在,您将第一次打开 Visual Studio。但首先,你需要登录。为此,您只需使用您的 Microsoft 帐户(您可能会使用该帐户登录 Windows 和 Hotmail)。如果您没有,您将有机会创建一个。

一旦你进入,用户界面看起来应该如图 4-8 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-8。

Welcome to Visual Studio

现在,我们将注意力集中在中间的大窗口上,在这里我们可以输入和编辑代码。我们在这里选择用 C#编码,因为它有点类似于 Java——大多数 Android 开发中使用的语言——只是稍微简单一点。用 C#编写代码时要记住的一件事是,每一行都需要以分号或开/闭花括号结束。如果你错过了这个,你会得到一个错误。你可能会发现很容易忽略这个关键的细节,然后花很长时间在你的代码中寻找为什么它不能运行。

您可能还会注意到,文档实际上不是空的,而是已经包含了几行代码。这些是函数,是在特定时间被调用的独立的代码集合。我们这里的两个函数将会出现在我们创建的每个脚本中,并为我们将要做的事情提供一点结构。

整个过程应该如下所示:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {

        // Use this for initialization
        void Start () {
        }

        // Update is called once per frame
        void Update () {
        }
}

先不要担心前两行。第三行显示的public class实际上只是命名我们创建的脚本,接下来的两个部分(void Startvoid Update)是我们的函数。

另外两件要注意的事情是正斜杠。在 C#中,每当一行以两个正斜杠开始时,这意味着它是一个注释,不会对代码的运行方式产生任何影响。换句话说,如果你忘记了一行代码是做什么的,你就可以这样给自己写消息。当程序员团队一起工作时,像这样的注释对于确保每个成员都知道每件事是做什么的非常重要。

这里已经有两个注释描述了这些函数的功能。第一个写的是"Use this for initialization",所以每当脚本第一次被引入场景时void Start就会运行。第二条评论说"Update is called once per frame",所以void Update随着游戏刷新以非常快的速度反复运行。

为了证明这一点,让我们试着让我们的角色在屏幕上移动。为此,我们首先需要引用一些我们将在代码中使用的重要元素。在这种情况下,我们需要使用附加在我们的Player游戏对象上的刚体 2D 脚本。为此,我们需要添加以下代码:

public class Controls : MonoBehaviour {
    public Rigidbody2D rb;

    void Start () {
        rb = GetComponent<Rigidbody2D>();
    }

这里发生的事情是,我们正在创建一个刚体 2D 的参考,并将其命名为rb(刚体的缩写)。然后,当脚本初始化时,我们告诉它刚体 2D 的实例是我们的脚本附加到的游戏对象(一会儿,我们将把它附加到Player游戏对象)。

不要担心这是不是有点混乱:你现在可以复制和粘贴代码,以后会更有意义。

最后,我们将向我们的Update函数添加以下代码行:

void Update () {
            rb.velocity = new Vector2(1, rb.velocity.y);
        }

这只是将一个值为 1 的 veleocity 加到刚体的水平 X 坐标上(Vector是一个坐标)。因为这是在Update中,这意味着它应该在每次场景刷新时运行——这发生得非常快。整个过程应该如下所示:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {
    public Rigidbody2D rb;

    // Use this for initialization
    void Start () {
        rb = GetComponent<Rigidbody2D>();
        }

        // Update is called once per frame
        void Update () {
            rb.velocity = new Vector2(1, rb.velocity.y);
    }
}

请确保您记得保存您的工作!

现在剩下要做的就是回到 Unity,给玩家角色添加剧本。我们做的和我们添加刚体 2D 一样:选择Player游戏对象,点击添加组件,然后编写➤玩家的脚本。现在点击播放,你应该会发现 Squarey 继续向右移动,然后从台阶上摔下来,走向他的最终厄运(图 4-9 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-9。

Squarey now has Lemming AI

只有当你把脚本附加到你的游戏对象上时,它才会有任何效果,你也可以很容易地把它添加到地面瓷砖上来获得同样的效果。

引入变量

现在是我们玩一些变量的时候了。变量是编码中一个非常重要的概念,也是很多逻辑和通用性的来源。

本质上,变量是一段数据的简写,可用于在未来表示该数据(如健康或球员姓名)。机会是,如果你能回想在学校时的数学,你会发现你在过去遇到过变量。还记得这样的谜题吗?

10 + x = 13,求 x

在这种情况下,x 是一个恰好代表 3 的变量。但是如果我们这样写

10 + x =?

这将允许我们改变结果,简单地用一个键或类似的东西改变 x 的值。在 C#中处理变量时,我们可以做完全相同的事情。例如,我们可以用一个名为movespeed的变量代替 1 来改变角色移动的速度。但是首先,我们需要通过初始化来定义movespeed的含义。所以现在我们的代码看起来像这样:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {
    public Rigidbody2D rb;
    public int movespeed;

    // Use this for initialization
    void Start () {
        rb = GetComponent<Rigidbody2D>();
        movespeed = 2;
    }

        // Update is called once per frame
        void Update () {
        rb.velocity = new Vector2(movespeed, rb.velocity.y);
    }
}

Squarey 将会像以前一样移动,但是这次是以两倍的速度。

当我们创建变量时,我使用了一些有助于理解的术语。例如Int,是 integer 的简称,是一种存储整数的变量。每当你定义一个变量的时候,你总是需要告诉 C#你正在处理什么类型的变量。在这一点上,需要知道一些有用的信息:

  • 整数:任何整数
  • Float:浮点变量是一个带小数点的数字
  • 布尔型:一个变量,可以是真或假,也可以是 1 或 0
  • 字符串:文本变量

同时,public意味着可以从脚本外部访问该变量。事实上,这意味着我们甚至可以从 Unity UI 中编辑我们的movespeed

为此,删除显示movespeed = 2的行,然后在 Unity 中选择Player游戏对象。你应该看到现在在检查器中有一个移动速度框,如图 4-10 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-10。

Changing Movespeed in the Inspector

尝试将该值设置为–1,您会看到 Squarey 现在向相反的方向移动,远离楼梯并朝向突然下降的方向。如果不从脚本中删除movespeed = 2行,每次调用Start函数时,它都会被覆盖。如果你不想让变量在你的代码之外被访问,那么就简单的用private代替public

现在,让我们把movespeed设为 3,因为我们想让 Squarey 在下一位快一点。虽然你可以不使用变量来做同样的事情,但是知道这些是非常有用的,当你在场景中添加更多的元素时,你会发现它会反复派上用场。

控制玩家角色

看到我们的角色在关卡中移动并与场景互动是非常令人兴奋的,但实际上我们希望能够控制角色。好消息是,这是我们可以很容易做到的事情,只需稍微改变我们已经拥有的代码。我们需要做的就是添加几个if语句,如下面的代码所示:

void Update () {
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.velocity = new Vector2(-movespeed, rb.velocity.y);

        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.velocity = new Vector2(movespeed, rb.velocity.y);

        }
}

这里发生的事情是,每当游戏更新时,脚本检查是否有输入。当然,KeyCode.LeftArrowKeyCode.RightArrow指的是各自的键盘输入,然后我们通过movespeed–movespeed来移动字符,这取决于哪一个被按下。"If"语句本质上是告诉一段代码只有在特定参数为真时才运行。只有当括号内的行为真时,花括号内的代码才会运行。

如果我们用伪代码(使用普通英语术语的假“代码”更容易理解)来写,那么它将翻译如下:

If (Player is pressing right) {

Move character to the right

}

记住在if语句的末尾关闭花括号是很重要的。如果你有使用 Excel 或其他电子表格软件的经验,使用像这样的if语句可能会很熟悉。

Note

如果你现在要创建一个 APK(Android 的应用包——稍后会详细介绍)并在 Android 上运行,它实际上可以和蓝牙键盘一起工作。稍后,我们将看看如何实现触摸屏控件。

如果你点击“现在玩”,你应该有令人兴奋的机会实际尝试控制 Squarey——就像一个真正的游戏。虽然我们不得不在这里写一点代码,希望你同意这是非常简单的事情:只需几行代码,我们现在就有了一个好看的游戏世界和一个我们可以控制的角色。

更高级的逻辑和引入跳跃

Squarey 现在可以像专业人士一样左右移动,并且非常擅长从物体上跳下来。你应该感到自豪。但是为了能和马里奥、索尼克以及他们中的佼佼者同台竞技,他还需要学习一些跳跃技巧。不幸的是,这比左右移动要复杂一点。

你可以尝试实现跳跃,就像你处理左右移动一样。下面的代码将允许我们的英雄跳跃:

if (Input.GetKey(KeyCode.Space))
        {
            rb.velocity = new Vector2(rb.velocity.x, 5);

        }

唯一的问题是这个代码也能让他飞起来。这是因为我们每次按空格键都会增加更多向上的速度,不管他是在地上还是在空中。这不好。

所以我们需要先确认他是否在陆地上。这就有点复杂了。

首先,我们需要创建一个新的转换。变换是空间中有自己的坐标和旋转(角度)的点。这个点也将有一个半径(这将是一个浮动),我们还需要一个图层蒙版。我们现在还创建了第一个布尔变量onGround

简而言之,您正在将以下所有代码添加到脚本中:

public Transform groundCheck;

public float groundCheckRadius;

public LayerMask whatIsGround;

private bool onGround;

现在,这可能看起来相当复杂,但不要担心,我会解释每一位是什么,以及我们进行的过程中它做了什么。

如果在这个阶段这还不够令人畏惧,我们还将在代码中添加另一个函数,名为FixedUpdateFixedUpdate是一个类似于Update的功能,除了Update依赖于屏幕的刷新率,FixedUpdate更加一致,因此对于与物理相关的代码更加可靠。

在这个函数中,您将添加以下内容:

void FixedUpdate()
{
    onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
}

现在还不要担心这是什么。回到 Unity,你现在可以看到我们在检查器中创建的新的公共浮动、布尔和图层蒙版。

在这里,您将创建一个新的空游戏对象。这是一个游戏对象,就像一个精灵或相机,但没有组件。在层次中右键单击并选择创建空。你将调用这个空的游戏对象Check Ground,并使它成为Player的子对象(通过在层次结构中将它拖到Player的顶部——参见图 4-11 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-11。

Check Ground is an empty GameObject and child of Player (more on what that means later)

现在再次选择玩家,在层级中找到写着地面检查的地方。目前它会显示 None (Transform ),但是你可以通过拖动Check Ground游戏对象并把它放到那个盒子里来改变它。它看起来应该如图 4-12 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-12。

Ground Check is a transform that is now defined as the coordinates of Check Ground

记住:地面检查是一个变换,意味着一组坐标。通过将一个空的游戏对象放入这里,我们现在告诉我们的脚本将这些坐标设置为那些附属于Check Ground的坐标。换句话说,我们已经定义了一个“点”,这就是我们将如何看待 Squarey 是否站在坚实的地面上。现在将半径值设置为 0.1,这意味着它将是一个非常小的点。最后,在场景视图中选择Check Ground并使用移动工具将其定位在 Squarey 的正下方,这样它就可以检查他正下方的空间。

还有一件事,我们需要做的是创建一个新的层,并将其命名为地面。再次拖动并选择所有的地砖,然后在检查器的左上方寻找图层菜单。在下拉列表的底部,你会看到添加图层的选项(图 4-13 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-13。

Adding the Ground layer

然后,您将有机会创建您的新层,只需在下一个可用空间键入其名称(unity 已经定义了几个层),如图 4-14 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-14。

Call the new layer Ground

在空白处键入 Ground。然后回到你的方块检查器,这一次从下拉菜单中选择地面,将它们全部设置为那个值。

现在再次查看检查器中的Player游戏对象,这一次使用下拉菜单设置什么是地面到地面。这基本上意味着,在我们的脚本中,设置为地面层的任何东西现在都将被视为地面——这意味着 Squarey 可以从它上面跳下来。

完成所有这些后,我们现在可以简单地将最后一行代码添加到我们的脚本中:

if (Input.GetKey(KeyCode.Space) && onGround)
        {
            rb.velocity = new Vector2(rb.velocity.x, 5);
        }

现在点击播放,你会发现 Squarey 可以跳,但只有当他在坚实的地面上。这意味着他不能在空中连续跳跃,也意味着在第五章我们可以开始引入一些真正的平台挑战。

进一步解释一下

你可能仍然对这里实际发生的事情有些困惑。让我们回顾一下正在发生的事情。

关键是我们放在FixedUpdate函数中的这行代码:

onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);

语句Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround)为真或假,询问groundCheck变换是否与我们定义为地(whatIsGround)的任何东西重叠。onGround如果有重叠则为真,如果没有重叠则为假——请记住,这是一个只能为真或假的变量。因为这条线在FixedUpdate中,它的值会随着游戏的进行而不断变化。

在伪代码中,我们这样说:

If the circle underneath the player is overlapping with ground material, then onGround is true. Otherwise, onGround is false.

然后,在我们的Update函数中,每当玩家按下空格键时,我们检查onGround是否为真:在 C#中,&&简单地表示 and。通过在if语句中使用&&,我们测试两个参数是否为真。因此

if (Input.GetKey(KeyCode.Space) && onGround)
{
    rb.velocity = new Vector2(rb.velocity.x, 5);
}

实际上意味着

If player presses jump and 'onGround' is true then add upward velocity.

我们也可以用一个变量代替 5,就像我们对movespeed所做的那样。称之为jumppower

为了方便起见,整个播放器脚本现在应该是这样的:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {
    public Rigidbody2D rb;
    public int movespeed;
    public int jumppower;
    public Transform groundCheck;
    public float groundCheckRadius;
    public LayerMask whatIsGround;
    private bool onGround;

    void Start () {
        rb = GetComponent<Rigidbody2D>();
        movespeed = 3;
        jumppower = 5;
    }

    void FixedUpdate()
    {
        onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
    }

    void Update () {
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.velocity = new Vector2(-movespeed, rb.velocity.y);

        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.velocity = new Vector2(movespeed, rb.velocity.y);

        }

        if (Input.GetKey(KeyCode.Space) && onGround)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumppower);

        }

    }
}

如果你现在复制它,你可以在尝试理解它的时候尝试修改线条和逆向工程。您应该会发现,其中很多内容实际上是不言自明的。

最后一点:让玩家保持直立

除了有一个小问题:Squarey 目前在楼梯上翻滚旋转,好像他喝了太多的伏特加。如果你跳起来,然后头着地,你将无法再次起飞,因为Check Ground游戏对象现在将指向空中。

要解决这个问题,单击 Squarey 并在检查器中找到刚体组件下的约束选项。在这里,您会发现冻结旋转 z 的选项。勾选该框,Squarey 的角度将被锁定(图 4-15 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-15。

Tick Freeze Rotation and your character will stop falling over

你会注意到这里还有一些其他选项,比如重力比例(控制 Squarey 受重力影响的程度)和其他一些选项。我们将在第五章中讨论这些。

现在你可以试着创建几个浮动平台,并尝试在不从屏幕上掉下来的情况下穿过它们。你可能需要稍微调整一下你的jumppower或者你的重力等级,所以尽情享受吧。现在花一点时间来反思你已经取得的成就:只走了一小段路,你就已经有了一个可以在屏幕上跳跃的角色和一个导航起来非常有趣的关卡(图 4-16 )。我们才刚刚开始,所以想想在我们结束之前你还能做些什么吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-16。

Only Chapter 4 and our game is already almost fun!

在第五章中,我们将会看到如何用预设和影响者创建更好的平台,我们将会用我们的相机做一些更有趣的事情。我们甚至可以开始放入收藏品和危险物品。

五、用预置、效果器和收藏品填充世界

在这一点上,事情开始走到一起,感觉有点像一个实际的游戏。我们有一个非常基本的 2D 水平,我们有一个角色,我们可以用箭头键和空格键移动,我们有工作的物理。

但目前仍有一些事情没有做到,我们没有遵循所有的最佳实践。这个世界也相当空旷,没有任何收藏品,风景,甚至天空。

在这一章中,我们将会看到如何开始添加像树、硬币和有特殊属性的平台这样的东西。我们还将看到如何更好地跟踪所有这些新元素,并通过预置来简化我们的游戏设计过程。到最后,你的游戏世界将看起来更加丰富多彩,你甚至可以开始创建一些基本的平台挑战。

使用效应器

你可能已经注意到,目前不太正确的一点是,我们可以贴在墙上。如果我们把 Squarey 撞在墙上,并一直按住那个方向的箭头键,那么他会把自己粘在表面上,停止下落。对于平台游戏来说,这是非常奇怪的行为,所以让我们阻止它发生。

首先,点按您想要编辑的平台,然后在检查器中查看它。现在单击添加组件➤物理二维➤区域效应器二维。然后你会被提示你需要勾选 2D 碰撞器下的被效应器使用的框。

这将在框的周围显示一个半圆,并在检查器中显示更多的选项。你应该有类似图 5-1 的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-1。

Platform Effector added to one of our tiles

现在试着把这个角色粘在木块上,你会发现他只是滑了下来。简而言之,平台效应器使平台表现得像一个平台。

试着从下面跳进平台,你会注意到别的东西:Squarey 可以穿过它们。你可能以前玩过这个功能的平台游戏,但是现在我们想关闭它。这样做的原因是,截至目前,执行这一举措将打破游戏。当 Squarey 穿过地板时,按住 jump 会使他第二次跳跃,这看起来很奇怪。

有很多方法可以解决这个问题:例如,通过使用光线投射来检查地面,而不是我们目前使用的系统,或者简单地让玩家在再次跳跃之前再次点击空格键。不过现在,最简单的方法是取消单向使用框(图 5-2 ),这也将允许一些游戏特性,如洞穴和死胡同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-2。

Use One Way has now been unticked

这是一个非常早期的例子,说明你的游戏将如何决定你对物理和代码的决定。你不能建立一个游戏引擎并单独设计你的关卡:游戏世界的行为方式应该由你的游戏设计决定,反之亦然。形式应该服从功能。

在这种情况下,问题是你是否想要设计一个更快节奏的游戏,允许玩家通过点击跳转无缝地扩展平台,或者你是否想要一些更多的谜题/探索,并保持将它们困在不同部分的能力。

(当然,你也可以有多种类型的平台,以不同的方式运行,但你的游戏设计的挑战是要确保从游戏开始就清楚地传达这些差异。)

出于我们的目的,我们将保持事情简单,并关闭此功能。

更多效果器

效应器是一种快速简单地让游戏元素以特定方式运行的好方法。当您选择平台效应器时,您可能已经注意到还有一些其他效应器可供选择。

例如,您可能发现了浮力效应器。这是一个效应器,让我们可以让瓷砖像水一样。

为了演示效应器有多有用,让我们设计一些看起来像水的新瓷砖(图 5-3 ),保持我们相同的 50 x 50 尺寸。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-3。

A square of water

现在把它添加到你的精灵文件夹中,创建一个新的游戏资源叫做水广场(或者你想叫它什么都行)。记住将这个精灵的每单位像素设置为 50,并确保它有一个碰撞器。现在选择添加组件➤物理 2D ➤浮力效果器 2D。记住勾选“由效应器使用”,这次你也要点击“触发”(稍后我会解释这是什么意思)。复制并粘贴几个水方块,在它们的两边用堤岸围起来,创造一个水池。现在跳入水中,观察 Squarey 在水面下上下摆动(见图 5-4 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-4。

Squarey bobbing just below the surface of the water

其他效应器可以让您创建风、传送带等等。

预置和更多的组织

不,我没忘记。现在,我们有一个很有趣的水池,但是只有一个瓷砖能正常工作。

你可以改变场景中的每一个方块来应用平台效应器。实际上,考虑到我们可以一次选择多个游戏对象,并以那种方式添加内容或改变设置,这甚至不会那么糟糕。但是现在想象一下,你有多个关卡,大量不同的游戏对象,以及庞大复杂的布局。如果你现在决定要改变一个价值观,所有这些都会让你的生活变得极其艰难。

我们要做的是创建一个预置。Prefab 是预制的缩写,本质上是一个具有预定义属性的游戏对象。我们可以把预设放到场景中,就像我们把精灵放到场景中一样,但是它们会携带所有现成的组件和值。

更好的是,当我们更改文件夹中的效应器时,这些更改将反映在游戏中对象的每个实例上。这将让我们改变我们对游戏设计方面的想法,并能够迅速实施这些变化。

首先,在素材中创建一个新文件夹,并将其命名为 Prefabs。这是相同的过程,因为它是为精灵文件夹和脚本文件夹(右键单击➤创建➤文件夹)。现在找到你制作的包含效应器的地面瓷砖,并把它从检查器拖到预设文件夹中。然后用另一个地面瓷砖和其中一个水瓷砖做同样的事情(图 5-5 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-5。

Two prefabs down, one to go

现在到了可怕的部分——您将删除场景视图中的所有图块,除了玩家和相机之外什么都不留下。然而,所有的努力并没有白费,因为现在你将能够简单地将每块瓷砖拖放到你的游戏世界中。

这是一个很好的机会来创造一些更好的组织和重新设计我们的水平。在你再次开始放入瓷砖之前,首先选择预设并在检查器中查看它们。在这里,将名称更改为易于识别的名称。我走过了水、泥土和草地。这不会改变预置本身的名字,但是会改变游戏对象的名字。

你也可以借此机会创建单独的空游戏对象,作为你在旅途中拥有的三个元素的分组。我的是Top Soil草地、Ground泥土、Water水。

现在将每个单幅图块拖回到场景中,按住 Ctrl 键以捕捉到栅格。确保每个项目的第一个实例位于正确的组中,这样重复的项目也会出现在此处。首先将物品从预设文件夹中拖出,放入正确的类别中——然后你就可以简单地复制并粘贴场景视图中的元素了。在这里,你正在制作符合预设规则的副本。不要忘记按住 Ctrl 键来隔开你的图块,并使它们与网格对齐。现在你可以随意重新设计关卡布局了。图 5-6 可以看到我的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-6。

A new, more organized setup using prefabs

最后,再创建一个空的游戏对象,并将其命名为Tiles或类似的名称。

为了展示预设的力量,你现在可以试着在预设文件夹中选择草地并选择单向使用。点击播放,你会发现你现在可以从下面跳过任何一个草块。解开它,他们都会变回来。

这将使我们的工作流程变得更加简单,我们安排层级的方式也是如此。例如,试着点击水组,你会看到每一个水块都被高亮显示(图 5-7 )。点击瓷砖将会选中所有的水瓷砖、草瓷砖、土瓷砖(图 5-8 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-8。

All tiles selected

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-7。

Water selected

这意味着你可以很容易地删除整个类别的瓷砖,在未来,这将有助于我们管理的东西,如收藏品,敌人和装饰品。好时机——本章的下一部分将开始增加更多种类。

故障排除:帮助!Squarey 总是卡住!

软件工程的乐趣之一(是的,就是这个)是事情会不断出错,你会被迫尝试去处理它们。有时会有一个简单的解决办法(在这种情况下,谷歌是你的朋友)。其他时候,问题可能在你的控制之外,迫使你想出一个新的解决方案。

现在,如果你在你的瓷砖和你的玩家角色上使用箱式碰撞器,你可能会发现你偶尔会被不应该被卡住的东西卡住——你的角色可能会停止移动,并压在稀薄的空气中。这个问题通常发生在位置相近的瓷砖之间的顶点,不幸的是,这似乎是 Unity 本身的一个小问题,而不是您可以修复的任何问题(显然,它是在 4.3.1 中引入的,在撰写本文时尚未解决)。

如果你确实遇到了这个问题,就试着为 Squarey 自己使用一个多边形碰撞器,通过点击编辑碰撞器来稍微改变形状,然后在轮廓上创建一个小凸起,如图 5-9 所示,这样你就可以“滑过”这些想象中的障碍。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-9。

Editing the polygon collider

欢迎开发!

理解父母,做一个会动的相机

另一件有助于理解的事情是父母和孩子之间的关系。

层次结构中的这些分组实际上并不是文件夹。更确切地说,空的游戏对象被称为父对象,而你在它们下面的组被称为子对象。像真正的父母和孩子一样,在这种情况下,孩子将继承成人的属性。例如,如果您将Top Soil向右移动,那么它的所有子节点都将向右移动相同的距离,确保它们彼此保持相对距离。这在很多情况下都是一个有用的特性——例如,如果你想让两个游戏对象以相同的速度向相同的方向移动。

为什么这可能是你想做的事?好吧,我们用这个把摄像机贴在球员身上怎么样?现在,Squarey 只能在屏幕的范围内探索,这对于我们可以进行的关卡设计来说是相当有限的。但是如果我们进入层次结构并选择摄像机,我们可以将它放到Player上,从而使它成为游戏对象的子对象。现在,摄像机将始终相对于玩家移动!将它移动到播放器的中心,以确保它处于一个好的位置,可以从左右两边看到障碍物。为什么不在右侧增加一些水平来庆祝呢?

在图 5-10 中,你可以看到相机应该是什么样子,以及我添加的一些额外的关卡设计。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-10。

With his camera attached, Squarey is now free to explore foreign lands

请注意,这是一个非常快速的破解,而不是我们真正想要的处理相机的方式。在一个已经完成的游戏中,摄像机应该做的不仅仅是盲目地跟随玩家。相反,它会加速或减速,放大和缩小,并根据游戏类型的不同而表现不同。这有利于游戏性,或者根据具体情况增加戏剧性和刺激性。我们将在后面的章节中更详细地讨论所有这些。

使用 Z 顺序装饰场景

现在,我们的关卡看起来很有游戏性——很明显这是一个电脑游戏关卡,感觉不太逼真,因为里面唯一的物体显然是设计用来跳跃的平台。为了改变这一点,我们需要添加一些装饰,让世界感觉像一个活生生的,会呼吸的地方。

为此,您首先需要创建一些可用于装饰的元素。我已经创建了一棵树(图 5-11 )和一丛灌木(图 5-12 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-12。

Bush

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-11。

Tree

请注意,这两个图像都是 PNG 文件,边缘是透明的。我用免费的图像编辑软件 GIMP 做了这个,我们将在第十章更详细地讨论你如何做同样的事情。

现在,你想把这些加入到游戏中,就像你以前做过几次一样。将它们放入 Sprites 文件夹,确保改变每单位的像素,并将它们分组到一个名为Plants的空游戏对象下。你可能也想再次创建预设,尽管这在这种情况下不太重要,因为它们的外观和行为都会有所不同。

现在把你的植物和树木分散到世界各地。您可以随意混合大小,坚持在网格内并不重要。事实上,让定位看起来有点随意是件好事,因为这样会显得更自然,有助于消除一些游戏的美感。

现在试着玩这个游戏,你会发现当你走过灌木丛和树木时,你可能会走到它们的前面或后面。事实上,如果你有一个旧版本的 Unity,你甚至可以在视图中闪烁。

问题是两个东西被画在同一个地方,你还没有定义哪个应该放在上面。要解决这个问题,您需要更改 Z 顺序,这可以在检查器中通过更改名为“层中顺序”的选项来完成。默认情况下,当你添加一个新的游戏对象时,它被设置为 0,但是你可以改变它来创建不同的效果。

如果您使数字变小,这意味着对象将在其他元素之后提前绘制。同样地,如果你把数字设得更高,这意味着它会被画在最后,在所有东西的上面。

我的建议是让一些灌木和树木出现在 Squarey 的后面(设置为–1),让一些出现在 Squarey 的前面(设置为 1)。这创造了一个有趣的效果,他看起来正在穿过茂密的树叶(图 5-13 ),尽管在你构建游戏时确保这不会让玩家感到困惑是很重要的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-13。

Squarey peeping out from behind some bushes

同样,你也需要试着避免让事情变得混乱。我的建议是保持你的播放器为 0,并以此作为你的参考点。我还建议确保瓷砖将留在前面,除非你特别打算添加装饰。这将允许你把像树这样的游戏物体藏在水面下一点,而不用担心难看的缝隙。您可以通过将它们在层中的顺序设置为 10 左右来实现这一点。

为什么你会想要在你的平台上放一些东西呢?一个原因是,如果你想添加一点更自然,看起来随机的细节。例如,我已经创建了这个爬行器(图 5-14 ,然后将 Z 顺序设置为 11。通过将 X 轴和 Y 轴上的比例分别更改为–1,我也可以水平和垂直翻转图像(图 5-15 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-15。

This is how it looks when it’s in place

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-14。

This creeper adds a little detail to the game world

你可以随心所欲地添加许多这样的细节。就我个人而言,我觉得这些小小的触动对世界的外观和感觉产生了巨大的影响。我建议发挥一点创造力,看看你能想出什么。

当然,现在我们能够添加不同的层,这意味着是时候添加背景了,这将对美感产生很大的影响。我画了一个多云的天空(图 5-16 )并把它做得相当大,这样它就可以覆盖边缘没有黑色边框的空间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-16。

A nice cloudy sky

你可以使用像这样的大图片,也可以平铺背景——选择权在你。只要确保你永远不会跑出天空。显然,使用更大的图像对你的应用来说意味着以下几点:

  • 它会占用更多内存
  • 加载关卡需要更长的时间

将背景的 Z 顺序设置为-10,以确保您不会不小心将某些东西放在它后面,并在您的层次中创建一个名为 background 的组。

我们留下了您在图 5-17 中看到的内容。现在看起来是不是好多了?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-17。

Much better!

透视视差滚动

如果你想变得更有趣,你可能会决定使用另一个额外的技巧:视差滚动。

您可能已经注意到,检查器不仅允许您更改对象的 X 和 Y 坐标,还允许您更改 Z 坐标。这可能会让你觉得奇怪,因为你在 2D 模式下使用 Unity。为什么不干脆取消这个选项呢?

简单的答案是,在某些情况下,您可能想要更改元素的 Z 位置以创建 3D 效果。要进行演示,请选择您刚刚创建的背景,并将检查器中的 Z 坐标更改为 30。现在选择相机,在检查器中点击名为投影的下拉菜单。将此从正投影更改为透视。

现在点击播放,看看会发生什么。你应该会发现天空现在看起来更远了,并且比关卡的其他部分移动得更慢。你刚刚创造了一个视差滚动效果!

说明这里发生的事情的最佳方式是将场景窗口切换到 3D 模式。点击顶部的 2D 按钮在两种模式之间切换,您应该会看到类似图 5-18 的内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-18。

This is what the camera “really” sees

简而言之,我们现在有了一个 3D 视角,可以正面观察排列在 3D 空间中的纯 2D 元素。你可以用它做很多很酷的事情,你可以添加任意多的层和元素。你甚至可以在前景中看到半透明的云,或者在中距离看到以另一种速度移动的起伏的山丘。所有这些都能给你的场景增加深度和美感,但是要确保你不会以牺牲清晰度或性能为代价而失去理智。如果你在任何时候有太多的事情要做,你的玩家将不知道他们可以跳上什么或者走过什么,这甚至会让你头疼。

稍后,我们将更多地关注如何设计你的关卡,使其看起来更好,并去掉一些锋利的边缘。在那之前,让我们保持基本的东西。

添加收藏品和危险

现在你已经添加了一些无生命的物体和装饰,是时候考虑添加一些你实际上能够与之互动的元素了。我们可以从一些收藏品开始。

要做到这一点,我们当然需要从设计一些我们可以收集的东西开始。在这方面,一个流行的选择是金币,所以让我们从它开始。水雷如图 5-19 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-19。

A gold coin . Don’t you just want to collect it?

现在我们要再次把它添加到我们的场景中,就像我们把其他游戏对象添加到我们的场景中一样。这意味着我们需要导入精灵,设置每个单元的像素,然后将它制作成一个预置。我们在场景中散布的任何硬币都将按照以下等级分类:收藏品➤硬币➤金币。这一次我们也将创建一个碰撞器,我们将勾选检查器中的“触发”框。

触发器基本上是一个碰撞器,它的行为不像一个物理对象。换句话说,我们的硬币不会是我们可以走进去或跳下来的东西——相反,我们会直接穿过它,就好像它是由空气组成的一样。但与此同时,Unity 将“标记”这一事实,允许我们添加代码,告诉游戏如何响应这一事件。

将一两个你的新金币预置放到场景中,你应该会有看起来像图 5-20 的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-20。

The scene with some added gold coins

现在我们需要创建一个新的脚本,你应该记得怎么做。前往您的素材➤脚本文件夹,右键单击,并选择创建 C#脚本。将此集合命名为 CollectCoin(脚本名称不能有空格),双击它打开 Visual Studio,再编写一点代码。

在这里,我们将使用一个名为OnTriggerEnter2D的函数。这个函数在附加的游戏对象被触发时被调用,所以你放在这里的任何东西都会在玩家接触到那个游戏对象时发生。

在这种情况下,我们希望硬币消失,所以我们需要销毁它。我们通过说Destroy(gameObject)来做到这一点。当使用 Unity 时,带有小写 g 的gameObject指的是脚本附加到的特定游戏对象。

完整的脚本应该是这样的:

public class CollectCoin : MonoBehaviour {

        // Use this for initialization
        void Start () {

        }

        // Update is called once per frame
        void Update () {

        }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            Destroy(gameObject);
        }
    }
}

在伪代码中,这是在说:当某个东西接触到 2D 对撞机时,如果那个东西有标签播放器,就自毁。您可能已经猜到了,这意味着我们现在也需要跳到 Unity 中,并将那个标签添加到 Squarey 中。选择 Squarey,然后在检查器顶部找到标签选项。它现在应该显示未标记,你要做的就是点击下拉菜单并选择播放器。

最后,不要忘记把收集硬币的脚本附在你的硬币上。通过单击添加组件➤脚本➤集合来完成此操作。

点击播放,现在当你走进硬币,他们应该立即消失。在图 5-21 中,你可以看到我如何排列我的硬币,以及我如何将玩家标签添加到 Squarey 中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-21。

Ready to do some collecting

如果我们想制造一些危险呢?在这种情况下,我们可以做完全相同的事情,除了我们想要移动我们的球员回到开始的位置或者可能结束游戏。

为此,我们需要一个新的精灵(图 5-22 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-22。

Spikes

现在添加精灵,就像你之前做的那样制作一个预置。记得设置单位像素,并添加一个多边形碰撞器。你可能需要自己塑造它来很好地适应周围的钉子。

您将像上次一样添加一个脚本。这一次的代码也将非常相似,只是略有变化。现在它将显示以下内容:

public class Hazards : MonoBehaviour
{
    private Player player;

    // Use this for initialization
    void Start()
    {
        player = FindObjectOfType<Player>();
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            player.transform.position = new Vector2(-6, 8);
        }
    }

}

将这个脚本组件附加到尖刺预设上,记住勾选 Is Trigger,然后就可以开始了。这个脚本与上一个非常相似,除了我们不是破坏游戏对象,而是移动玩家。首先,我们必须定义我们所说的“player”是什么意思,这是通过查找附加到 Player 脚本的对象来实现的。从那里,我们可以改变球员的变换(位置)到一个新的向量 2(一个有两个轴的坐标)。我们将玩家移动到位置(–6,8),因为那是 Squarey 在我的场景中开始的地方。看一下你的 Squarey 版本的起始位置,并改变坐标来匹配。

最后,像我在图 5-23 中所做的那样,在你的关卡中合理的位置放置一些尖刺。我还建议将它们组织在一个名为Hazards的空游戏对象下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-23。

Beware the spike pit !

现在,当你点击播放,落在钉应该自动传送你回到开始的位置。这不是很有魅力,但它做了工作,说明了这一点。在接下来的章节中,我们将会看到如何正确地杀死和复活玩家,以及如何计算收藏品的点数。现在,虽然,这给了你一个很好的想法,如何使用触发器,以使各种各样的效果工作。我们可以使用完全相同的代码来制作一个传送门,把玩家送到下一关!或者我们可以用它来制造一些敌人…

介绍敌人

本质上,所有的敌人都是移动的危险。现在你知道该怎么做了:首先创建一个新的精灵,最好是看起来有点威胁的东西,如图 5-24 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-24。

Not sure who this guy is but he looks menacing

给他一个对撞机,给他做一个触发器,造一个预置。然后附上危险脚本,这样他的功能就和尖刺一样了。不同之处在于,我们还将添加另一个名为 BackAndForth 的脚本。进行修改,使其与之前的脚本完全相同(在 scripts 文件夹中右键单击),然后添加以下代码:

public class BackAndForth : MonoBehaviour
{

    public double amountToMove;
    public float speed;
    private float startx;
    private int direction;

    // Use this for initialization
    void Start()
    {
        direction = 0;
        startx = gameObject.transform.position.x;

    }

    // Update is called once per frame
    void Update()
    {
        if (gameObject.transform.position.x < startx + amountToMove && direction == 0)
        {
            gameObject.transform.position = new Vector2(gameObject.transform.position.x + speed, gameObject.transform.position.y);

        }
        else if (gameObject.transform.position.x >= startx + amountToMove && direction == 0)
        {
            direction = 1;
        }
        else if (gameObject.transform.position.x > startx && direction == 1)
        {
            gameObject.transform.position = new Vector2(gameObject.transform.position.x - speed, gameObject.transform.position.y);
        }
        else if (gameObject.transform.position.x <= startx && direction == 1)
        {
            direction = 0;
        }
    }
}        

通读一遍,看看你能否弄清楚它是如何工作的。明白了吗?你当然知道。但是以防万一…本质上,我们有两个公共变量可以从 Inspector 中设置:速度(称为speed)和对象将移动的距离(称为amountToMove)。当对象在运行时被创建时,它也检查获取它的当前 x 坐标。方向可以是 1 或 0,并且像所有整数一样,在脚本启动时默认设置为 0。

因此,脚本会询问当前位置是否小于我的起点加上我必须移动的距离,以一定的速度向右移动——但前提是我向右移动。一旦物体经过那个点(>=的意思是“大于或等于”),那么它就会把方向改变为 1。当 direction 为 1 时,应用反向逻辑,直到字符等于或小于起始位置,此时 direction 切换回 0,我们再次向右。

现在,如果你把这个脚本和危险脚本一起添加到坏人身上,你应该有一个左右移动的游戏对象,当它接触到他们时杀死玩家。只要记得首先在检查器中设置变量(见图 5-25 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-25。

The bad guy in his starting position

请注意,无需重写大量代码,只需以独特的方式组合多个脚本,就能获得令人印象深刻的结果。天空是无限的。

可推动的对象

当我们添加所有这些不同种类的对象和元素时,让我们再添加一个非常好和简单的:一个可推的板条箱(图 5-26 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-26。

Crate to finally meet you…

你需要做的就是引入一个有碰撞器和刚体的游戏对象(就像玩家一样)。这将允许你通过推动它或甚至将它丢入水中来与该物体互动,以观察它上下浮动(图 5-27 )。这创造了许多潜在的游戏机制和挑战,这再简单不过了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-27。

Push the crate into the water and see what happens

但是请记住:如果你的角色要能够从箱子上跳下来,他们需要将他们的层设置为地面。

使用材料

在我结束这一章之前,让我来解决一个小问题,它仍然与我们游戏世界中的物体不太相符:slidiness。你可能已经注意到 Squarey 喜欢像在冰上一样到处滑行,这看起来不太对,而且很难控制。

为了解决这个问题,我们将创建一种材料,并将其应用于表层土壤。为此,您将创建一个名为 Materials 的文件夹,然后创建一个新的物理材质 2D (RMB ➤创建➤物理材质 2D)。称之为地面。

现在选择这个材质在检查器中查看,你会发现你可以改变两个属性:弹性和摩擦力。你可能已经猜到了,摩擦力控制着特定表面的摩擦力。当 Squarey 落地时,将此值更改为 0.6 以获得更多的地面控制,将反弹度更改为 0.1 以获得不易察觉的抖动(图 5-28 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-28。

Squarey lives in a material world

现在选择表层土预设,在检查器中找到盒子碰撞器 2D 下的材质选项(不是精灵渲染器下的那个)。选择您刚刚创建的地面材质,它应该会自动应用到您游戏中的所有草地瓷砖。现在试试跑跳,事情应该更容易控制。

像这样的材料提供了一种为各种游戏对象添加属性的有用方法,我们将在以后看到它们的更多用途。

现在,这足以开始打造一个充满平台挑战、障碍和收集物品的世界。然而,我们仍然有很多事情要做,在接下来的几章中,我们将会看到如何计算分数,添加 UI 元素,甚至引入漂亮的动画。一旦一切就绪,我们就可以开始在实际的 Android 设备上进行尝试了。

现在都凑在一起了!

六、添加动画、效果和 HUD

好的,我知道我们已经读了这本书的第六章了,但是在这一点上我们还没有真正接触到 Android 手机!这是用桌面 IDE 编码的讽刺,但是如果你感到不耐烦,不要担心——在下一章中,你将尝试在实际的 Android 手机或平板电脑上部署你的游戏。不过现在,我们将添加更多的内容,为我们未来的游戏开发奠定基础——比如动画、粒子效果和平视显示器(HUD)。当我们读到第七章时,我们会明白为什么要先这么做。

别担心。现在也有很多令人兴奋的事情:添加简单的东西,比如动画,将会让你真正地给你的游戏添加个性和魅力,并将它提升到一个看起来非常专业的程度。

处理死亡和使用粒子

每个人都有自己处理死亡的方式。现在,Squarey 的方式并不特别优雅。他不仅在游戏开始时立即“出现”,而且在这种情况发生时,他也没有给我们任何短暂的停顿。整件事太简短了,不能让它真正深入人心。

如果我们有某种死亡动画,或者更好的是血淋淋的爆炸,那就好了。

为了做到这一点,我们将使用粒子系统,这种效果可以让你在屏幕上分散像素,并让它们以不同的方式运行。我们将制作一个看起来像血液爆炸的粒子效果——但是你可以很容易地使用它来制作常规的爆炸、烟火、喷泉、电力等等。

要创建您的第一个粒子系统,选择游戏对象➤粒子系统。你应该会看到一个缓慢移动的白点喷泉出现在你的场景中,选项在检查器的右边(图 6-1 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-1。

Your first particle effect

你需要调整这里的一些设置,以使效果看起来更像血。我们可以从改变开始颜色为红色(点击白色条)和开始大小为 0.2 开始。然后单击下面的形状选项,选择球体而不是圆锥体。在“排放”下,将“随时间变化的速率”改为 300。

现在展开渲染器菜单选项,并单击材质选项旁边的圆圈。选择精灵-默认,红色斑点应该变成红色方块。

接下来,展开“生命周期内的大小”(请注意,您需要先勾选“项目符号”框),然后拖动右侧,使线条向下倾斜。这意味着粒子在空气中传播时会变得越来越小,使它们以一种看起来自然的方式消失,而不是突然消失。类似地,你也可以在一生中对颜色做同样的事情。我让我的血液在向外扩张的时候变得稍微暗一点,只是为了让事情保持有趣。

我还施加了 0.2 的重力(这样粒子就往下掉了)。您可以随意使用其他选项——它们通常是不言自明的。

不过,你需要做的一件事是取消顶部的循环框,并将持续时间更改为 0.30。现在效果将只播放一次就结束,而不是立即循环。在任何时候,您仍然可以通过单击“模拟”按钮来测试动画,该按钮在选择粒子效果时浮动在场景视图上。完成后,你应该会看到类似图 6-2 的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-2。

A lovely cloud of blood

摧毁粒子系统

在我们写另一个新剧本的时候,我们将暂时把它放在一边。像往常一样,在脚本文件夹中创建它,并将其命名为 DestroyParticleSystem。你能猜出它是什么吗?(啊,太好了,罗尔夫·哈里斯的推荐信…)

该脚本将看起来像这样:

using System.Collections.Generic;
using UnityEngine;

public class DestroyParticleEffect : MonoBehaviour {

    private ParticleSystem thisParticleSystem;

    void Start()
    {
        thisParticleSystem = GetComponent<ParticleSystem>();
    }

    void Update()
    {
        if (thisParticleSystem.isPlaying)
        {
            return;
        }
        Destroy(gameObject);
    }
}

这个脚本的目的只是在粒子效果播放完毕后将其销毁。首先,我们寻找粒子系统的特定实例(在面向对象的编程中通常称为"this"),然后我们检查粒子系统是否在Update方法中运行。

最后,一旦效果播放完毕,我们就销毁它。

为什么这很重要?因为否则,我们会在内存中保存无数粒子的实例,这最终会使事情陷入困境。过一会儿这个会更有意义一点。现在,请相信我的话,保存脚本,并将其作为组件添加到您之前创建的粒子效果对象中。

重命名所述粒子系统为血液,然后将其放入预设文件夹。现在从你的等级和场景中删除血。

使危害变得危险

不过,我们还没有完成。接下来,您需要向您的危险脚本添加额外的代码,如下所示:

public class Hazards : MonoBehaviour
{

    private Player player;
    public GameObject Blood;

    void Start()
    {
        player = FindObjectOfType<Player>();
    }
    void Update()
    {

    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            Instantiate(Blood, player.transform.position, player.transform.rotation);
            player.transform.position = new Vector2(-6, 8);
        }
    }
}

首先,我们在寻找一个被称为Blood的公共游戏对象,然后我们实例化这个游戏对象。这意味着我们正在创建一个游戏对象的实例,在这种情况下,我们使用与玩家相同的坐标。不过,在我们移动球员之前,这一点很重要。

确保你还记得为你的每一个危险在等级中设置血液预置作为游戏对象。你需要在预设文件夹中这样做,这样它将会在每一个后续的尖刺或敌人(而不仅仅是那一个)中被反射。见图 6-3 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-3。

Adding the blood particle system to the Hazards script attached to the Spikes prefab

有了这些,你现在可以试着玩游戏,测试新的效果。仅尝试在场景视图中观看游戏,而不是选择全屏游戏视图。这样,您应该能够看到发生了什么:当 Squarey 走到一个钉坑上时,他爆炸了,并且在该位置创建了一个血液粒子效果的实例。此时,您会看到它出现在层次结构中。一旦序列结束,效果会在消失前自动消失。

这就是为什么我们需要 DestroyParticleEffect 脚本——否则,我们会有很多“完成的”粒子效果,这些效果来自我们死去的所有时间,这会占用不必要的内存。

如果我们创建子弹或敌人,我们同样可以使用类似的脚本,这样当我们用完数据时,数据就会被销毁。在这种情况下,我们可能有一个脚本,在一段设定的时间后或在与玩家的特定交互后销毁对象。

为什么不试着对你游戏中的硬币做些类似的事情呢?创建一个新的粒子效果并将其命名为 Sparkle,确保添加 DestroyParticleEffect 脚本,然后将其应用于游戏中的硬币。也不要忘记在 CollectCoin 脚本中添加必要的行。你也想让闪光出现在硬币的位置,而不是玩家的位置,但是我会让你自己去想。

两个额外的触摸

我们将在处理死亡的过程中增加两个小细节。第一个是在 Squarey 被杀和 Squarey 出现在他的新地点之间引入一个短暂的停顿。我们通过在 Hazards 脚本中添加以下代码来实现这一点:

void OnTriggerEnter2D(Collider2D other)
{
    if (other.tag == "Player")
    {
        StartCoroutine("respawndelay");
    }
}
public IEnumerator respawndelay()
{
    Instantiate(Blood, player.transform.position, player.transform.rotation);
    player.enabled = false;
    player.GetComponent<Rigidbody2D>().velocity = Vector3.zero;
    player.GetComponent<Renderer>().enabled = false;
    yield return new WaitForSeconds(1);
    player.transform.position =new Vector2(-6, 8);
    player.GetComponent<Renderer>().enabled = true;
    player.enabled = true;
}

你现在不需要太担心这段代码中发生了什么,但可以说我们增加了一个延迟。是一个可以在其他事情正在进行时发生的例行程序,这意味着我们可以包含一个暂停,而不会让它看起来像是游戏已经崩溃了。我们正在实例化我们的爆炸,等待 1 秒(WaitForSeconds(1)),然后将玩家移动到新的位置。

在这些事件之间,我们还关闭了玩家的可见性(player.GetComponent<Renderer>().enabled = false),并且我们移除了所有的动量,这样玩家在重生(player.GetComponent<Rigidbody2D>().velocity = Vector3.zero;)时就不会移动了。

点击播放并尝试一下。你应该会发现 Squarey 的死现在更有说服力了,因为他爆炸了,游戏暂停了,然后他又回到了起点(图 6-4 )。在接下来的一章中,我们将看看如何实现检查点,但是现在,这应该很好地完成了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-4。

Ouch, that has got to smart!

关于死亡,我们现在要做的最后一点接触是当 Squarey 从我们的水平边缘掉下时,阻止他无限下落。这很容易做到——我们要做的就是用一个盒子碰撞器创建一个不可见的游戏对象,并附上 Hazard 脚本。然后我们将拉伸它,在关卡下方创建一个屏障(见图 6-5 )。记得确保游戏对象是一个触发器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-5。

Adding our barrier underneath the level

为玩家制作动画

像这样添加粒子效果已经为我们的游戏做了一些重要的事情:它添加了一个基本的动画,这使世界感觉更加动态。

但并不是每部动画都包含大量分散在各处的小点。在传统的平台游戏中,物体像卡通一样被动画化,这样它们看起来就像真的在跑,在跳,或者在风中飘荡。是时候给我们的玩家角色添加这种动态动画了,所以考虑到这一点,我创造了一个小太空人,他可以探索我们将要设计的外星世界。我们将叫他凯文,和凯文·史派西同名。他的精灵如下图 6-6 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-6。

Kevin, your typical derivative platform hero!

你可能会注意到凯文的雪碧和你平常喝的雪碧有点不同。具体来说,Kevin 不是一个精灵,而是几个精灵——只不过所有这些精灵都在一个文件中。你可以在自己的游戏中使用凯文,也可以创建不同的精灵;只是要确保将它们都保存在一个图像文件中。

这就是我们所说的 sprite sheet,它只是一个包含游戏中单个角色或对象的所有动画帧的图像。这只是一种更有效的处理精灵的方式,你同样可以为游戏中的其他元素制作精灵表。像往常一样将它导入游戏,然后在检查器中打开它,将每单位像素设置为 50 后,将精灵模式设置为倍数。这告诉 Unity 文件在一个图像中包含多个不同的动画帧。精灵后面的棋盘图案代表图像中的透明区域。

现在点击精灵编辑器,然后切片(在左上角)。参见图 6-7 进行参考。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-7。

The Sprite Editor

这个切片按钮很棒,因为它自动检测我们图像中的所有帧,并为我们将它们裁剪成多个不同的图像。您将看到由方框勾勒出的各个框架,如果您愿意,您可以选择手动调整。一旦你满意了,就点击顶部的应用。

现在你可以从精灵文件夹的序列中选择第一个图像(点击精灵旁边的小箭头将显示各个帧)并将其放入玩家角色的精灵框中。现在我们用凯文替换了 Squarey(我们会想念你的,Squarey),但当我们跑步时,他仍然会沿着地板滑行(图 6-8 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-8。

Kevin enters the world

下一步是在 Unity 中再打开两个窗口。这些是动画和动画师。你可以通过选择窗口➤动画,然后使用顶部菜单选择窗口➤动画。这将打开两个新窗口,这两个窗口将首先浮动在用户界面的顶部。将这些标签拖到 Unity 中您想要的位置。我已经把动画放在了与场景和游戏相同的位置,我已经把 Animator 和项目标签一起放在了底部(见图 6-9 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-9。

Animation and Animator windows in place

你会看到我已经选择了球员,你也应该这样做。在动画窗口中,你应该会看到一个创建按钮,我们可以用它来创建我们的第一个动画。我们称它为 Idle,当对话框打开让你定义它时,你还需要创建一个新的文件夹来存储它,名为 Animations。

你会注意到,一旦你这样做了,一个时间线出现在动画窗口中,以及一种“思维导图”出现在动画窗口中。我们一会儿就会讲到这个。现在,你要做的就是将第一个精灵(凯文完全静止的样子)拖放到时间线的开始,这样你就有了看起来如图 6-10 的东西。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-10。

An idle Kevin

信不信由你,你刚刚创作了你的第一部动画。这感觉不太像动画,因为它只有一个单一的框架。但是如果你在玩游戏的时候看动画窗口,你会看到同样的图像在一遍又一遍的循环。

与动画师同行

我们更有趣的动画当然是行走的动画。要做到这一点,你需要在动画窗口中找到单词 Idle,旁边有上下箭头(在左上角)。单击它,然后单击创建新剪辑。调用这个行走,并确保它再次在动画文件夹中。

现在将行走动画的每一帧从 sprite 表放到时间轴中,确保它们的间距大致相等。如果您需要创建更多的空间,您可以通过向下滚动鼠标来实现,这将缩小视图。它看起来应该如图 6-11 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-11。

Kevin’s running animation, ready to go

现在我们有两个独立的动画,但目前 Unity 不知道我们何时要在它们之间切换。考虑到这一点,我们需要进入 Animator 中的流程图,该流程图目前直接从进入空闲状态(现在忽略任何状态——这仅在动画的更复杂交互中有用)。

我们需要做的是增加一个条件,在这个条件下,我们的流程图从空闲变为行走。为此,右键单击“空闲”并选择“新建过渡”。这将创建一个箭头,您可以将它拖动到行走状态。现在你的图表进入➤闲置➤行走。

确保选择了转换本身(箭头),然后找到读取参数的小选项卡并切换到该选项卡。你会在 Name 旁边看到一个加号按钮,如果你点击它,你就可以从不同类型的变量中进行选择。记住:变量是表示数字和字符串等数据的容器。我们正在创建一个新的 bool,Boolean 的缩写——一个可以为真或假、1 或 0 的变量。一旦你点击了加号,你就可以给它命名了,你应该称它为行走。如果你做的一切都是正确的,它看起来会如图 6-12 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-12。

Adding the walking Boolean

动画代码

我们现在需要再次做一点编码,所以打开播放器脚本并创建一个新的 Animator 引用,我们称之为anim。然后我们将在Update方法中添加一小段代码,它将检查是否按下了左键或右键,并适当地设置 Walking bool。

完成后,您的玩家脚本应该如下所示:

public class Player : MonoBehaviour {
    public Rigidbody2D rb;
    public int movespeed;
    public int jumppower;
    public Transform groundCheck;
    public float groundCheckRadius; 

    public LayerMask whatIsGround;
    private bool onGround;
    private Animator anim;

    void Start () {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
    }

    void Update () {

if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.velocity = new Vector2(-movespeed, rb.velocity.y);
            anim.SetBool("Walking", true);

        } else if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.velocity = new Vector2(movespeed, rb.velocity.y);
            anim.SetBool("Walking", true);

        } else
        {
            anim.SetBool("Walking", false);
        }

        if (Input.GetKey(KeyCode.Space) && onGround)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumppower);

        }
    }
}

注意我们使用了一个"else if"语句。当这个语句紧跟在一个if语句之后时,这意味着如果前面的语句为假,后面的语句为真,那么下面的代码就会运行。这允许我们仅在两个按钮都没有按下的情况下将Walking设置为假,同时保持我们的逻辑完整。

或者,我们可以对线anim.SetBool("Walking", rb.velocity.x 1=0)做一些类似的事情,这意味着如果下面的语句为真,如果玩家沿 X 轴的速度为零,变量Walking将等于真。然而,这可能会让凯文原地慢跑,而他纯粹依靠动量向前滑行。

完成后,返回 Unity,选择从空闲到行走的过渡,并在检查器中找到标题“条件”。单击+,使用下拉菜单选择 Walking 作为条件,并将值设置为 True。这实质上意味着只要行走是真实的,转变就会发生。

当你在这里的时候,去掉写有离开时间的方框。这意味着 Unity 不会等到整个动画结束后再从一个过渡到另一个。

现在反向重复这些步骤,这样无论何时Walking = false,你都可以从步行回到空闲状态。一旦一切就绪,它看起来应该如图 6-13 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-13。

Our flow chart is complete

正如你可能已经收集到的,没有什么可以阻止我们添加更多的分支到我们的流程图中,这样角色就有了跳跃、下落或其他我们在游戏后期添加的动作的动画。同样,我们可以添加动画,让树随风飘动,硬币原地旋转。水甚至可以在顶层轻轻波动。

该死的凯文

当然,目前这里有一个相当明显的遗漏,那就是凯文只有一个正确运行的动画。哦不!我们忘记了创建向左跑的精灵。

心理!幸运的是,我们没有必要把所有东西都做两遍,我们可以非常容易地创建向左跑的动画,只需在 Kevin 转身时翻转图像即可。为此,我们需要在播放器脚本中创建一个私有整数变量,并将其命名为facing。在Start方法中设置facing为 1(让前进方向对应正值是有一定意义的,所以 1 要=右)。然后像这样更新Update方法中的这段代码:

if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.velocity = new Vector2(-movespeed, rb.velocity.y);s
            anim.SetBool("Walking", true);
            if (facing == 1)
            {
                transform.localScale = new Vector3(-1f, 1f, 1f);
                facing = 0;
            }

        } else if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.velocity = new Vector2(movespeed, rb.velocity.y);
            anim.SetBool("Walking", true);
            if (facing == 0)
            {
                transform.localScale = new Vector3(1f, 1f, 1f);
                facing = 1;
            }

        } else

        {
            anim.SetBool("Walking", false);
        }

这里的关键行是显示transform.localscale的行——这是通过将比例设置为 1 或–1 来翻转播放器精灵的行。我们还需要确保我们正在改变facing的值,这样只有玩家第一次改变方向时才会发生。代码应该如图 6-14 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-14。

The new Player script

现在点击播放,你应该会发现凯文有一个不错的小跑步动画,可以切换方向。确保您的相机对象的坐标正好为 0 和 0,否则,当 Kevin 左右翻转时,视图会轻微晃动。

当然,目前这还远非完美。我们缺少跳跃的动画,动作有点生硬,镜头僵硬地跟着我们在屏幕上走。不要担心,您可以稍后解决所有这些问题。现在,我只是给你螺母和螺栓,这样你就可以开始自己玩了。随意开始制作你所有游戏元素的动画。图 6-15 显示了当凯文抓起一枚硬币准备跳入深渊时,他看起来是多么的激动人心。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-15。

You go, Kevin

添加 HUD

在这一章中,我们一直在关注使用效果和动画来为玩家增加更多的反馈。现在是时候关注更直接和更基本的反馈了:玩家的分数和进度。

换句话说,是时候让玩家知道他们在我们为他们制作的游戏中表现如何,并记录诸如等级、分数等等。这将通过 HUD 显示玩家重要的细节来完成。稍后,我们将能够使用这个覆盖来显示所有其他种类的东西。

首先,让我们从记录玩家收集了多少硬币开始。为此,我们希望在播放器脚本中创建一个名为coins的新公共整数。我们不需要在Start方法中说coins = 0,因为所有的数值变量在创建时都被默认设置为零。

现在我们将打开我们的CollectCoin脚本并添加对player的引用。然后,在OnTriggerEnter2D事件中,我们将添加行:player.coins++。这是player.coins = player.coins + 1的简称。换句话说,我们将玩家硬币的价值增加 1。

整个事情将如下:

public class CollectCoin : MonoBehaviour {

    // Use this for initialization
    public GameObject Sparkle;
    private Player player;

        void Start () {
        player = FindObjectOfType<Player>();
    }

        // Update is called once per frame
        void Update () {

        }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            player.coins++;
            Instantiate(Sparkle, gameObject.transform.position, gameObject.transform.rotation);
            Destroy(gameObject);
        }
    }

如果你尝试一边玩游戏,一边观察检查器中的Coins变量(玩家被选中),你会看到每次我们收集一个新硬币,它都会上升。

我们现在知道我们的玩家收集了多少硬币,但目前玩家还不知道。为了纠正这一点,我们将创建一个叫做画布的东西。

添加和使用画布

再次打开顶部菜单,创建一个新游戏对象。这一次选择游戏对象➤ UI ➤画布。在你的层次中双击它,你会看到你的场景突然缩小显示一个大的白色方框。这是画布,你可以在这里给你的游戏添加 UI 元素,比如 HUD 和触摸控件。顺便说一句,这就是为什么在创作第一部 APK 之前关注图形是恰当的。

现在右键单击层次结构中的画布,并选择 UI ➤文本来创建一个新的文本对象。在这里,让我们在检查器中写入级别 1,并将字体大小设置为 20 和粗体。我们可以改变字体,如果我们想简单地通过找到相关的 ODF 或 TTF 文件(通过下载字体,换句话说),并把它放在这里的盒子里,就像我们做精灵一样。不过,我们可以以后再担心。

此时我们需要做的最重要的事情是将这个 UI 元素锚定到屏幕的左上角。点击检查器左上角的方块图片,然后从下拉菜单中选择左上角的选项。现在把文本放在你想要的地方,它会一直锁定在屏幕的左上角。它看起来应该如图 6-16 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-16。

I chose a color that would match Kevin’s boots and be readable against a lot of backgrounds

将文本对象重命名为Level。然后创建另一个,它将被放置在最上面一个的正下方,称为Coins。使用相同的大小和颜色的字体,并使这个说硬币:0。

你猜怎么着?是时候再做一个剧本了。这个将被称为 Score,它将被附加到我们刚刚创建的Coins对象上。内容如下:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Score : MonoBehaviour
{
    Text coins;
    private Player player;

    // Use this for initialization
    void Start()
    {
        coins = GetComponent<Text>();
        player = FindObjectOfType<Player>();
    }

    void Update()
    {
        coins.text = "Coins: " + player.coins;
    }
}

注意写着using UnityEngine.UI的那一行。这基本上告诉 Unity 我们引用了一个额外的类,以便获得更多的编码选项。

希望这个脚本的其余部分是不言自明的。我们所做的就是反复更新文本(这是一种字符串变量)来读取Coins:player.coins整数。

将它作为一个组件添加到文本对象中,你会发现这个游戏让你知道凯文在他的冒险中收集了多少硬币。事实上,就像你在图 6-17 中看到的那样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-17。

Kevin now has two coins. Way to go, Kevin. Remember to add your coin’s sparkle effect, if you haven’t already.

添加声音效果

既然我们已经做了所有这些,我们也可以完成这项工作,并在收集硬币时添加一些音效。幸运的是,这很容易做到。

你当然需要一个文件来存放你的声音(你可以从本书的参考资料中获得或者自己制作),正如你所预料的,你会想把它添加到一个名为 Audio 的新文件夹中。我的音频文件叫 Bling.wav。

现在将一个公共音频源 bling 添加到您的 CollectCoin 脚本中,并在player.coins++上方添加一行内容为bling.Play()。这非常简单,除了我们不能直接把音频文件放到检查器的盒子里。取而代之的是,我们需要使用一个音频源,它是任何一个将音频作为组件附加的游戏对象。我见过很多人做的是将音频文件添加到空的Collectibles游戏对象中,该对象是Coins对象的父对象,然后将它拖到检查器的框中。(确保在唤醒时取消勾选播放)。

不幸的是,你需要为游戏中的对象实例做这件事,而不是预设。

还有其他方法可以做到这一点,但就目前而言,它应该看起来像图 6-18 ,并且每当你捡起一枚硬币时,它都会发出声音。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6-18。

The Collectibles object now has Bling as a component

有了这些,我们现在准备在实际的移动设备上试用这个东西。除非你觉得自己很勇敢。

一些高级理论:类、对象和方法,天啊!究竟什么是对象?

你可能已经注意到了,我把 Unity 中的几乎所有东西都称为游戏对象。这个术语很方便,因为在游戏开发环境中,大多数东西都是对象,比如树、敌人、硬币和云。但实际上这里还有更深层的东西。

这是因为在编程语言中,对象也可以引用一种类型的数据。Unity 如此强大和方便的另一个原因是它使用了面向对象编程(OOP)。C#和 Java 都是面向对象的,Unity 以一种优雅而聪明的方式运行着。你可能以前听说过 OOP,也可能这是你第一次遇到它。无论哪种方式,OOP 都是一种编程的设计哲学,它代表了多年来编码中发生的某种进化。如果你用像 BASIC 这样的老派语言编写代码(就像我在 ZX 谱上做的那样!),那么您就应该以一种叫做命令式编程的方式进行编程。

目标对命令对功能

命令式意味着你写的所有东西都是连续的,你应该按照运行时执行的顺序来写语句。计算机会阅读你的代码,就像你阅读文章一样:从上到下。唯一的例外是当您使用命令GOTO时,它会将解释器向前或向后发送到代码中的特定行号。这很容易理解,但随着程序开始达到数百万行(这种情况经常发生),管理起来也变得不可能。如果代码中有错误,你必须一页一页地去查找原因,如果你想重用某个部分,你唯一的选择就是复制粘贴。

然后,过程化编程出现了,它通过将代码包含在称为过程或子例程的离散部分中,解决了其中的一些问题。这意味着某些指令可以被一遍又一遍地调用,并与主代码分开编辑——但鉴于您必须调用这些过程,代码仍将经历一个漫长曲折的旅程,并在途中做出无数次停留。这就是现在所说的意大利面条代码。

OOP 只是从那里发展而来的下一步。它较少从命令的角度来看编程,而更多地从这些命令描述的数据和对象的角度来看编程。

解释的类和对象

在面向对象程序设计中,子程序被类代替,而类又被用来描述对象。对象是具有属性和行为的数据集合,这些行为被称为方法。

我们在代码中编写的所有脚本实际上都是类,因为它们描述了对象的属性和行为。我们的 CollectCoin 脚本(实际上是一个名为CollectCoin的类)描述了硬币的行为(收集时消失,增加player.coins值)和属性(硬币的位置、大小等等)。

这个类就像一个蓝图,可以创建任意多的硬币(物体)(就像一个房子的蓝图可以用来创建许多房子一样)。我们称之为对象的实例。当我们销毁我们的硬币时,我们销毁的是这些硬币的实例,而不是类本身。这就是为什么我们只有一个脚本(类)却有许多硬币的副本(实例)。这也是为什么我们需要在粒子效果播放结束时销毁它们,这样在任何给定的时间都不会有无数的粒子效果对象保存在内存中。

正如我们已经看到的,CollectCoin ( onTriggerEnter)中的方法可以编辑Player ( coins)中的属性,类能够通过访问彼此的方法和属性来相互交互。

一个类也不需要被附加到一个 sprite 上。一个类也可以仅仅用于处理数字和操作其他类。例如,您可以编写一个脚本(类)来控制时间限制,在这种情况下,对象将是时间限制——一个抽象的概念,而不是您可以移动的东西。但它仍然是一个对象,仍然由类定义。

当我们告诉 Unity 我们在每个脚本的开始使用某些类时,也会发生这种情况——这些类是 Unity 提供的,提供额外的功能,我们可以访问它们的方法和属性。当我们写这些行时,我们告诉 Unity 我们想要访问它为我们创建的一些方法和属性。

在 Unity 中实现面向对象的好处

这就是面向对象编程的高明之处:它允许我们以模块化的方式在编程语言和代码之间共享元素。如果你想在未来的游戏中加入可收集的硬币,你可以简单的把这个类放到你的新项目中。同样,当我们使用 Android SDK 时,我们实际上是在让 Unity 访问 Google 提供的类,以确保代码在 Android 设备上都能顺利运行。使用对象允许我们从其他程序员那里借用元素,并在我们自己的代码中实现它们。这也非常适合于更开放的源代码和协作形式的开发,这对整个软件行业都有好处。

对我们来说,OOP 还让我们将事物整齐地组织在逻辑块中。我们没有一个巨大的文件来决定我们游戏世界中所有事物的行为,相反,我们有游戏对象,它们都有自己的脚本。Unity 为我们提供了这些游戏对象的可视化表示,并隐藏了大部分复杂的东西,从而使事情变得更加清晰(另一方面,学习 Java 要复杂得多,主要是因为需要了解类、方法和对象)。在 Unity 中,很多时候对象确实是对象,我们可以在我们的项目中将它们作为有形的单元移动。Unity 是面向对象代码的完美入门,当你最终过渡到一个不那么可视化的代码类型时,它将帮助你想象你的类和对象以一种相似的方式存在(希望如此)。

如果我们过于迂腐,那么将死亡代码放在Player脚本中可能更有意义,而不是放在Hazards脚本中(它们实际上是类)。死亡是玩家的一种行为,因此它是该类的一个方法更有意义(记住,类描述对象和行为)。为此,我们只需将代码转移到一个公共方法(public void dying() {...)中,并进行必要的修改。然后我们将通过编写player.dying();Hazards内部调用该方法。我们也可以通过把信息放在括号里来传递信息。哦,私有方法和变量是不能被其他类访问的。

无论如何,如果你喜欢,就去改变吧——这将是一个很好的学习机会。但是如果您不愿意,代码仍然可以正常工作。

就我们的目的而言,尽可能保持代码的组织美观和高效并不重要。我们正在制作一个相对较小的游戏,大多数设备都能够运行,在这一点上,更重要的是你要跟上并了解正在发生的一切。然而,当代码变得更大时——当你作为一个团队工作时,或者当游戏更加资源密集时——在你的代码中尽可能优雅开始得到回报。让代码片段尽可能的短和高效实际上也能获得乐趣和回报。OOP?更像是强迫症编程。

不要担心,如果所有这一切都直接超过你的头。我花了多次重读才最终理解 OOP 在实际意义上的真正含义。不过,希望您现在至少对这个术语的含义有所了解——本质上是以模块化的方式编码——这将为您随着时间的推移扩展知识提供有用的基础。这将帮助你更像一个程序员一样思考,这总是一件好事。

现在,到了有趣的部分:让我们把这个东西变成一个应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值