《魔兽世界》“成就系统”实现原理。

dacan66 2010-11-23 06:48:31
玩过WOW的朋友应该都知道,
当你完成某一系列游戏内容之后,
你将获得某项成就,
比如你走遍地图的每一寸,就可以获得一个“探索”类的成就。

而你从高处掉落,甚至可以获得一个“高处坠落”的成就。

我经常在思考,暴雪是用何种技术实现这一点的,
WOW有上千种成就,
各种成就存在于丰富的游戏内容之间,
如果单纯的在客户端循环每一次和成就有关的游戏内容中判断是否完成成就的话,
这个计算量,我想是非常的大,也会拖垮系统。

于是我很好奇,暴雪是如何做到在不耗费大量系统资源进行成就匹配,
又这样准确而优秀地判断成就是否达成。
...全文
1306 47 打赏 收藏 转发到动态 举报
写回复
用AI写文章
47 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
[Quote=引用 46 楼 zhang_debug 的回复:]
这个 sp1234 。。。。。
[/Quote]

什么意思呢?

难道不可以回答楼主的问题?楼主问到:“如果单纯的在客户端循环每一次和成就有关的游戏内容中判断是否完成成就的话,这个计算量,我想是非常的大,也会拖垮系统。于是我很好奇,暴雪是如何做到在不耗费大量系统资源进行成就匹配,又这样准确而优秀地判断成就是否达成。”,这显然没有必要。每一种生物都有一组“完成任务”的标志位,判断这个来计算成就只需要几毫秒,不可能“计算量非常大”!
zhang_debug 2011-09-23
  • 打赏
  • 举报
回复
这个 sp1234 。。。。。
theks 2011-09-23
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 skyparty 的回复:]
用观察者模式+事件的职责链就可以完成了
[/Quote]

握手。。
theks 2011-09-23
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 danjiewu 的回复:]
基本的事件触发就可以了啊,就跟windows消息怎么判断哪个按钮被点击了一样。
检查的顺序比如:人物移动->区域变更->检查区域是否未访问过->检查地图是否全开->获得成就。
服务器不会在每次人物移动时候检查成就的,就好比你鼠标移动的时候windows也不会检查当前鼠标对应的是哪个按钮。
[/Quote]
就象设计模式中的观察者模式,把事件注册到某个动作(方法),当满足条件触发后,再注册下一步的动作。

上千种成就看起来多,按照跟阵营、种族、职业、等级、性别等等相关度的关联性能排除掉一部分,再按场景、时间等即时改变的条件排除,真正可以被触发的并不多。
清风道禅 2011-09-23
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 slmintg 的回复:]
"成就"基于"统计数字",基于角色
以下是我的假设:
比如探索 "千针石林" 地图(未完成)
上面分为若干个区域
上线时 从服务器推过来的信息表现在客户端是 98,01000100
98是千针石林的地图ID,01000100是区域已探索的数据
然后是移动指令什么
更新位置后 客户端和服务器都判断你的坐标是否在0的区域 然后做相对的数据更新
只要所有区域都匹配探索 "千针石林" 地图……
[/Quote]
这个分析靠谱·
逐风 2011-09-23
  • 打赏
  • 举报
回复
事件驱动,
成就建立一个树或者堆,对号入座。
至尊贱客 2011-09-23
  • 打赏
  • 举报
回复
[Quote=引用 38 楼 wangshilei1018 的回复:]
这问题,怎么这么多人纠结
1.肯定是消息触发机制来做的
2.服务器处理能力很强大,网络通信处理能力也能强大,你在wow里的每一个小动作,例如打怪怪物掉了多少血,都是服务器来计算,并通知给客户端的,和战斗比起来,成就所带来的系统消耗几乎可以不记
3.mmrpg游戏,服务器掌控一切, 比如你打死一个怪,不是客户端告诉服务器,你打死了一个怪,而是服务器告诉客户端,你打死了一个怪. 客户端说的都不算……
[/Quote]

楼上的最后的那个比喻非常好。。。。。
vistach 2011-09-23
  • 打赏
  • 举报
回复
肯定是消息触发机制,我也这么感觉。

至于它的实现,我想应该是把所有的成就都做成成就模型了,一个不太恰当的比喻,就像一些浏览器所支持的鼠标手势。玩家的每一个动作,都会进入判定树里面进行判定,和玩家当前动作相关的成就才会被激活进行更进一步的处理,这样肯定不会是成百上千个成就都遍历判断。
vistach 2011-09-23
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 jonerxq3 的回复:]

问一个,比如说钓鱼成就,我每掉一条鱼,我就要给服务器发请求,去+1,那么几秒钟,如果大量用户在线,他怎么能那么即使的反应呢~很好奇怎么做到实时的去加1
[/Quote]

你这个问题其实不是问题,你想一下,打FB的时候,多少人在DPS啊~治疗啊,每秒钟要产生多么大是数字,那BOSS的血量啊~玩家的血量啊~玩家的魔法啊~能量啊~怒气啊~符文啊~ 每秒钟不都是在不断的加减的么,这些计算应该都是在服务器进行的。那回过头来看,钓个鱼+1这么小的计算量,算不了什么的~
wangshilei1018 2011-09-23
  • 打赏
  • 举报
