从零开始的 RPG 游戏制作教程(第十二期)

2021-03-08 10:50:24 +08:00
 DreamerQQ

往期回顾

前言

第一期:制作基础场景

第二期:让勇者和怪物登场

第三期:基础的数值设计

第四期:从理论的角度简单聊聊关卡

第五期:制作物品和技能

第六期:设置怪物掉落物并部署关卡怪物

第七期:触发器与逻辑

第八期:对话、按钮、变量、马甲

第九期:信息反馈(上)

第十期:信息反馈(下)

第十一期:刷怪与防守(上)

我们已经讲了很多关于如何优化体验、实现特定系统、脚本逻辑的设计等基础知识。但除了在前期我们以剧情关为中心讲述单个关卡以外,我们已经很有没有提过游戏的主流程了。

本期我们再度聚焦到游戏玩法( Gameplay ),关注游戏的主要流程。

在魔兽地图的玩家社群中,除了 3C 、DOTA 这类对抗类地图,还有一种炙手可热的地图类型是防守图。

这种地图类型之所以流行,是因为其简单易懂、便于制作,无论对于制作者还是对于玩家,都能很好、很快地接受其玩法。

而“防守”,顾名思义,整个玩法即是保护某个目标,抵抗入侵的敌人。 这来源于一个基础的系统:刷怪。

周期性的、间隔一定时间按照特定规则刷出一定数量的怪物,并让这些怪物向基地进攻。

除了在地图上直接放置怪物以外,这种玩法是相较于塔防、自走棋、在线多人 RPG 等规则以外,制作难度更低的类型。

本期就让我们从这里开始,先制作一个刷怪系统。

打开地图编辑器,新建一个地图。

为了直观理解,我们创建一个纵向长方形的地图。

我们将要让怪物从上方出现,并攻向下方的基地。

点击确定,我们将得到如下图的场景。

我们简单地刷一下地形纹理。

上方的岩石区用来作为怪物的入口,下方的草地区作为怪物进攻的目标。

我们先实现最简单无脑的刷怪,每 2 秒刷出一只怪物,并命令它攻击到基地。

在岩石区创建一个矩形区域。

如上图,简单地创建一个触发器并将逻辑编写好。

我们不需要立即把怪物的所属玩家设置为玩家 2 、3 或者别的玩家,因为我们的目的并不是立即编写出一个可以直接发布并供游玩的系统。

在我们制作一个完整的可以供体验的地图之前,我们想要的只是先完成这个刷怪逻辑。

因此,选择一个能够便于让我们测试的写法,能够让我们更有效率地制作功能,并确定它是否能满足我们的需要。

创建完成一个单位后,我们要命令这个单位攻击到基地所在位置,即下方的草丛区。

再创建一个矩形区域 001 。 然后如下,添加动作。

如此,保存并进入游戏测试,每 2 秒会出现一个步兵,并且这个步兵会被命令攻击到基地。

不过既然是刷怪,我们不能把怪物的所属玩家定义为我们自己。

但如果我们还没有办法确定接下来我们要把怪物的所属分配给哪个玩家,我们可以先使用一个变量来替代。

我们创建一个类型为 monster_owner 的全局变量,并修改我们的动作转而使用 monster_owner 作为刷出的怪物的所属玩家。

但就像我们变量窗口所显示的,我们还没有设置 monster_owner 是哪个玩家。 我们可以再创建一个触发器,用来设置初始的数据。

如果现在回到游戏,我们的怪物将会属于玩家 2 。

不过在那之前,我们增加一个触发器,用来打开全图视野,否则我们将无法在游戏中看到刷出的单位,因为整个地图中现在都没有玩家 1 的单位,这会导致我们无法观察系统的运行状况。

好了,保存,测试地图。

结果如上图,符合我们想要的效果。

不过如同我们所见到的,这个刷怪系统会每 2 秒必然刷出 1 只怪物,这意味着玩家一定会对抗源源不断的怪物,没有休息时间,并且怪物也不会随着时间增强。

如果只是作为一个小功能,那么我们已经完成它了。但如果是作为游戏的主要流程,还差点意思。

我们先设定游戏每 3 分钟会出现一波怪物浪潮,总共会有 10 波怪,并且每波怪的数量是 30 个,每波的怪物类型也不一样。

根据上述设定,首先我们要修改刷怪触发器的触发间隔时间为 180 秒。

