文章目录
 

Blog

DevNotes_190308

  |   DevNotes   |   No comment

对开发中的游戏项目感到失控怎么办?

重构极其重要和必要:

放弃沉没成本,不要因为已经有的为即将到来的埋榴。该重构的即可开始重构,可以花一周左右的时间去重新整理需求和实现思路,也包括策划们,可以花一周时间整理一下设计,把混乱的玩法和系统需求梳理一遍。

适用于所有ARPG游戏的刷怪机制

一些脑洞的功能最后没能实现;不论什么怪物刷出来都像丧尸一样“没有脑子”;或者是刷个怪真不容易,海量的数据要填写。是的,这些感觉都没错,因为我们总认为刷怪是个简单的小功能,从来不重视他,甚至会把一些真实的需求给搪塞了,以至于最后刷怪就被默认为是这么一件做出来效果不咋的的体力活。

但是为什么我们很少在国游里看到这些落实呢?因为背后的代价太大了,要做这个效果,在没有好的设计的情况下,简直是天方夜谭。所以我们接下来就要开始提炼需求了。

这个是个很容易想到但实际上并不好用的设计想法:

而有效的、易扩展的应该类似于这个

即美术做了一张地图,所以全世界就有了这么一张地图,而不是一张地图可能是有2张策划设计的地图,以及服务器运行时候n个副本

刷怪时,需要依赖 地图区域数据

这个也可以叫做locationModel,区域信息

它是静态的数据,比如包括

+ string id;区域名称

+ array<string> Tag ,区域tag,如果有的话,

+ polygon(or rect) Area 坐标区域;

这就真的只是静态数据,而不提供逻辑作用:

即比如这个区域在什么区域下有什么反应是与区域信息无关的;

·:隶属于这个区域的怪物,作为索引信息,可以细节地、充分地对这个区域做各种各样的限制;

·:刷怪倒计时,还可以有多个倒计时;

·:刷怪条件,SpawnInfo

→→:扩展的刷怪条件,比如各种 返回bool的函数们;候选怪物信息,

“将一个怪物的填表数据“MobModel””,变成运行时的characterObj,这里除了索引信息,还可以有一些动态数据;

一些动态数据,是不应该属于怪物表的,比如等级、掉落、等级、ai段、buff信息(此处,例如刷在雨中的敌人不会着火,这个不应该是刷新时带的,而是刷新出来后才带上的)

反过来验算:

带着我们之前的脑洞,回过头来看看这些功能能否实现,以及一些相关的玩法功能能不能实现,要尽可能的刁难自己,因为越是刁难,越是会出现边际情况,越是可以催促我们返回去进一步设计。


设计这些做法为的是让人更容易发挥,所以从一开始就应该考虑的是如何更容易维护的开放式思维,而不是开始就想好有哪些约束,让别人只能在约束下设计,这样是有违设计精神的



 

[技术交流] 几乎是全类型游戏任务机制设计中的“雾点

1,设计任务机制的基本思想”You call me, I don’t call you”。

假设我是一个系统,另外一个系统需要我提供相关数据的时候,仅仅由它主动来访问我,而我从不向他提供任何帮助

回调,回调,回调。

触发的灵活性、可扩展性远比 监视 要好得多。

甚至他还可以是个buff系统,比如我们采集了4/10个道具,就是4层buff,那么任务系统可以只检测这个buff系统(以及进行tick)而不是监视玩家的每个行为;

在实际研发过程中,这种”You call me”的任务机制,对于程序员的开发来说是非常清晰的——

Step1:在写功能的时候注意回调点。

Step2:提供3个接口来提高任务进度、降低任务进度、直接完成或者失败某个任务。

Step3:调试并确保可用。

回调的点,是不关心任务的具体数据的,比如要找npc说话,威胁他;

那么实际上