回复
这问题,怎么这么多人纠结
1.肯定是消息触发机制来做的
2.服务器处理能力很强大,网络通信处理能力也能强大,你在wow里的每一个小动作,例如打怪怪物掉了多少血,都是服务器来计算,并通知给客户端的,和战斗比起来,成就所带来的系统消耗几乎可以不记
3.mmrpg游戏,服务器掌控一切, 比如你打死一个怪,不是客户端告诉服务器,你打死了一个怪,而是服务器告诉客户端,你打死了一个怪. 客户端说的都不算,服务器验证后的数据才算数,不然外挂怎么防?
4.成就系统真正麻烦之处,在于要把成就系统的钩子<hook>,添加到各个系统模块中去.相当于有人非要睡在一对小夫妻之间,监视他们做爱次数. 总之程序员最烦这个了
Baesky 2011-08-10
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 maddemon 的回复:]

我发现所谓的高手除了喷就没有实用的话

客户端所造成的每一个数据都会发送到服务端

服务端根据你所发送的数据做相关的计算工作,其中包括统计和成就

成就本身并不多,几千个而已,每个成就也就几点标识,所以就算遍历,也不会耗时严重的.

如果要缩短这个成就计算量,自然是你的数据类型和成就挂钩. 比如副本成就和击杀boss挂钩 这就避免了大部分的计算. 成就本身也是分组的. 所以我认为……
[/Quote]
一个人遍历几千次可以,上千玩家呢?上万玩家呢?
成就系统很精髓
zouqiang122 2011-08-07
  • 打赏
  • 举报
回复
up 下
dayudodo 2011-08-07
  • 打赏
  • 举报
回复
这个问题是否可以这样?将这个成就的运算交给客户端来执行,举个例子,你收集了10个小宠物,客户端呢能显示成就自然也可以设计成知道成就的详细内容,使用一个事件处理就可以做到:当你收集到10个小宠物时,对服务器发出一个成就请求,对服务器说:我有10个小宠物啦,服务器一看,确实如此(服务器中的数据包括你的人物位置,状态,等等都是实时的,所以肯定会有你小宠物的数据),于是便把成就给了客户端,这么设计呢,服务器只需要对你某个特定的成就来进行一次判断就行了,相当的节省服务器资源,不过问题也会有一些:
1.客户端不发成就请求,服务器就不判断,万一你发成就请求的时候断线了,这个成就岂不是没有了?
解决办法:你将获得第10个小宠物和成就请求封包在一起发送给服务器,也就是说客户端在确实获得了第10个小宠物并且已经判断出这是个成就后,才会封包,而不是分成二个发送.
你(客户端):我拿到9个宠物 服务器:确实如此,记录你的宠物数量为9
你:又拿到一个并且请求10宠物成就 服务器:确实如此,宠物数量为10,成就库中有此成就,给予你10宠物成就
你:断线… 服务器:给这家伙奖励居然玩断线,记下这人,下次上线再给你
你:上线 服务器:建立连接,发送相关人物数据,包括你的奖励

服务器/客户端模式的设计这样想来也是非常复杂的,有一个计算量的分配,就服务器来讲,肯定是运算量越小越好,这样就能容纳更多的用户,赚钱才是真!
2.客户端没有10个小宠物,但是却发了一个10个小宠物的成就请求,这在外挂的情况下是可能的,以服务器的为最终依据,如果出现这样的情况,可以先断线,严重了就封号处理.判断你使用外挂还是有很多办法的
3.复杂的客户端设计,有时候觉得魔兽世界这么大,对机器的要求其实也挺高的,肯定是替服务器做了不少事情.
胡思乱想,莫当真.
小赖赖 2011-08-05
  • 打赏
  • 举报
回复
用观察者模式+事件的职责链就可以完成了
maddemon 2011-08-05
  • 打赏
  • 举报
回复
我发现所谓的高手除了喷就没有实用的话

客户端所造成的每一个数据都会发送到服务端

服务端根据你所发送的数据做相关的计算工作,其中包括统计和成就

成就本身并不多,几千个而已,每个成就也就几点标识,所以就算遍历,也不会耗时严重的.

如果要缩短这个成就计算量,自然是你的数据类型和成就挂钩. 比如副本成就和击杀boss挂钩 这就避免了大部分的计算. 成就本身也是分组的. 所以我认为计算量不大.

达成某个成就,当然可以是看标识位.

比如 副本的谋个成就 击杀 3个boss 获得成就的值 是 111 (二进制)
那么 1boss就是 001 2boss是010 3boss是100,那么每次击杀都做 & 运算,就行了. 杀完就判断此副本相关成就. 如果获得了就发给客户端,调用成就获得效果


jonerxq3 2011-08-05
  • 打赏
  • 举报
回复
问一个,比如说钓鱼成就,我每掉一条鱼,我就要给服务器发请求,去+1,那么几秒钟,如果大量用户在线,他怎么能那么即使的反应呢~很好奇怎么做到实时的去加1
Captain673 2010-12-26
  • 打赏
  • 举报
回复
我觉得应该是 数据库早以统计号!!!
a184485789 2010-12-26
  • 打赏
  • 举报
回复
高空坠落,在客户端判断高度等信息,符合坠落条件就发送到服务器验证你是否完成该成就,没有完成则更新成就数据库,并通知你已经完成成就,更新你客户端的成就界面,完成过了就返回已经完成..
我是这么想的
brox24 2010-12-25
  • 打赏
  • 举报
回复
好复杂。。。类似事件这样的说法应该比较靠谱吧 不然一直循环量很大
krqw 2010-12-25
  • 打赏
  • 举报
回复
没有一个人能讲明白的 ,艾!! ,
加载更多回复(26)

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