V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DreamerQQ
V2EX  ›  程序员

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

  •  
  •   DreamerQQ · 2021-01-15 15:36:53 +08:00 · 1368 次点击
    这是一个创建于 1169 天前的主题,其中的信息可能已经有所发展或是发生改变。

    往期回顾

    前言

    第一期:制作基础场景

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

    第三期:基础的数值设计

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

    第五期:制作物品和技能

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

    第七期:触发器与逻辑

    好久不见。

    在 RPG 中,我们通常需要与 NPC 互动。 NPC 往往是游戏世界的原住民,当玩家与 NPC 互动时,我们便能够借由 NPC 之口,向玩家展示我们的游戏世界设定。

    在第七期中我们讲述过触发器与逻辑,在本期(乃至后续的更多期)中,我们将更频繁地使用它。

    不过在那之前,我们先创建 NPC 。

    实现 NPC 对话,变量与数据类型,按钮与马甲

    我在地图上放置了一个新单位。

    8-1.png

    在地图编辑器中,按下 I 键可以打开、关闭如出生点这类信息提示标记。 或者通过地形编辑器的菜单-察看-信息显示,来开关。

    8-2.png

    然后我们可以更方便地放置我们的单位。

    8-3.png

    这里我新放置的女巫,是通过物体编辑器创建的新单位 [安洁拉] 。

    8-4.png

    她在本教程中被设定为克里夫的妻子。当玩家操作克里夫与安洁拉互动时,我们可以藉由安洁拉之口来讲述一些背景设定。

    打开触发编辑器,增加一个触发器 [ E04 克里夫靠近安洁拉] 。 在事件列表中存在一个事件是 [单位 – 进入指定单位的范围] ,它使得触发器能够捕获一个单位进入另一个单位附近的事件。

    8-5.png

    在这里,128 对应的是地形编辑器一个白色网格的大小。

    8-6.png

    当你的鼠标在地形编辑器上滑动时,编辑器窗口左下角会标注你的鼠标当前所指的坐标点。

    8-7.png

    基于这个信息,我们就能判断游戏世界的尺寸并在需要时填写正确相关的参数。

    当克里夫靠近时,我们添加一个 [电影] 分类的动作 [播送单位消息(指定单位)] ,让安洁拉对克里夫说话。

    8-8.png

    随后保存进入游戏,命令克里夫靠近安洁拉,就会产生最基础的对话互动。

    8-9.png

    进入游戏后我们发现一个问题,即安洁拉不断在说话。 这显然是不符合预期的。

    这即是逻辑开发中我们常说的 BUG 。 在本逻辑中,出现这个 BUG 的原因是因为我们没有筛选接近安洁拉的单位,使得周围的小动物靠近安洁拉时,安洁拉也会说话。 让我们修复这个 BUG 。

    8-10.png 8-11.png

    在我们添加了条件限制靠近安洁拉的单位类型是克里夫后,进入游戏,一切正常。 不过如果我们的游戏是多人游戏,则还需要对这触发器进行调整。

    8-12.png

    我们对动作做了微调。

    [电影 - 播送单位消息(指定单位)] 的第一个参数是玩家组,默认会对所有玩家播放信息。但如果我们不希望在多人游戏时,每一位克里夫靠近安洁拉身边时,都对所有玩家发送一遍信息,我们就必须精确地限制我们应该给谁发送消息。 我们通过 [单位所有者] 函数,可以获得进入的克里夫所属是哪个玩家。

    8-13.png

    然后将其转换为单位组填入播送单位信息动作,作为该动作的第一个参数,便可达成我们想要的效果。

    8-14.png

    另外,通过触发器动作的注释可知,当一个对话信息在 [没有声音] 状态时,其默认持续时间为 5 秒。

    8-15.png

    我们可以通过修改该动作的参数,来让文本消息持续时间变得更长。

    8-16.png

    默认持续时间 5 秒,并添加 3 秒,即这样修改后,这对话的文本信息便可持续 8 秒。

    同时,如果我们希望安洁拉不是只说一句话,那就可以在其后再增加消息。

    8-17.png

    进入游戏后,我们能够在第一条消息 8 秒后,见到安洁拉说第二条消息:“祝你好运。”

    8-18.png

    不过目前的逻辑,如果我们来回不断在安洁拉附近徘徊,她就会不断说话。

    8-19.png

    显然,如果让这场景在正式发布的游戏中出现,画风就会要么变得很诡异要么搞笑,甚至对于一些更严谨的玩家来说就会显得冒犯。 除非这样的场景是故意设计的,否则我们就应该去修复它,避免其出现这种诡异的情况。

    让我们回到触发器,继续优化我们的逻辑。 这次,我们要使用到 [变量] 。 找到菜单的变量按钮。

    8-20.png

    点击它,打开变量窗口,添加一个变量。

    8-21.png

    8-22.png

    在弹出的变量窗口,点击上方的绿色按钮以新建变量。 新的变量在这里我取名为 [ E04_Talk ] ,设置类型为 [布尔值] ,用于记录玩家是否已和安洁拉互动。 接下来为了教学目的,我们先抛开多人游戏的情况,聚焦我们当前的知识。

    返回到 E04 触发器,添加一个条件,这次我们使用 [布尔表达式] 。

    8-23.png

    将首个参数修改为我们的变量 E04_Talk 。

    8-24.png

    第二个参数修改为不等于。

    8-25.png

    在变量窗口中我们可以看到 E04_Talk 的默认值为 FALSE 。

    8-26.png

    布尔值有两个值,一个是 TRUE (真),一个是 FALSE (假)。 [布尔值] 这个 [变量类型] 的名字来源是 Boolean,音译为布尔值。 而实际上我们可以把它理解为 [开关] ,这是一种 [数据类型] ,只有 [开] 和 [关] 两个值。 而诸如 [整数] 、 [实数] 等其他 [数据类型] ,也分别有各自定义。 整数顾名思义,-1 、0 、1 、2 、3 、100 、50000 、121531,都是整数。 实数也一样,-1.012 、0.1361 、13561.21 ,都是实数。 各数据类型的具体特性我们随后再讲解,总之现在我们先记得 [布尔值] 可以为 TRUE 或为 FALSE 就行了。

    在我们的触发器中,我们添加的第二个条件 [布尔表达式] 中,我们定义了,当 E04_Talk 不等于 TRUE 时,这个触发器才能运行。 因此如果 E04_Talk 等于 TRUE 时,这个触发器就不能运行。

    因此,我们可以在触发器的动作中修改 E04_Talk 的值,使其不再等于默认值 FALSE,而是我们赋予的 TRUE 。

    8-27.png

    8-28.png 8-29.png

    如此,E04 触发现在开始只要运行过一次后,就不会再次运行了。

    8-30.png

    测试游戏,运转正常。

    按照同样的方法,我们还可以创建很多 NPC,并且创建很多对话。 为了让玩家便于理解,我们也可以设置可互动的 NPC 所属玩家为玩家 2 (蓝色)以外的玩家。

    8-31.png 8-32.png 8-33.png

    我额外添加了一些 NPC,并设置他们所属为玩家 4,并为他们设置对话。

    8-34.png 8-35.png 8-36.png 8-37.png 8-38.png 8-39.png

    如此,我们的游戏世界就变得生动起来了。尽管我们的角色仍然是逻辑组成的数据,但他们现在的的确确可以与我们的玩家互动! 经过仔细设计,我们甚至能让他们饱含情感、根据玩家所控制的主角的状态,说出不同的话、并可能地对主角进行治疗。

    8-40.png
    8-41.png

    除了这种靠近之后产生对话的方式,我们也可以制作按钮式的对话。 即当玩家点击 NPC 的对话按钮的时候,NPC 才会与玩家对话。

    在魔兽争霸 3 中,如果有一个单位属于盟友而不属于自己,我们与之互动的方式往往是购买其出售的物品或者购买其出售的单位。 魔兽争霸 3 并没有为我们提供 [单位按钮] 这种功能,但我们的游戏需要单位按钮。 因此我们就得使用魔兽争霸 3 提供的基本组件,即单位、物品、技能、触发等等,来组合出我们需要的逻辑效果。

    我们需要捕获到玩家点击 [按钮] 这一事件,并且需要在中立或盟友单位身上呈现。 我们的第一个任务是找到哪些物件放在中立单位身上,也能够被玩家使用。 典型的一个例子是 [地精商店] 。

    8-42.png

    8-43.png

    进入游戏,我们靠近地精商店,选中它,右下角便会出现该商店会出售的物品列表。

    8-44.png 8-45.png

    当我们购买这里的任意物品时,便会触发一个事件:单位出售物品。

    8-46.png 8-47.png 8-48.png

    我们不希望在出售物品的时候触发对话,我们希望的是点击 [对话] 按钮的时候对话。想要实现这个效果,我们可以创建一个售价为 0 的物品,并添加给地精商店。

    8-49.png

    在物品页面,我们随意复制一个物品(本例中选用了 [水晶球] ),改名为 [对话] 并修改其售价。

    8-50.png

    然后我们回到单位页面,找到 [地精商店] ,修改 [科技树 - 售出物品] ,删除其它物品并添加 [对话] 物品。

    8-51.png

    修改新建的 E08 触发中的对话内容后,我们回到游戏内。

    8-52.png

    现在地精商店会出售 [对话] 物品。

    8-53.png

    不过在点击了这个按钮后,我们会发现我们的物品栏中多出了一个 [对话] 物品。 再次修改 E08,添加如下动作。

    8-54.png 8-55.png

    我们便通过 [出售物品] 来间接实现了 [按钮] 效果。

    8-56.png

    尽管我们现在点击对话按钮后不会再获得 [对话] 物品了,但我们注意到点击一次后,会有一个 [没有库存了] 提示出现在该按钮上。 解决这个问题的方法是在物编中修改物品的贩售间隔时间。

    8-57.png 8-58.png

    至此,一个基于 [出售物品] 实现的点击按钮对话逻辑我们便完成了。

    如果我们觉得只能出现一种对话很没意思,我们还可以修改点击对话后的逻辑,随机地给出不同的对话内容。 我们创建一个整数变量 i 。

    8-59.png

    8-60.png

    然后在 E08 中为整数 i 赋予随机整数值,并使用条件分支来判断整数值。

    8-61.png 8-62.png

    如此,进入游戏对话。

    8-63.png

    这样,我们就获得了不同的对话内容。

    不过,根据我们先前所说的,目前的 E08 触发器的内容是,只要地精商店出售任意道具,都一定会触发这对话。 让我们完善它,只有在玩家购买 [对话] 道具时,才显示对话内容。

    8-64.png 8-65.png

    这样,我们就获得了一个完整的对话内容。 (注:这里并没有考虑多人游戏的情况。)

    不过,我们不希望这种能够手动对话的 NPC 只是建筑。 因此我们为 [安洁拉] 添加 [商店购买物品] 技能。 8-66.png

    然后为其 [科技树 - 售出物品] 添加 [对话] 。

    8-67.png

    创建相关触发器。

    8-68.png

    这一次进入游戏,我们发现安洁拉并没有 [对话] 按钮。 原因是 [商店购买物品] 只能作用于 [中立被动] 单位上,而安洁拉属于 [玩家 4 ] ,是我们的玩家的同盟单位。 因此我们要在 [商店购买物品] 的基础上,增加 [共享商店,联盟建筑物。] 技能。

    8-69.png

    8-70.png

    加上这些后,我们发现购买 [对话] 会让 [对话] 这个物品直接掉落到地上。

    8-71.png

    然后让我们再添加 [选择英雄] 技能给安洁拉。

    8-72.png 8-73.png

    这次回到游戏中,我们的逻辑正常了。

    这次为安洁拉添加功能显得困难重重。 如果我不了解魔兽的运作机制,也许还得花费大量时间去询问为什么物品会掉落到地上,为什么有些商店可以出售物品,用单位就不行。 这些问题会出现,是因为魔兽争霸 3 存在一些由那时的工作人员在程序内设定好的 [隐藏逻辑] 。 这些隐藏逻辑没有什么说明书,全靠先行者的摸索以及他们将知识分享到社区得以流传下来。 详情请参见本期附带的 [概念:隐藏逻辑] 。

    概念:数据类型

    只要是程序,就有数据。而只要是编程,就一定和数据脱不了关系。 魔兽地图编辑器是一种游戏制作工具,但其本质仍然是数据编辑器。

    在魔兽地图编辑器中,打开触发编辑器,然后打开变量窗口。 在创建变量时,任何一个新建变量都必然被要求指定一个 [变量类型] 。 这个变量类型,实际上就是 [数据类型] 。

    8-74.png

    在上方图片内,列出了我们通过作者平台下载的编辑器中所提供的数据类型。 其中 [布尔值] 对应了取值只有 0 和 1 的 [ bool ] (或称 boolean ); [整数] 对应了 32 位整数 [ int32 ] ,取值区间为[-2147483647, 2147483647];实数则对应了 [ real ] 。 诸如物品、单位、玩家、点,等等,均可以被归类为 [对象] ,在魔兽脚本中均来源自 [ handle ] 类型。 通过找到我们下载的编辑器目录下的 jass/system/ht/common.j 文件,可以找到这种继承关系。

    8-75.png 8-76.png 8-77.png
    数据一定有类型的区分,因而每一个变量都一定有专属的一套专用于对这种数据类型进行操作的函数。 你不需要现在立即理解这些话的意思,只要记得在撰写逻辑、填写参数的时候,输入的数据一定要和某个参数的数据类型相同。 剩余的在实践中会更快理解。 同样,如果你希望了解更多关于 [数据类型] 的知识,可以直接利用你手头的搜索引擎,搜索 [数据类型] 这个关键词。

    概念:马甲

    在魔兽地图的制作中,一种经常被使用的技术是 [马甲] 。 魔兽地图编辑器提供了包含丰富的逻辑编辑功能的 [触发编辑器] ,但它仍然有很多局限性。 比如,魔兽地图编辑器内并没有 [属于单位的按钮] 。在本章中,NPC 的按钮实际上是我们通过 [出售物品] 来 [模拟] 的。 除了通过 [物品] 来模拟 [按钮] ,我们也可以通过 [单位] 来模拟按钮。因为在魔兽争霸 3 中,一个中立单位也可以直接 [出售单位] 。 这些被出售的、仅仅用于触发 [单位被出售] 、 [物品被出售] 这类事件的单位类型和物品类型,我们将它们称之为 [马甲] 。 这些单位类型和物品类型往往会在出售的同时立即被删除,因为它们存在的目的仅仅是为了触发触发器的事件检测机制,用于让游戏能够做我们需要的其它的逻辑。

    而除了这种被出售的马甲,今后我们还会遇到 [技能马甲] 、 [特效马甲] 。 这类马甲不会被立即删除,但会被创建后,用于施放技能、攻击等操作,或用于展示特效,从而帮助我们实现自行设计的、魔兽争霸 3 内不存在的更复杂的、机制更丰富的技能或系统。

    概念:隐藏逻辑

    [隐藏逻辑] ,就像游戏中的作弊码一样,是由开发者写下的,但并没有说明书公开的逻辑。 这些逻辑被挖掘出来后,经过逻辑编写者的组合,就能够达成特定的效果。 但这些逻辑本身因为过于隐秘,往往对于初学者会制造大量麻烦。 这些逻辑有些是被故意设定的,还有一些则是因为考虑不周而遗留下的 BUG 。 这些 BUG 或机制,有些恶性的逻辑会被规避,有些良性逻辑则会被游戏制作者作为一种 [快捷的特性] 来使用。 无论是兴趣向的游戏制作工具,还是专业的游戏制作引擎,都是这样。

    魔兽中存在大量的这种 [ BUG ] 或者说 [特性] ,但其数量庞大,使得魔兽地图制作的深入显得不那么容易,甚至有时候会显得恼人。 因此当你遇到一些问题无法解决时,求助于社区是好的选择。因为在社区中,偶尔会有赋闲的老手愿意出手解答新人的问题,从而帮助他们更快搞定某个难题。当然,老手的帮助并不总是免费的,所有人的时间都很珍贵。因此当你在社区提问时,保持基本的礼仪和尊重是重要的。

    回到 [隐藏逻辑] 的话题, [隐藏逻辑] 其实并不是什么好的东西,相反它会在学习过程中制造大量本不应该出现的麻烦。 这种问题往往会出现在 [为一个现有的游戏制作 MOD ] 的情景下,魔兽地图的制作正是如此。 只不过撰写一篇完完全全极其详尽的 RPG 制作教程,就不会是同本教程一样稍显轻量了。 今后的更新中我们仍然会用到一些隐藏逻辑,也可能会被这些逻辑困扰。但如果我们的目的不是深入到程序的根源去撰写全新的 RPG 游戏,我们就需要依赖于某些特定的、现有的游戏,或工具集。

    我个人并不认同依赖 [隐藏逻辑] 进行游戏制作。 但在游戏制作中,这些特性到底是好是坏,取决于游戏的真正制作者。 那些一线的设计师、开发者们,以及这些特性能否最终帮助我们呈现出更好的游戏给我们的最终受众——玩家们。

    3 条回复    2021-01-15 15:49:43 +08:00
    Charod
        1
    Charod  
       2021-01-15 15:41:15 +08:00
    牛逼
    Smash
        2
    Smash  
       2021-01-15 15:48:50 +08:00 via Android
    老哥,你是真的牛皮,这个系列做了这么久了,我还没来得及好好看完。
    rocbomb
        3
    rocbomb  
       2021-01-15 15:49:43 +08:00
    感觉现在搞 Dota2 的编辑器 更有前途啊
    不过 Dota2 搞 RPG 可能不太合适
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2832 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 582ms · UTC 14:53 · PVG 22:53 · LAX 07:53 · JFK 10:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.