____在NPC的表中,加入 和某个npc谈话时,增加一个TAG,类似为,“和npc说话并威胁他”,给这个tag加一,然后检测玩家是否在执行这个任务,如果是就给这个TAG真的加一,否则就跳过;

eg:

玩家获得4种道具,之后如果将辣椒和汽油组合就能获得阿拉伯神油(现实中配方并非如此,我先声明——如果你照做后果自负),但是玩家尝试过程中也许会失败几次。因此我们制作这样的任务的时候,就需要在每次Craft时候去执行:

  1)给玩家添加一个记录尝试次数的Buff,通过这个Buff的层数,改变完成任务时候任务给于者说的话,当然你也可以给不同的buff,根据buff组合说出更有趣的话。

  2)当Craft出神油的时候触发任务进度提高。

8楼的例子:

我觉得……可能这么描述这个流程比较好理解些:
1,怪物死亡,并发出信号给所有符合和怪物接触的人(在WOW中就是击杀怪物的人)。
2,接受到信号的人处理这个信号。
我们用伪代码来进一步说明就是:
怪物mob下有一个列表记录和怪物接触的人(其实在WOW中,一般情况下就1人,一些共享掉落的怪物则会有很长的列表,只要你打了就在列表内,激战2则采用后者,只要你打过就在列表内),这个列表假设为killer:Array<Player>。
那么怪物的die()中就应该有
for (guy in killer){
   guy.increaseQuestFinish(mob.questSign);
}
通过这个发出信号给相关角色,而increaseQuestFinish执行的则是
if (this.currentQuest.exists(sign)){
    …..
}
类似这样的去处理掉这个任务进度的问题。但之前的游戏大多地做法则正好相反——
for (i in 0…guy.quests.length){
  for (j in 0…guy.quests.condition.length){
    ……
  }
}
这样的做法下就存在很严重的效率问题,即使你杀死的是一个根本和任务不相关的怪物,你也要去遍历一次,这就成了”I ask u”了,所以需要”u call me”来提高这件事情的效率,而”u call me”的思想其实并不仅仅用于杀怪,包括比如一个任务让你学蛙跳100次,你可以在每次蛙跳时Call一下,而不是因为任务系统的完成条件中带有蛙跳100次,所以总是在遍历。

这样的设计其实越早提出越好,当然所有的设计都是如此,但是在项目后期,其实要去改进就要看之前的代码构架了,一般来说如果用的是entity system的思路,会非常简单。当然很多时候程序员不乐意改也处于很多其他原因,所以逻辑层一般来说,我们这里策划自己动手。

13楼的tag举例:

我就举一种Tag机制的灵活运用开拓一下思路好了。
一个怪物击杀的QuestTag(暂且叫这个,反正就是杀死时影响任务变化的),一个火焰歌不林,如果你填写:goblin_humanoids_area03_schoolfire,那么你可以让程序用“_”作为分割标记来看,用伪and运算和任务的条件的tag标志产生关系:
比如有个任务叫消灭火源,他的任务目标是杀死区域内100个带火特性的生物,你只需要把这个条件的Tag定义为schoolfire,那么(schoolfire and goblin_humanoids_area03_schoolfire)肯定是==schoolfire的,两者都有schoolfire,那么这个哥不林就在这个任务的击杀范围内了。
此时你心添加了一个任务叫做屠夫,条件之一是杀死这个区域内的人形生物20个,只需要将这个条件的标志定义为”humanoids”,哥布林一样在范围内。此时你又设计了一个消灭区域3内所有哥布林的任务,它的条件之一是”goblin_area03″,那么这个哥布林仍然是符合范围的,但是另外一个哥布林(goblin_humanoids_schoolwater)就不符合条数少的那个,因为他而事实上你在填哥布林的时候并没有想过有这么多任务。


[技术交流]手游主玩法系统中被忽略的管理中枢机制

所谓的“分析请求”实际上就是这个管理中枢的核心工作

内含中枢的举例;

 

 

No Comments

Post A Comment