从0开始做个Brotato(1):拆解游戏篇
01前言
作为一个游戏老玩家,我们或多或少总有玩到过自己非常非常喜欢的一款游戏,很想和周围的朋友们分享。这种分享并不是简单地将游戏推荐给他们,因为当我们花越多时间研究这个我们超级喜欢的游戏的时候,我们就会有越多的想法——对于游戏中好的坏的,我们总想追加一些什么、改进一些什么、删除掉一些遗憾进去,让这个游戏变得更加完整、更加完美,然后分享出去。于是才有了我们作为游戏人的最基本动力——自己做一个吧,做一个比这个更好玩的游戏。
但是随着游戏行业的“发展”,做一个游戏看起来变得越来越困难,做游戏的方式也变得越来越模糊了,但真的是这样的混沌吗?其实做一个游戏的过程并不特别难,只是随着行业的“发展”,很多正确的方式方法失传了,所以作为在行业做了20年项目核心开发者的老一代游戏人,我们还是想分享一些完整的做一款游戏的过程和思路。
于是我们决定选择最近比较受欢迎的一款独立小游戏Brotato来作为切入点,分几章节来跟大家一起从0开始拆解到最终把游戏做出来,做到可以发布的程度。
友情提示:本文很长,动图、视频、表格都很多,使用桌面浏览器可以获得更好地浏览效果。
何谓拆解游戏
拆解游戏往往是有想法要“自己做一个”之后的第一件事情,毕竟我们看到了一个游戏,产生了这样一个激动的心情,我们一定要让自己更清楚自己即将要做的事情——就是如何做好这个游戏,以及如何把自己的想法加入进去,因此我们首先得去拆解它,拆解之后才能更好的接下去做。做一个不那么恰当的类比,就像我们小时候拿到了一个机械小玩意儿,觉得很有趣,想着改造得更好玩的时候,我们需要把它彻底解构,然后重组,然后把想法落地了。
但是由于近几年行业内一些不太准确的分享产生的误导,让人错误的理解了拆解——可能年轻的游戏人们会觉得拆解就是把玩游戏中每一个好玩的点分段写下来。比如《战神》的某些细节为什么这么设计,它带给“我”怎样的体验,所以这个设计是优秀的。这样辛苦的“拆解”却总遭到行业前辈们的指责、鄙视和排斥,正是因为这是一个错误的拆解方式,我们拆解一款游戏,是为了了解一个游戏的构造,而不是为了分享自己对于游戏的看法,毕竟拆解的结果并不一定真的需要分享,而拆解的最终目的,是为了更好地做一个,而不是宣泄一下情绪。
所以,如何才算是“拆解游戏”?实际上就是把游戏的系统、元素结构,得出游戏的性质、原游戏中开发的坑点(可能遇到的困难和瓶颈),并在这个基础上更好的去“重构”这些内容,把自己的想法重构进去,做出更好的游戏来,这也是借鉴别人游戏做出更好玩的游戏必要过程。
游戏的拆解过程分为5个步骤:定义、系统拆解、元素拆解、性质提炼和创意发挥。在本篇我们将和大家一起,对Brotato这个游戏做前4个步骤的拆解。
02Brotato是什么游戏
首先分析清楚我们要拆解的游戏是什么样的东西,这就是所谓的“定义”。这包括且不限于拆解目标是什么类型的游戏,也就是它可能存在的原型是什么样的游戏;拆解目标的作者可能在制作他的时候加入了自己什么样的想法,当然这部分是可以省略的,但是对于有足够游戏经验而富有灵性的设计师来说,需要做一下这个分析,这样可以更好地帮你理解拆解目标;然后是游戏的与众不同之处,这里说的“与众不同”特指与它的原型所属类型的游戏截然不同之处,不光是表面玩法,甚至可以是背后的调性。
基础原型
Brotato的原型是一个叫做《吸血鬼幸存者》的游戏,这个游戏是一个突然火爆的,看起来是放置类游戏的游戏,并且因为受欢迎度之高以及(看起来的)开发难度之低,有了许许多多的仿造作品,换了许许多多比吸血鬼更有趣的题材产生了许许多多玩法一样的游戏,因此有了“吸血鬼幸存者Like”这个类型。
这个类型的游戏特指玩家操作一个角色,在一定时间内不被不断涌出的敌人所击败是一个标准的“是男人就撑过xx秒”的类型,只是地图采用了经典的平面俯视视角(经典的RPG类游戏的视角),玩家可以控制角色在一个平面上上下左右的移动,通过移动来躲避敌人,寻找更好的位置,并且拾取道具等。角色的攻击是全自动的,攻击方式是随着武器来变化的,玩家可以通过一些手段来获取不同的武器,并且强化武器。玩家还可以做的事情就是在角色升级的时候来对角色进行强化。
从细节洞察出设计者的原创想法
从画风上,我们可以看出作者采用了类似《以撒结合》的风格,说明作者在喜欢《吸血鬼幸存者》玩法的同时,也对《以撒结合》情有独钟,并且认为这两个游戏可以做一个很好的结合,所以会在游戏中加入一定的《以撒结合》的元素。
《以撒结合》本身是一个平面俯视视角的射击游戏,游戏的核心玩法强调的是走位躲避敌人并且射击的技巧,同时各种强化也都是来自随机的,这些点都恰好与《吸血鬼幸存者》“理论的玩法”有相似之处,因此这两个游戏的结合是存在可能性的。
Brotato的“与众不同”之处
《以撒结合》的节奏相比《吸血鬼幸存者》更快,交战速率更高,而《吸血鬼幸存者》则更接近于箭塔可以移动的塔防——玩家除了升级箭塔之外还需要控制箭塔移动躲避敌人的攻击。因此当这两个内容结合之后,节奏更快速、交战频率更高的“吸血鬼幸存者”诞生了,它更像是一个自动发射子弹的清版射击游戏,弹幕、不同的玩家子弹种类等成了这个游戏核心玩法的主旋律,相比原来的“简单走位和强调养成方向选择”,Brotato有了更有趣的核心玩法——清版射击游戏(弹幕游戏)中的躲避和开火的核心玩法,这也正是《以撒结合》所给出的更多的元素。
03Brotato的系统拆解
什么是系统拆解
系统拆解就是将游戏中的系统关系捋清楚的过程,这个过程中,我们会列出游戏的所有玩法,也就是俗称的“系统”,找到其中的核心玩法,以及围绕核心玩法展开的不同辅助玩法。所谓的玩法,就是一种规则,比如在经典的JRPG游戏中,战斗采取回合制选指令的模式、获胜目标是战胜所有的敌人、失败条件是己方关键人物被击败;而大地图玩法则是自由的在地图上以格子为单位上下左右的走路——从这里我们不难能看出,这就是2个完全不同的玩法,因为游玩他们的规则是不同的。
通常我们会错误的将一些游戏元素误认为是一个玩法,而实际上元素是隶属于玩法系统下的内容,比如“角色系统”其实是不正确的,包括“角色养成系统”,因为这是一种高度的概括——角色养成到底养成了什么?分为哪些构成?装备系统也是“角色养成”,技能系统也是“角色养成”,但是装备和技能是有区别的,这种区别不是来源上的不同,而是装备提供的是“从多个属性中选择一个作为当前使用的”,技能提供的是“不同的战斗方式来服务于战斗”,所以他们的选择方式和规则都可能是不同的——比如装备是根据部位划分的,头盔部位的装备只能从“头盔”中选择一个;技能则是根据cost来选择的,角色当前有200cost值,装备火球扣除30点,装备毒云扣除110点,这就已经是截然不同的玩法了。
一个好的游戏中,核心系统往往有且仅有一个,而辅助系统则是围绕在核心系统周围的,好的游戏辅助系统也只有一圈,如下图所示:
我们要做的,是列出核心系统与所有辅助系统,最重要的是——每一个辅助系统对核心系统产生的影响,这个影响并不是指“产出”或者“收益”,更不是“会带来什么体验”,而是一个客观存在的作用,比如:“提供双方攻击力、防御力数值上的变化,由此调整关卡的强度。”,通常RPG游戏中的武器装备系统就是起到这个作用,提供给玩家不同的数值,玩家数值与关卡强度成反比关系。
(存在“游戏目标不明”、“哪个是核心玩法都搞不清”等隐患的游戏系统结构)
在一些较为复杂的游戏中,可能会出现辅助玩法周围也有一圈子辅助玩法存在,这是一个危险的信号,这说明游戏中的玩法存在了“多核”的情况,要及时进行调整,因为这可能对于游戏性来说是杀手级的。因此我们不论是拆解还是从0设计一个游戏的时候,他所有的玩法关系,都应当确定只有一个核心,和每个玩法对核心玩法的关联。
Brotato中的系统关联
Brotato是一个比较“单纯”的游戏,所以他的玩法系统关系是这样的:
从上图我们可以看出Brotato其实一共有四大玩法:
Brotato的核心玩法是战斗系统,这个战斗系统就是在一个有限大小的地图(元素)上,控制玩家角色(元素)在二维平面上任意方向移动,由武器(元素)发出子弹(元素)来攻击敌人(元素),同时玩家要躲避来自敌人(元素)和子弹(元素),在限定的时间内存活下来(胜利条件)。
升级系统则是通过角色等级提升之后选择一个属性强化、花费资源购买一个升级卡片修正玩家角色(元素)的强度以及赋予一些特性。也就是说,升级玩法以玩家元素为接口,来对核心玩法(战斗)起到改变关卡强度的影响。
武器玩法则是通过强化、改变的方式来影响核心玩法中的武器元素和子弹元素(因为武器可以发射子弹)来改变核心玩法(战斗)中的场面情况,从而带来不同的游戏局面。
关卡玩法包括了选择玩家角色、选择强度、波数推进等元素,这些内容都是为了定制核心玩法(战斗)中的游戏局面和强度而存在的。
04Brotato中各元素的拆解
拆解系统然后建立系统之间的关联不是一个很复杂的过程,因为这只是系统设计的一个大纲建立过程。接下来的每个元素的设计,才是一个玩法设计的核心工作,在这个过程中将出现主流大公司分工中的系统和数值需要共同工作的内容——这就是游戏元素设计。不论是从0设计还是拆解别人的游戏(以提供给自己游戏设计空间),我们都需要提炼出每个系统的元素,然后进一步设计他们的数据结构和每个数据在玩法中的作用,这个设计过程中最重要的一个工作就是找出“运行时数据”和“填表数据”。
所谓的运行时数据,就是在游戏运行过程中动态产生的元素。比如brotato中的子弹实体,我们知道它产生的规则,但是具体运行到什么时候(精确到毫秒)才会在什么位置产生出什么样的子弹,这是无法预测的,只有计算机程序根据我们预设的规则才能动态算出来。这部分元素中的一些数据策划是没法填表的(比如子弹当前位置、剩余生命周期),这部分数据被称为“动态数据”;而另一部分比如子弹用什么样的贴图、子弹创建出来的时候多大尺寸这些数据是策划可以预设的,我们可以称之为“静态数据”。因此可以理解为:游戏中运行的子弹实体,需要“动态数据”+“静态数据”在一起才可以运作,而这些“静态数据”往往在运行过程中也未必是一成不变的,所以子弹实体必定是一个动态元素,又因为游戏中的元素都是数据,所以这就是一个“运行时数据”。除了子弹,也包括敌人、掉落物等等等等,游戏中大多的元素都是运行时数据。
而正如上面所说的,为了产生运行时数据,我们也会需要一些“静态数据”去初始化这个“运行时数据”中的一些元素。而这些静态数据,往往是需要策划填表的,所以称为“填表数据”,在许多公司工作流程中定义的“定表头”说的也是设计“填表数据”的结构。
当数据结构设计/拆解得足够清晰之后游戏的玩法也就自然清晰了,因此实际上这部分工作是一个完整的游戏玩法设计工作,所以通常是同一个设计师来设计的。被拆分成系统策划和数值策划工作之后,就需要多花点时间在沟通上,因为这是必须要这两部分策划紧密合作的。
当然,值得注意的是,拆解游戏的过程中拆解游戏元素,更像是一种设计草稿,这是对于原有游戏的结构的一种推测。因此拆解出来的结构,既不一定是原有游戏真实的做法,也不一定是最适合之后开发要用的,所以这里更多的意义是整理思路,在真正动手实现的阶段,我们还需要基于这个拆解,进一步设计数据结构来做到更好的适用于项目级(而非demo级)的结构。
“看破”技巧
当我们真的要开始动手拆解一个玩法,具体到拆解出元素的时候,会需要用到一个“看破”技巧。这个技巧也是对于一些事物的归纳能力——即我们要看穿游戏中很多东西仅仅只是UI或者画面表现不同,可能流程上也会有些不同(流程并不是玩法元素,虽然表现玩法时候需要用到这个技术),它们骨子里面是同一件事情。
比如Brotato中角色升级和购买强化卡片,其实本质上都是一样的东西——他们都是改变了玩家的一些数据。唯一的区别在于它们获取的渠道不同,一个是需要角色每次升级获得1点来解锁,一个则是花费游戏过程中赚取的资源来获取。如果我们将这些资源统一抽象为Currency,而Currency本身是一个Dictionary(Map)结构,Key是货币类别,Value是持有多少,那么这两个过程其实就是完全一样的玩法,让你感觉不同的仅仅只剩下在流程中、UI表现上的不同了。于是,我们看破了一件事情——角色升级和购买卡片是同一件事情(下文会更具体拆解)。
这个技巧在我们拆解游戏的时候是十分重要的,尽管在0到1设计一个(没有参考)的游戏时候他可能不那么有用,但是我们日常工作中、包括激情产生的想做一个游戏的时候,绝大多数的情景都不是从0到1无参考的设计,而是在别人已经有的基础上改进的(这就是拆解,也是本篇的价值所在了),所以“看破”确实是一个十分重要的技巧。
接下去我们就正式开始拆解Brotato的玩法元素了,其实这个拆解要做的事情无非就是3到4件——确定运行时数据→设计运行时数据产生的时间点和方式→判断是否要填表数据→如果需要填表数据就设计这个数据结构:
核心玩法元素:地图
在Brotato中,地图的结构是非常简单的运行时数据,因为在游戏中地图就是一个矩形,不会发生任何变化,也没有阻挡物,所以他的数据包括:
数据类型作用地图长度float地图纵向长多少米地图宽度float地图横向高多少米
由于游戏中产生地图尺寸的时候仅仅和预设的数值以及玩家的“地图尺寸变化”属性(下文会具体提及)有关,所以不需要“填表数据”,只需要定制一个规则,或者提供一个Config即可。所谓的Config也就是一个默认配置信息,这里面的内容很多是游戏设定的规则填充,与开放给玩家选择屏幕分辨率之类的Config不是同一个东西。
核心玩法元素:敌人Brotato中的敌人大约有25种,外加树也会被当作敌人处理,一共是26种左右。
敌人需要的运行时数据:
数据类型作用外形GameObject角色的造型,也包括了Animator之类的东西。位置Vector2角色的坐标,由于逻辑上是个2D游戏,所以无论画面是否3D,坐标都是2维的。面向右bool角色是否面向右侧,这是一个表现需要用的数据,若不面向右边,则面向左边,这是Brotato的角色表现规则。当前Hpint当前敌人剩余的Hp,当前Hp如果<=0就会被击败。Hp上限int即使怪物被恢复Hp也不会超过这个值。移动速度int之所以可以用int,是因为在Brotato的规则层约定了最小移动单位为毫米,而这里要表达的是每帧(即游戏最小时间单位,游戏的传统时间单位是帧而非秒)移动多少毫米。伤害力int敌人撞击玩家的时候会产生的伤害,我们可以理解为伤害力<=0的敌人不会撞击玩家。敌人的撞击范围和受击框一样都是一个规则(无论外观如何的敌人都是这个固定尺寸),所以只需要伤害力描述就足够了,比如大树作为敌人的话,攻击力是0的。掉落资源int每个怪物被击毙的时候都会掉落固定数量的资源(绿色方或圆形的东西),大树会掉落3个,其他小怪一般都是1个,也有完全不掉的和击败后掉落很多的。掉落回血int这是一个0-100的概率值,在Brotato中概率都是整数,十分单纯,也就是程序随机[0,100)若是<=这个值就会掉落回血的道具(一个仙人掌造型的东西)。掉落宝箱int同掉落回血一样,是一个0-100的概率值,每个怪物理论上都是有几率掉落宝箱的。子弹发射器BulletLauncher怪物发射子弹的规则,并不是所有的怪物都需要子弹发射器的。AIAI怪物的AI,在Brotato中,AI主要有2个部件移动和发射子弹,包括走路和冲锋都是移动;发射子弹是控制子弹发射器发射子弹的——所以这里的AI仅仅是移动AI就行了,发射子弹的事情就交给子弹发射器了。击败事件Array<Function>在一个怪物被击败的时候,可能会发生一系列事件,比如产生出3个小怪物。
敌人的运行时数据是在创建这个敌人的时候被初始化的,值得注意的是,在刷怪时会现在要刷怪的地方标记出来,如果此时有单位(无论是玩家角色还是敌人角色)太过接近(Config配置距离确定“接近”的具体值是多少毫米半径内)会导致敌人不被创建。初始化敌人的时候会根据敌人的配置表,以及关卡的运行时数据(下文会详细提到)算出角色的,所以角色需要一份填表数据,由策划填写(也就是“表头设计”):
数据类型作用idstring敌人的id,填表数据可能会被运行时数据或者其他填表数据所以依赖,所以肯定会有个id作为索引,这个id在程序中可以是一个int(自增序列),但是如果要填表的话,string会是一个更可读的做法,而string最后被读取到游戏过程中依然是可以生成一个keyvalue结构一一变成int的,所以从建表的角度来说,id用string是老道而聪明的做法。外观Prefabstring产生外观所需要的索引信息。基础Hpint怪物的基础Hp,基础Floor(基础Hp+波数*每波Hp提升)作为怪物的Hp上限和初始的当前Hp值。每波Hp提升float每一波的提升量,因为可以是4、8、13……这样的提升,所以允许是浮点就对了,最后计算出来是整数就可以。移动速度int怪物的移动速度。基础伤害int基础伤害,工作原理同基础Hp,赋给伤害力。每波伤害提升float工作原理同每波Hp提升,作用于伤害力。掉落资源int直接赋值给运行时敌人的掉落资源。回血掉率int直接赋值给运行时敌人的回血掉率。宝箱掉率int直接复制给运行时敌人的宝箱掉率。子弹发射器???敌人以何种形式来发射子弹。实际上这不光是决定了发射出的子弹,因为在Brotato中,敌人的AI总体可以被理解为移动和(何时)发射(何种)子弹,所以这个子弹发射器不仅是怪物发射子弹的能力,也是AI的一部分,如果怪物会发射子弹(并不是所有的都会),他就需要配置这个。AI移动配置???敌人的移动AI的配置,正如我们上面所分析的,Brotato的敌人AI,主要负责的是移动。击败事件Array<string>通过反射将击败后执行的事件函数赋值给击败事件。
当我们在整理到这里的时候,会发现在表里有两个项目:子弹发射器和AI移动配置的类型是问号,因为这2个项目我们要进一步拆解一下,他并不是一个简单的数据类型能够概括的。子弹发射器本身和子弹跟敌人都有关系,所以我们放到下文的《核心玩法元素:子弹》部分再进一步细说,这里我们先就AI移动配置进行深入一步拆解。
敌人AI拆解
当我们熟悉了Brotato之后,可以发现敌人的移动行为大致分为几种:
当然这样的分类只是拆解工作的第一步,因为这些类型中,除了“不移动”之外,都是十分模糊的概括词,没有实际的设计指导意义,所以我们先得继续去看下一步——明确移动需要的数据结构:
可能的数据构想的作用目标点移动肯定是需要一个移动目标点的,这个目标点是每一定时间产生的一个“大方向”,也就是一种目标点的方针,比如“跟踪玩家”。速度以一个什么样的速度进行移动,因为我们看到移动中还有个“冲锋”,冲锋的时候速度肯定会快于平时,由于我们把移动速度分配给了怪物而非每个移动片段,所以这里速度应该是个修正作用。时间在多少时间内执行这一段,因此“目标点”并不是一个“非要走到不可”的点,只能说我们以目标点为最终目标开始移动。由于有“跟踪+冲锋”的风格,因此我们可以判断出来,同一个怪物的移动风格会随时间变化,一段时间跟踪,然后换成冲锋,冲锋本身也是一个移动,所以也有时间,时间结束之后会换回跟踪。下一行为正如上面说的,因为要有跟踪(的时间结束)之后变成冲锋,同样冲锋结束后也变成跟踪,所以我们需要一个“下一行为”来指定当前移动行为(的时间)结束之后执行哪个行为,当然可以不断执行自己,让时间这一条也不生效。
以上只是一个构想,所以没有任何数据类型,因为光是构想并不是一个可以落地的设计,所以拆解到这里并没有结束。我们要进一步根据以上的信息和构想,来整理归纳一下游戏中的“进行时”AI的数据,也就是在运行过程中AI需要依赖于什么样的数据来移动,于是,我们先把移动方式进行再进一步的解析:
我们将怪物移动类型归纳为4个类别:
类别说明1完全不移动,尽管这可以和第二类混为一谈,即把它当做移动速度为0的第二类,但是既然不移动就不需要移动AI了,那么完全可以单独出这个类型来,以提高程序执行效率。2其实这里有2个类型的移动,因为这里包含了一个“冲锋”,可以看做一个独立类型,即下面的类型5。这类的移动中,我们要解决的移动目标问题,就是每一帧找一个“距离玩家x米的点”,这个点则是以玩家角色为圆心产生的一个圆上的一个没有被占的点,因此如果当x<=0的时候,这就是一个单一点(玩家位置)。由于游戏中本身就设有怪物之间的碰撞,并且目标点也只是个“大方向”,所以即使多个怪物目标是同一个点,也不至于最后会重叠在一起(阻挡系统已经将他们隔开了)。3围绕玩家其实就是2和4类的结合体,即当和玩家保持距离没有达标时会努力走到以玩家为中心的一个圆上,如果已经到了圆上,则会随机的选点走动。4这个类型往往是随机选择点移动,因此这里有一个选点的问题,我们可以从符合怎样的条件才会去选择。首先选择的“触发时机”可以确定是这一段移动开始的时候,当移动到点或者移动时间(构想中的属性)用完之后,就会进入下一段移动,如果下一段移动也是4类型,那么就会重新选一个点。触发时机确定了,下面就是确定这个点怎么选,这个点的选法。这实际上需要的只是一个参照物和一个值,他们分别是“距离玩家多大半径的圆内是选不到的”以及“距离自己多大的半径内是选不到”,即可选范围是:5冲锋型移动,其实就是以自己指向玩家角色的方向的射线上找一个点,然后“冲锋”一定时间。
到这里,我们已经不难推断出这个AI的大致的数据结构了:
AI移动数据类型说明移动目标点Vector2即我们这一个片段要移动到的目标点。移动时间int这个片段要持续多少个Tick(即游戏最小时间单位),我们只是向着目标点移动,不代表这个时间内一定能移动到目标,由于是一个直线移动,所以移动目标点更像是一个移动方向的参数(“我”的坐标指向这个移动目标点的向量)。移动速度float移动速度的倍率,基础移动速度的倍数得出移动的实际速度(米/Tick)。片段自增idint这是一个运行时的片段index,是一个自增量,用于判断下一个产生的这个结构会是怎样的。
以上这个数据结构是驱动AI进行移动的数据,他的赋值需要一个规则,这个规则中会依赖到“片段自增id”这项属性,由此来计算当前的数据=f(片段自增id++)。这个数据计算的规则就依赖于不同的移动模式提供的数据,这些都是“填表数据”:
类型1的数据类型说明无数据——类型1是不移动,所以完全不需要数据,没有数据就不会移动。类型2数据类型说明保持距离float类型2是找一个距离玩家角色多少半径的圆上的一点,如果这个保持距离(单位米)<=0,那说明是要找玩家重叠的点(圆半径为0就是一个点),否则我们在产生AI移动数据的时候要根据算法获得一个目标点。移动速度float移动速度的倍数,产生AI移动数据的时候赋值给移动速度(米/Tick)。速度变化float每个Tick移动速度都会+=这个值,由此变化移动速度赋值给AI移动速度。持续时间int这个片段的特点是,当赋值给AI移动数据的时候,这个移动数据的持续时间总是1Tick,因为我们需要每一帧重新获得玩家的位置,从而重新获得移动的目标点,所以AI移动数据(这个运行时数据)中的“移动时间”总是1。这里的持续时间,则是产生多少个连续的“片段自增id”,比如一个AI移动数据的片段自增id=0的时候读取到了一个类型2数据,这个数据的持续时间是10,那么直到那个AI移动数据的片段自增id<=9的时候,都会读取同一段类型2数据,根据这个信息来改写AI移动数据。类型3数据类型说明保持距离float与类型2的“保持距离”作用类似,唯一的区别就是不能接受一个过小的值,这个值一定>0,但是具体是多少,可以设计一下,比如是2米。移动速度float和类型2的“移动速度”一样,但是没有速度变化会影响这个值。与自己距离float当达到了“与玩家保持距离”的目标之后,就会开始做与类型4做一样的事情,即从地图上随机选择一个剔除掉与玩家“保持距离”半径和自身“与自己距离”半径圆所在的点,作为目的点。持续时间int和类型2一样,需要每一帧都是“移动时间”为1的,根据“片段自增id”来判断是否结束。类型4数据类型说明与自身距离float与自身的距离(作为半径)的圆形范围内的区域,是这个AI不会选做移动目标的范围。与玩家距离float与玩家的距离(作为半径)的圆形范围内,也不会成为这个AI选做移动目标的范围。移动速度float在这一段移动的时候初始的移动速度。速度变化float这段移动中每个Tick的移动速度变化,如果是0就保持匀速了。持续时间int这一段AI的持续Tick。类型5数据类型说明发起距离float由于冲锋就是自己的位置指向玩家位置作为冲锋向量,所以只有一个问题,就是距离玩家多少范围内才可能选择冲锋。移动速度float这段冲锋的的起始速度。速度变化float冲锋过程中的加速度。持续时间int这段冲锋持续多久,值得注意的是,即时遭到阻挡导致冲锋没有发生实际位移,它依然是会走完持续时间的。
到此,怪物的AI移动已经大致拆解完毕,但是他还缺少一个如何讲这些AI串起来做交互的方式,这个方式我们会在具体实现的时候进一步思考组织,因为光靠现在能拆出来的结构就去组织并不是一件明智的事情——在此之前,我们最好重构一下,也就是看着这些数据进一步抽象一下AI的真正需求。因此到此,我们的拆解工作也就完成了,尽管它看起来还有事情没做,但是实际开发中,事情需要一步步有序的做。
核心玩法元素:主角
尽管当我们打开游戏的UI的时候,就能看到主角的列表了:
但是这些并不是完整的属性,这些仅仅是因为基于游戏的性质所扩展出来的内容——即根据玩法的空间提炼的一些可变数值,赋予其实际效果,比如攻击速度,就是原本游戏中每次开火都有时间间隔,这个时间间隔是一个常量,我们将它变成一个变量,并且赋予一个转化规则,比如每100点攻击速度属性=间隔减半,尽管在brotato中并不一定是如此工作的,但是这不是值得深入研究用处的地方,因为我们最终的目标,我们要做的是:
● 提炼出有哪些可用的性质,可以设置出属性,至于属性值如何转化为对于游戏机制的影响,这是可以随意设置“兑换公式”的,比如我们就设计护甲(设为ac)的作用是减少ac/(100+ac)的伤害,或者设置为伤害直接减少ac点,都是可以的,这是一个标准的数值设计要做的内容。
● 提炼出这个“玩家属性”到底是玩家角色专属的还是“游戏环境”的:假设我们可以(或者需要)同时控制2个玩家角色,某些属性应该落在角色身上,以至于2个角色都不一样,还是2个角色可以共用?如果每个角色都要,那就是“玩家角色属性”,如果是共享的,就是“游戏环境属性”(简称“环境”),在brotato里,正好这两者可以混为一谈。
接着我们就进一步的去拆解玩家属性:
属性类型所属作用剩余时间int环境当前关卡(游戏中关的概念称作“波”)所剩的时间,如果剩余时间归0,就算胜利过关,进入下一波。当前危险int环境当前所处的危险等级,是在开始一局游戏的时候选定的。当前波数int环境当前所处的波数,共20波,危险和波数是刷敌人的用的具体参数。当前生命值int角色角色当前的生命值,如果归0,游戏就输了。等级int环境当前的等级,等级的作用仅仅只是升级每次升级可以选择一项升级内容(详细见下文),因此等级高了仅仅只是增加了“下一次选择升级项目”所需要的经验值。经验int环境经验值达到标准后,会提升等级,实际上就是一个累积到一定数量可以选一次升级项目的数值。金币int环境用于购买一部分升级内容的货币。双倍次数int环境每一波战斗结束的时候,玩家没有来得及拾取的金币就会通过收获值计算后转化为双倍次数,在下一波拾取的前“双倍次数”的金币将会翻倍,并且消耗双倍次数。累积升级int环境在一波中玩家获得经验升级的时候会获得1个累积升级,在一波结束时,每1个累积升级都可以选择1个强化内容。累积宝箱int环境在一波中玩家获得的宝箱都会变成累积宝箱,在1波结束后,每个累积宝箱都可以进行一次抽奖,获得一个道具,玩家可以拾取道具或者直接卖钱。最大生命int角色角色最大生命值,当前生命值无法超越这个值。生命再生int角色生命回复值,在brotato中,这个值决定游戏每运行多少个tick回复一次多少点生命值,在属性较低的时候,是减少恢复1点生命值的时间间隔,当数值高到间隔固定为最小之后,提升恢复的量。生命窃取int角色提升武器的生命窃取率,生命窃取率决定了每次攻击有多少概率(最高100也就是100%)恢复1点生命值,每秒最多可以通过生命窃取恢复12点生命值(游戏规则如此)。伤害int角色最终伤害值提高的百分比。近战伤害int角色不同的子弹依赖的是不同的伤害属性,其实只是为了让伤害源多元化,所以划分了5种伤害类型,实际上他们的逻辑作用是完全一样的——都是子弹的伤害乘以这个值获得最终伤害量(后文分析子弹时会详细说到)。远程伤害int角色元素伤害int角色工程学int角色爆炸伤害int角色攻击速度int角色武器的攻击速度变化,决定了一个武器发射子弹间隔时间。暴击率int角色子弹造成暴击的概率变化,最高100%暴击,最少0%暴击(绝对不暴击)。范围int角色子弹的射程或者体型变化(后文分析子弹会详细说到)。护甲int角色百分比降低(或者是负数时提高)受到的伤害值。闪避int角色几率在受到伤害的时候回避伤害(降低),有一个最大值,默认是60%,个别角色可以到90%。速度int角色角色的移动速度增加或者减少,百分比增加减少量,最小值是-99。幸运int环境决定了怪物掉落宝物的“回血掉率”和“宝箱掉率”数值的变化,还能决定刷出来的升级项目更高品质的几率(下文升级内容会详细说到)。收获int环境增加或者减少战斗结束后未拾取金币转化为双倍和直接拾取成金币的数量。大树产量int环境刷出大树(这个敌人)的概率变化。商店价格int环境商店中贩卖升级物品的价格变化。敌人数量int环境刷出敌人的数量变化。敌人速度int环境所有刷出来的敌人的移动速度将被这个值改变。拾取范围int环境拾取金币、回血道具和宝箱的范围变化(扩大或缩小,不会低于初始拾取范围)。道具恢复int环境拾取掉落的回复道具的时候,回复的生命值发生的直接变化。经验值倍率int环境拾取金币同时获得的经验值发生变化。穿透数量int角色如果发射的子弹带有穿透效果(下文子弹中会详细说到),将会改变可穿透数量。地图尺寸int环境地图的尺寸百分比增大或者缩小。进地图事件List<Function>环境当开始一波的时候,也就是刚进入地图的时候,会执行的一系列函数。很多道具会提供这样的函数,比如进入地图是生成一个环绕玩家的减速的子弹。每tick事件List<Function>环境每个Tick都可能会发生的事情,比如地雷每一定时间会随机创建一颗。击杀数int环境是一个统计数字,记录当前一局游戏已经击杀了多少个敌人。总击杀数int环境所有局的击杀数之和。
到此,我们可以发现,玩家的实际数据比肉眼可见(UI显示)的要多不少。同时我们不难发现:只要游戏中存在的性质,包括刷怪、地图大小这些,他们本来都是一个常量(参数),都可以提练成变量,让玩家通过游戏中的其他元素来改变这个值,只需要有一个变化规则,这样轻而易举的就丰富了游戏中的数值元素。但是尽管如此,越多的数值元素要“养成”(也就是有渠道变化),就会给玩家带来越多的思考成分,思考成分会与放松体验产生冲突,所以如何安排好多少内容需要玩家养成,“适可而止”是一个设计要点。
核心玩法元素:子弹
当我们要讨论子弹的时候,首先我们需要看破一件事情——就是在Brotato中,玩家一侧的所有攻击都可以视为子弹,子弹特指一个判定范围为圆形的,会按照轨迹移动的物体。这里需要“看破”的是近战武器,我们从表现上看,近战武器主要是挥舞和穿刺两种攻击模式:
但是实际上我们完全可以把近战武器本身看作是一种子弹,这并不是说不需要武器,而是武器发射的动作(武器发射动作的概念将在下文中详细描述)本身就是让武器消失,然后创建一个“和武器长得一样”的子弹,运行其自己的轨迹,形成了一种肉眼看就是近战攻击,但实际上是“近战武器”执行了“开枪”,发射了一个值比较特殊的子弹。
除了玩家的子弹之外,我们观察到敌人的子弹除了标准的之外,还有一种类似“刀光”的看起来是打一条线的攻击方式,比如:
这个看起来是以一条直线来作为判定的,与我们上面说的“子弹特指一个判定范围为圆形”这个概念是冲突的,但是实际上他们在逻辑上是一样的,只是UI表现不同,这正是因为子弹碰撞判定的处理方式决定的,首先当我们每一帧判断子弹是否击中目标的时候,我们的子弹需要根据上一帧的位置到这一帧的位置做一个胶囊体来和“子弹的目标”进行碰撞检测,如图所示:
如果我们子弹的碰撞判定不是一个胶囊体,那么有可能会因为子弹飞行速度过快,直接穿过了要检测的角色,就导致原本应当发生的碰撞并没有发生,因此我们需要:
这样一来,即使子弹飞行再快,也不会错过应该碰撞到的角色了,而这时候,在这一帧里,世界是静止的(因为是某一帧内,而时间推进又是帧推进,所以“世界是静止的”),这个子弹的上一帧到这一帧的连线便是一条“直线”,恰好符合我们肉眼可见的那个提示的“直线范围”。
到此,我们可以彻底确定,游戏中的子弹都是一个“沿着轨迹走的圆形物体”,因此我们得出运行时的子弹数据:
数据类型说明位置信息Transform子弹是一个实体,所以它有位置、旋转、缩放等信息,其中位置是一个Vector2,旋转只有z轴有效(unity2D中),而缩放信息则是xyz锁定的。半径float子弹是一个圆形,所以他需要一个半径。移动轨迹function移动轨迹函数是用来算出“位置信息”的,他通过这个子弹存在了多久作为参数,得出一个当前的“位置信息偏移”,将这个“位置信息偏移”加上创建子弹时候的位置信息,就是子弹这一帧能达到的位置信息。外观string子弹的外观,比如是一把刀,还是单纯的一颗子弹,还有爆炸本身也是一颗子弹。命中玩家bool在Brotato中只有敌人和玩家两个阵营,所以一个子弹能够击中哪些阵营可以用2个布尔来确定,比如敌人的子弹都是只能命中玩家的,还有玩家制造的炮台也是如此。命中敌人bool耐久度int每当子弹命中一个目标的时候都会减少1点自身的耐久度,如果耐久度<=0了,子弹就会消失。伤害力int子弹默认是要造成伤害或者治疗的,当然我们可以不严肃的把负伤害当做治疗来看。生命窃取int生命窃取的概率,如果子弹有创建人,成功计算生命窃取后,创建人将会获得1点生命值回复,如果1秒内还没有到12次(游戏规则)的话。碰撞事件function当一个子弹碰到了一个目标之后,需要执行一些特殊事件,比如会产生爆炸(也就是另一个子弹),或者将自身的伤害力减少(也就是武器上常见的贯通后伤害下降效果),这些都会通过子弹的碰撞事件来执行。剩余时间int子弹的剩余时间,子弹消失的另一个条件,就是剩余时间(tick)<=0的时候,每一帧所有子弹的剩余时间都会-1,一旦达到0或者更低,子弹就会被删除。创建人T创建子弹的负责人,它可以是某个敌人、没有人(因为敌人的子弹大多不需要负责人)以及玩家的某个武器。这个负责人是用来给生命窃取和碰撞事件做逻辑判定的。
当我们建立好运行时的子弹数据表之后,不难看出子弹的模板数据相比运行时,只少4个元素——位置信息,耐久度,剩余时间和创建人,其他的数据都是需要制作“填表数据”来初始化子弹的。
核心玩法元素:掉落物
在Brotato中,击败敌人后可能会产生3种掉落物,分别是金币、宝箱和回血道具。当玩家操作角色接近这些道具的时候就会把他们拾取掉,值得注意的一个细节是,回血道具在玩家生命值受损和没有受损时的拾取距离会有所不同。
掉落物的运行时属性仅有2项:
数据类型作用类型enum是金币、宝箱还是回血道具,不同的东西拾取后处理不同,并且在一波结束的时候也会有不同的处理。金币:无属性修正时,拾取金币直接获得1点经验和1个金币;一波结束后金币将变成玩家属性中的“双倍次数”值。宝箱:无论是否是一波结束时,拾取后都能获得1个“累积宝箱”值。回血道具:拾取后会立即恢复5点生命值(无修正下);一波结束时将不再拾取。位置Vector2掉落物所处的位置。
核心玩法元素:武器
武器是Brotato区别于《吸血鬼幸存者》的一个关键元素。在Brotato中,玩家角色可以携带0-12把武器进行战斗。尽管在《吸血鬼幸存者》中,角色也可以同时携带很多武器同时进行攻击,但是和Brotato中的武器不同的是,《吸血鬼幸存者》中的子弹都是从主角身上发出,并且依赖于主角所面对的方向的,brotato中每把武器都是独特的个体,它们仅仅只是坐标和玩家角色的坐标是有个对齐规则的。
虽然从玩家角度看这是一个微不足道的区别,但实际上这却是根本不同的设计,我们完全可以理解为玩家扮演的是一个武器小组,每一把武器都是独特的单位,只是共享了坐标(围绕一个角色)。因为有了这样一个结构,在我们拆解完整个游戏,并进行再设计的时候就可以利用这个性质来选择一些题材,比如一辆冲锋陷阵的吉普车,上面不同的士兵(作为武器)开火攻击敌人,也可以是一个魔法少女,和漂浮在她身边的魔法书、法器等。
武器的核心作用,其实就是一个子弹发射器,无论是远程武器还是近战武器,它的本质都是发射子弹,包括敌人的“发射子弹的AI”,也就是一个看不到外观的武器。那么武器的运行时数据就有:
数据类型说明图形string武器的美术资源。偏移Vector2武器与玩家角色的偏移,对于怪物来说该属性无意义。位置信息Transform当前武器的位置和旋转信息,缩放暂时用不到。类型enum武器的类型是为了玩家装备的同类型武器获得加成,比如5件枪械+50范围。也有一些玩家角色允许装备指定类型武器时候有额外奖励。瞄准对象enum瞄准对象是指武器会将枪口尽可能对准哪一类角色,主要有3种瞄准对象:● 瞄准玩家:主要用于怪物的AI,枪口始终是对准玩家的,所以开火的时候是以怪物指向玩家为发射方向。● 瞄准怪物:主要用于玩家武器,尝试选择最近的范围内的敌人进行攻击。● 不瞄准:即根据角色的旋转值来作为枪口发射方向。发射范围float瞄准敌人、开火的时候,都需要至少有1个敌人在这个发射范围内才会执行开火。开火间隔int每次开火之后还要多久才能再次开火,由于是运行是数据,所以是填表数据的“开火间隔”根据玩家属性等内容算出来的值。下次开火int是一个倒计时,每一帧减少1,到0了就会发射子弹,然后重置为等于“开火间隔”的数据。动画animator武器有普通动画和开火动画2种动画。子弹List<BulletLauncher>每次到了开火时候会一波发出来的子弹,未必只有一颗,比如霰弹枪就是一次性4颗子弹。附加效果List<Function>开枪时给发射出来的子弹们附加的效果,这些效果将附加在子弹的命中效果上。
由运行时数据,我们不难看出填表数据为:图形、瞄准对象、发射范围、开火间隔、动画、子弹和附加效果。在这个结构中有一个“子弹”的结构是BulletLauncher也就是“子弹发射器”,这个结构是用来告诉发射子弹的系统发射子弹的方式的,因为我们发射子弹光靠一个子弹id还是不够的,但是这个结构并不复杂:
数据类型作用子弹idstring要发射的子弹。相对枪口角度float发射的这颗子弹以枪口为0度,需要偏移多少度发射出来随机偏斜float在算完相对枪口角度之后,发射前还会随机加减这个角度来获得最终发射的偏斜值。比如冲锋枪这种武器就是因为这个值而变得并不是那么的精准。
核心玩法元素:建造物
建造物是Brotato中的炮塔、地雷等,一些是因为玩家使用了某个武器,一些是因为玩家获得了某些道具之后,每一定时间会在场上生成1个建造物。Brotato中的建筑物主要有:
从每个炮台的作用,我们不难归纳出一个事实——除了地雷之外,其他炮台都能看做“武器”,而地雷本身,则是一个不会移动并且持续时间很长的“子弹”。因此在这里,我们并不需要进一步拆分什么了,因为“建造物”本身并不是一个独特的元素,它只是用别的元素做了一下视觉包装而已。
升级玩法元素:升级内容
游戏中的升级内容表现上有两种:角色等级提升时候选的能力提升和商店里面购买的道具。我们从上面的“主角”中已经可以分析得出,其实这两种升级最终都是改变玩家(或环境)属性的方式来工作的,只是他们的选择出现的机会和选择的价格有所不同而已。因此我们把他们的结构可以定为同一个,只是出现选项的规则(也就是选择的source)不同,与这个结构无关。
(角色升级时候选择的内容之一)
(可供购买的道具,其实和升级性质一样,都是改变玩家属性,只是多点少点的数值差异)
在游戏中升级内容的运行时和填表数据是完全一致的,即直接用填表数据可以获得升级选项,当玩家选择了某个选项,交易成功之后,就会直接立即获得选项内的内容。升级内容的数据结构:
数据类型作用idstring物品的id。图标string物品的图标,显示用的。名称string物品的名称,也是显示给玩家用的。品级enum物品的品级,不仅UI要用来显示颜色,还要在随机抽取作为出现率的因子。作为道具bool这是否是作为道具的,如果是作为道具的,则在道具陈列的UI上会显示。这也是道具和升级给玩家看起来有所不同的核心原因之二(之一是获取渠道不同)。个数uint现在持有了多少个。贩卖时代表这是多少个,一般为1。限制个数uint玩家最多持有这个多少个,超额了就买不了了。属性变化List<玩家属性>改变的玩家属性,可以改变若干条,可增可减。追加效果List<Function>获取了这个之后,玩家的“进入地图时”和“每Tick事件”里面会追加这些内容。价值int一个基础的价值信息,价值随波数和角色的属性会进行计算,得出最后购买这个升级的价格。外观部位enum道具在购买的时候,有些是有外观部位的,最后购买的道具会覆盖掉同“外观部位”的外观显示。外观信息string外观显示的东西。
关卡元素玩法:角色选择与解锁
在每一局游戏开始的时候,玩家需要进行一个角色选择,选择角色决定的是一局游戏的初始条件,实际上我们可以把一个角色当做一个道具来理解,只是他是免费购买的,如果解锁了的话。
(一个角色相当于一件比较复杂的装备)
与装备不同的是,选择角色会同时修改角色若干部位的外观,选完角色之后还可以选择一件初始装备(如果角色允许的话),这也会是在角色数据表中的项目,所以角色的数据表相对于“升级内容”的不同:
数据类型区别说明部位外观List<修改外观>变为多个在升级项目中,每一件道具对于角色外观的影响只有一个部位,选角色是若干个部位。初始武器List<武器>新增角色初始可能就持有一件武器,但是大多角色初始武器是空的,只能靠可选武器中选一件作为“初始武器”。可选武器List<武器>新增角色初始的时候可以在这些武器(若已经解锁)中进行选择,选完后也会装备上,一些角色开始会有多把武器,因为除了可选武器,他本来还有初始武器。倾向性List<string>新增这是一个Tag,决定了升级项目出现的概率影响,这保证了角色不太容易随机到“没用的项目”。
在Brotato中,不同角色解锁有不同的的条件,这个条件分为3个大类:
● 初始就送:一些角色只要进入游戏就默认有选择了。
● 属性达标:“主角”的属性中某条达到某个值的时候触发解锁角色。
● 通关游戏:危险度几的时候通关游戏解锁,值得一提的是第一次挂掉相当于危险度-1通关。
关卡玩法元素:危险与波数
游戏中设有危险度和波数两个元素,危险度相当于玩家在开始游戏的时候选择一个难度,危险度默认是0,最高5,需要玩家1级1级的解锁出来,通过危险度0可以解锁危险度1,以此类推。危险度的作用是与刷怪挂钩,不论刷怪数量还是刷出来的怪的内容,都会收到危险度影响:
危险度说明0正常难度。1会有新的敌人出现。2更多新的敌人出现。在11或者12波的时候会出现一个精英怪或者大群怪。3更多新的敌人出现。在11或12波出现一个精英怪或大群怪。敌人血量、攻击(造成碰撞伤害、发射子弹)频率、移动速度都提高5%。4更多新的敌人。在11到18波有3波会出现精英或者大群怪。敌人的属性也会更高。5除了危险度4的特性,Boss也会变成2个,每个boss的生命值减少1/4。
05提炼出游戏中可发挥创意的点
当我们拆完游戏中的系统和元素之后,就可以开始进一步分析,基于这些系统和元素,提炼出可以发挥创意的点,来进行进一步创作,把游戏变得更好玩。这样发挥的创意因为是紧紧围绕着玩法的核心展开的,所以不容易过于天马行空,也不至于破坏游戏的玩法结构。提炼游戏中可发挥创意的点,通常有3种方法:
把性质变成属性
所谓把性质变成属性,就是在游戏中找到游戏规则下天然形成的一些效果,这些效果通常可以描述为一个数值。
比如在《贪吃蛇》游戏中,蛇吃到食物就会增加一节身体,这是一个规则产生的性质,我们可以把他理解为“蛇吃到食物的时候有100%几率增加1节身体”,在这里我们看到了2个数字,一个是100%概率,一个是1节。其中1节身体是贪吃蛇的一个基本规则,是一个规则级参数,因此如果我们改动它,就会牵一发动全局——贪吃蛇原本的规则是:移动时,将最后一个格子(俗称“尾巴”)挪到移动方向上的下一格,如果吃到食物,则不是挪动“尾巴”,而是复制一个“尾巴”到移动方向上的下一格作为头部。这样一来食物增加1节身体的规则其实是固定的,如果增加2节,就有第二节加在哪儿,加完以后会不会直接导致游戏失败等多重问题,这也是去动规则级参数(这个错误行为)产生的不良后果。所以我们能动的参数,是那个提炼出来的100%——我们可能甚至从没想过贪吃蛇的吃食物增加体长是概率性的,但是如果概率是100%确实效果和原来是一样的,谁又知道原来是不是真的有概率,亦或者概率100%才是对的,从反推我们无法得知原来的设计想法,但是可以确定的是——这样设定之后,确实扩展了一个属性,因为既能完整的保证原来的效果,还能在原来效果基础上做了一个增加——达到这样的效果,就是成功的提炼了一个新的属性。
我们再回到Brotato中看,大多属性都是按照Brotato的性质所提炼出来的,比如攻击速度——原本我们就需要做2次开枪之间的一个CD设计,确保不是每一帧都发出子弹,而这个CD完全可以是1秒作为规则,但是这个1秒并不是一成不变的,他是0.8秒,1.6秒都没有问题,于是可以把他提出来作为一个属性,就叫“攻击速度”。包括地图尺寸、大树生成率等我们在界面上无法查阅的属性。
寻找Trigger
所谓寻找Trigger,就是根据游戏中的事件可能存在的触发点来寻找灵感,通常来说一个游戏的规则中,总是存在着一系列“阶段性”的转变时机,这就是“触发点”。
●比如在《俄罗斯方块》游戏中,每当方块落定之后,就是一个触发点(Trigger),会触发一个“方块落定”事件,在这个事件里面会执行:方块落下了,夺走玩家操作权。● 检查是否有行符合删除条件,如果有就删除(播放动画)。
● 检查是否符合失败条件,如果达成就GameOver了。
● 最后创建约定好的下一个方块到关卡里。
我们可以看到这个Trigger执行了4件事情,在对战的俄罗斯方块,如《街霸方块》《噗哟噗哟大战俄罗斯方块》等多人聚会游戏中,策划利用了这个Trigger,在原来的基础上追加了2条事件:
● 如果达成消除,则会为对方添加若干干扰棋盘。
● 如果方块组合出角色的必杀技,则会大幅度干扰对方棋盘。就这样,简单的创意就做出来了——在俄罗斯方块的基础上,增强了对战的干扰(早期版本俄罗斯方块可以双人进行,但是没有任何对战机制)。
(《俄罗斯方块大战噗哟噗哟》利用俄罗斯方块的Trigger点做出对战的新规则)
在Brotato中,我们也可以寻找这样的触发点,最基础的触发点,就是当子弹命中时,根据这个子弹命中时,可以做出很多花头,使得子弹看起来多姿多彩,Brotato中的一些原有的独特设计包括且不限于:
类似的利用子弹命中时这个Trigger产生的各种各样的效果,是可以设计出很多的。
外接一个辅助玩法
外接一个辅助玩法是最常见、也是最简单粗暴有效的一种扩展游戏(很难谈得上是“创意”)的手法,即在游戏现有的元素基础上,我们追加一层玩法去强调某个玩法。这个做法的困难在于一不小心就容易搞出“多核系统”(参见《Brotato的系统拆解》章节)来,导致游戏的玩法失衡并造成变味。
在常见的页游、手游中,这样的做法比比皆是,包括著名的MMO端游《魔兽世界》中,围绕着装备元素展开了如附魔、珠宝、幻化等玩法,这些都是将一个元素进一步拆多个系统的做法。
在Brotato中藏着一个并不明显的“外接辅助玩法”,就是武器合成系统,2把完全一样的武器可以合成1把更高级的武器。由于这个玩法所需要的元素很好的“隐藏”在了核心玩法元素中,因此属于融合手法比较高明的,一般不推荐这样来扩展玩法,除非商业化需要。
总结
当我们要制作一款游戏的时候,不一定非要从0开始完整的重新设计一个规则,很多时候我们可以借鉴前人已经设计好的游戏来进一步改良,做出更好玩的游戏来,而这个借鉴改良的核心技巧就是——去拆解游戏,拆解之后找到合适的“重构点”来发挥创意。现在我们拆解完了Brotato了,接下来就可以开始开脑洞了,下一篇就将是脑洞分析篇,欢迎大家一起加入到开脑洞的行列中来。