随后,由于每波的怪物类型不同,我们需要记录当前的波次。

创建一个整数变量 wave 来指代当前波次,并在每次游戏逝去 180 秒的时候+1 。

然后修改怪物的数量为 30 。

但是程序并不会自动帮我们选出每个波次刷什么怪物类型,因此我们需要自己设置它。 同时,这些怪物类型还必须和波次有关联。

我们可以简单地通过条件分支来判断当前波次,如下图:

我们也可以把每波要刷出的怪物类型保存在一个类型为“单位类型”的数组变量中,并在地图初始化或别的任何你想要的时候把这些数据赋值储存到变量中。

如果你观察仔细,你会发现 monster_type 这个变量类型的数组长度是 11,但实际上我们只设置了 1 到 10 的值。

原因是,monster_type[0]也是一个数据。

你可以将 monster_type[0]设置为步兵、monster_type[1]设置为矮人火枪手,但其实无论从 0 开始从 1 开始,都可以让程序正常运行。

只不过为了便于理解,我使用 1 作为数组的起始值。

数组的长度设置不正确(往往是设置得太小),会导致在读取某个超出长度的变量时,打断触发器逻辑的运行。有时候这不会有什么影响,另一些时候这样的问题会导致系统逻辑严重错误并且导致游戏流程卡死。

但是排查这种问题往往不一定很简单,因为魔兽并不会准确地告诉你它崩溃或者运行错误是因为什么原因,甚至有时候它不会认为你使用一个没有经过赋值的变量是错误的。

关于这一点,后续我们还会再做讲解,但现在只先略作提醒。

回到正题,现在我们已经有了和波次关联的怪物类型数据。想要使用它,我们回到刷怪触发器,修改创建单位的类型,使用如下写法。

这样我们便得到了一个能够基于当前波次来刷出不同类型怪物的刷怪系统。

不过这个系统还是有 BUG 的。

如果我们现在就进行测试,将会在刷出怪物后,只有 30 个怪物中的一个攻向基地。原因是“最后创建的单位”指向的是单独的一个单位,我们只能用“最后创建的单位组”才能捕获被创建的多个单位。

如果我们通过单位组发布命令,而非对单位发布命令,就能看到这样的函数。

但是如同该动作所说的,这个动作最多只能对单位组中 12 个单位发布命令。我们的一共有 30 个单位。 因此我们只能选取单位组,挨个对其中的单位发布命令。

如图所述进行修改,注意要将发布命令动作中的第一个参数从“最后创建的单位”修改为“选取单位”。

现在我们的系统就完成了,保存地图后测试,会发现每 3 分钟就会刷出 30 个怪物并且攻向基地。

不过……

如果我们真的等待 3 分钟,这样的测试效率就太低了。

因此在那之前,让我们再额外增加一个事件,用来帮助我们进行逻辑测试。

完整的逻辑如上图。

运行效果如上。

不过这还不算完成,如果我们现在就这么不管了,我们的怪物每刷一波,就会造成 31 个点泄漏( 1 次怪物出生点,30 次发布命令)。

让我们修复这个问题。

如上图,我们完整地完成了一个刷怪系统的核心逻辑。

不过对于最终的游戏,我们还需要在完成第 10 波后关闭刷怪系统,否则在 10 波完成后还会继续刷怪。

因此我们还需要增加一个判断。

显然这些逻辑仅仅完成了刷怪功能,如果我们想要让玩家知道距离下一波还有多久,为玩家提示下一波怪物的类型,我们就还需要更细化的逻辑。除此以外,当玩家在第 10 波后杀死所有怪物,我们希望游戏胜利,就还需要额外撰写胜利逻辑。 这些内容,让我们下期再完成。

————————————

附:感谢魔兽争霸官方对战平台对本教程提供支持。

魔兽争霸官方对战平台是由网易研发运营,暴雪官方正式授权的官方对战平台。如果正在阅读本文的你对制作魔兽地图有想法、希望与平台探讨合作事宜,或正在寻求魔兽地图的商业变现,可通过官方平台提供的合作电子邮箱来沟通联系。

电子邮箱地址:warcraft3worldedit#service.netease.com (#替换为 @)

1405 次点击
所在节点    程序员
1 条回复
lusi1990
2021-03-08 16:04:48 +08:00
收藏了 挺怀念当初玩 水之 TD

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/759498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX