[gdc15]<暗黑破坏神3:夺魂之镰>的开发之路

《暗黑破坏神3:夺魂之镰》在经历初版的挫败后,通过深入反思游戏核心要素,引入冒险模式、loot2.0系统并移除拍卖行等措施,成功提升玩家体验。本篇详细解析了这些改革背后的思考与实践。


gdc15,《暗黑破坏神3:夺魂之镰》的game director--josh mosqueira带来(但现在已经离开暴雪),非常精彩的presentation,墙裂推荐。

在gdcvault上有,youtube上也有:link

《暗黑破坏神》系列一直是pc游戏史上重要的存在,史诗级的《暗黑2》的10年后,暗黑三发布了,整个团队背负了很多东西,也渴望重现传奇,也被新游戏设计思潮冲击。

各种各样的原因,尽管媒体给出了好的评价,但是在玩家这里却给出了3.9的超低分,这在暴雪看来简直不可想象。

然后团队重新上路,历经探索,带给玩家现在这个好得多的夺魂之镰资料片

数据:媒体依旧是接近90分的高分,玩家的评分是66,不算好,销量还是非常可观,可以查到的数据是D3截止到15年8月销量超过3千万,跻身游戏卖拷贝数量前十。


整个presentation充满着透彻的思考与专业合理的做事方式,非常不错,读完写好blog,真是受益良多。

josh对于问题的透彻思考,同时有好的设计来把问题解决,做出好的设计,真是令人叹服,难怪最近diablo3玩的上瘾放不下呀。


diablo的几大支柱

josh首先谈到diablo的几大支柱:

  • fantasy的世界观,史诗级的英雄对抗黑暗的力量,并且有超牛逼的装备掉落
  • 有剧情终点
  • 联网体验超棒
这几个核心支柱非常的重要,后面的游戏设计,或许在某些游戏中是有效的好设计,但是在diablo里就要带到这几个核心支柱中来衡量。
比如早期diablo3的几个设计就有自己的原因,但是背离了核心要素,就不好
  • 一个设计就是打怪非常的困难,获得装备很麻烦,而踢罐子则相比之下更容易获得好的装备,然后就出现一身牛逼装备的英雄不停的去打各种罐子,这就严重背离了设计的初衷。
  • 一个英雄常常随机的打出自己不需要的装备,然后就拿到拍卖行去买卖,虽然这个是diablo2时候的黑市交易,但是毕竟是一个官方不支持的东西,是少数玩家(10%不到)会有的行为,但是一旦官方支持,那么游戏就会变成,去shopping而不是去farming,这也背离了史诗英雄对抗黑暗力量拿到史诗装备的核心要素。

diablo3的几大问题
  • diablo3发布哲学(要做什么不做什么)
  • 对于玩家心理状态的误读
  • beta test不对
发布哲学
设计团队回顾了diablo2的成功,觉得非常长的装备曲线是diablo2保持长久生命力的关键因素,所以在diablo3里面也设计成玩家获得装备非常的困难,装备曲线很长。
但是实际是,diablo2的装备曲线不是一开始就这样的,是经过长时间的多个版本的迭代才逐渐加上去的。
而长时间的装备曲线则让人非常的沮丧。

另外就是觉得玩家非常的喜欢挑战,喜欢高难度,但实际是玩家的确是喜欢挑战等等,但必须是最终能够高效的干死一切恶魔的结果,而不是很难狂被虐的局面。

装备的含义也非常的不清晰,会出现蓝装比金装好的情况,这个在diablo2时代(那个时代也没几个好游戏,大家可以静下心来慢慢搞)或许可以,但是现在就很让人抓狂。

重新认识随机
之前大家觉得装备上的随机特别重要,也是导致diablo2流行的重要原因。
但是后来设计团队认识到,随机不是最终目的,可复玩性(replayability)才是,随机是达到可复玩性的方法之一。

所以这里我们围绕可复玩性来看随机的话,
  • 纯随机就不好,野蛮人拿到一个箭袋(恶魔猎手才能用的)就不是一个好的设计
  • 另外就是“掉落喷泉”也是,干死一个boss,狂喷出大量的装备,但是大量没用的,有用的不多,这也不是一个好的设计
    • 后面提到的smart drop就是好的,boss掉落
玩家心理状态
这里josh的看法是在设计一个item base的游戏的时候,一定要分清why to play和how to play
why to play就是开始的时候什么把玩家吸引过来,这里主要是fantasy的因素,史诗英雄,恶魔,牛逼装备,技能,故事。。。
how to play则是玩家开始上手之后,更深一层或者说真正开始追求的东西,就是装备,如何高效的farm来获得更牛逼的装备,
而现在互联网的发达,游戏直播,论坛等的发达,都会导致玩家很快会学会最高效的farm方式,会急速放大设计中的缺陷,
所以玩家会跑去踢罐子,去逛拍卖行,而不是屠杀恶魔。


因噎废食的beta 测试

因为担心有人会泄露剧情等等,所以beta测试中只是开放了一小部分,并不完整,来的人也不够多,导致很多问题都没有暴露出来,后来设计的缺陷,服务器挂掉,如果开放了更广泛测试,diablo3的情况会好很多。

这里看起来是一个一闪而过的一句话,但是我强烈建议读者不要一闪而过这一点,这一点以及这个presentation中所谈到的问题都是表面上看起来ok,但是实际上缺乏对问题本质的认识。

像这个beta test,大家都是这么做的,都是约定俗成的,不需要大家思考的,但正是这样的流程化的东西,让大家不要思考的东西,结果真的大家就不思考了,导致做的这个测试没有完成其应该完成的事情。

而在reaper of souls,则邀请了尽可能多的玩家来玩,尽可能的发现程序上和设计上的问题。


带来新视角的console版本

在josh看来,console版本是新资料片能够雄起的关键。

应该说,console带来了另外一个视角去看待diablo,那么很多之前模糊的问题,在新的死角下面就清晰了。

能够获得新视角,也不是随随便便就行的,josh还是做了深度思考,定义了关键的要素:

  • diablo的关键是杀怪和获得装备
  • console版本不应该是一个降配移植,应该是一个transform,把游戏在console上以更牛逼的方式重现出来,不只是一个简单的简化这种。
    • 从头思考谁,以什么样的方式来在console上玩diablo
    • 把所有的技能,技能中的镜头都做了细化调整
    • 大家在沙发上,用手柄玩diablo会是一个什么样的感觉(比如就不能很方便的上网查资料)

正是想在console上做出更牛逼的diablo体验,导致了josh他们做了更深度的思考,

第一次他们在沙发上,面对大电视,那手柄玩野蛮人,干死第一幕开始的骷髅的时候,他们认识到其实用手柄在电视玩更牛逼,这个沉浸感更好,于此同时也让josh认识到diablo游戏的真正魅力就是这种沉浸感,史诗感,黑暗势力,杀戮,装备等等,围绕这个的应该加强,背离这个的应该改变。

同时还有,diablo关键不是你如何去操作(键盘鼠标还是手柄),而是你在做什么,diablo的关键就是杀怪和拿装备,只要这个过程异常爽快,那怎么操作则不重要。


冒险模式

具体介绍可以看这篇blog

冒险模式现在应该是diablo资料片里最流行的方式,前天我也惊奇的发现,我的野蛮人从1升级到70,还升了好多巅峰等级,居然剧情一点都没打。

而这个设计就是来源于console版本。

而这个设计产生的过程非常的有意思,开始只是希望能在console上面方便的选择难度,进而产生了为什么不让怪物的难度随着玩家的等级增长而变化,原来就是每一幕里的怪的难度是固定的,当走到这里,就形成了冒险模式的基础了,再进一步,就形成了冒险模式。

而怪的难度跟随等级,问题也不太大,其实是解决了玩家无聊的刷低级怪的问题,同时怪是跟等级,不跟装备的,所以你装备牛逼,还是会形成碾压,只是没有完全固定且等级碾压那么无聊。


loot 2.0

  • 掉落少而精
    • 这个精包括更多的牛逼装备,基本不掉其他英雄的装备
  • 装备的分级描述更加的清晰,装备属性也更fantasy--更有特点,有故事性,更牛逼

在console版本里,掉落也做了优化,之前diablo3里,掉落绝对数量多,但是有用的少,基本是这样的拿来丢商店的货:


之后的掉落



现在这个装备的描述就好太多了:


有:

  • 什么英雄打就掉这个英雄能用的
  • 基本属性(武器则是输出相关),次要属性(有一些是打怪多加经验等)主次分明
  • 还有史诗级的词缀属性
  • 和现有装备的对比,用了之后增益一目了然
对于掉落好的装备,设计团队也担心会不会玩家太快拿到自己喜欢的装备,然后就离开游戏了,这里josh的看法是:
  • 如果能那准火候肯定最好
  • 如果拿不准,就慷慨一点,让玩家开开心心的,拿到自己喜欢的游戏,即便不再玩了,那么下一个补丁和资料片他还是会回来的,而团队太小气,玩家受挫折,就不再会回来了

干掉拍卖行

设计上,拍卖行对于diablo的伤害逐渐清晰,但是大家在当时,对于暴雪这样的公司,去承认去纠错应该还是有难度的。

这里更多的是一个人事的问题,一次关键上,大家讨论这个问题,同时总裁也在,josh知道这个时候可以说一些冠冕堂皇的正确的废话,来搪塞过去,但是还是大胆的说出了自己的看法,就是要干掉拍卖行。

最后大家都一致的认为如此了。

故事看起来很简单顺利,但是话说回来,这种否定,如果不是josh当时一莽,提了出来,或许大家还是在各种不痛不痒的做一些优化,大家还是去shopping而不是去杀怪的。


总结

最后josh总结了关键的东西:

  • 务必明确游戏的核心要素,否则就是被各种“有道理”的设计带的东倒西歪
  • 了解你的恐惧,团队处于一个diablo2的成功阴影之下,你是做不了好东西的
  • 随机和可复玩性的区别(或者叫做问题的本质和深度本质的区别)
  • 团队才决定质量的关键

misc

console只是一个尝试,大家也是看看能不能做出来,做出来看看怎么样。

但实际上,josh刚刚加入团队,事实证明他也是一个很有能力的人,很想做真正牛逼的东西。

所以这也促成了,在console上,以新的视角,重新看待diablo的核心要素,调整设计,所有的这些,构成了《夺魂之镰》资料片的基础。


<think>我们面对的是编译时出现的未定义引用错误,涉及以下符号: 1. `ara::core::Initialize` 2. `apf::osa::OsApi::strlen` 3. `apf::osa::OsApi::getenv` 4. `apf::osa::OsApi::time` 5. `apf::osa::OsApi::exec_tool[abi:cxx11]` 这些错误通常发生在链接阶段,表明链接器无法在提供的库中找到这些符号的定义。以下是解决步骤: ### 1. 确认库依赖和链接顺序 首先,确保包含了定义这些符号的库,并且链接顺序正确。链接器按照从左到右的顺序解析符号,因此基础库应放在依赖它们的库之后。 例如,如果`libA.so`依赖于`libB.so`,则命令行中`libA.so`应出现在`libB.so`之前: ```bash g++ ... -lA -lB ... ``` ### 2. 查找缺失符号所在的库 使用`nm`或`objdump`工具在可能的库中搜索这些符号。假设我们知道这些符号可能存在于`libara_core.so`和`libapf_osa.so`中,则可以: ```bash # 查找ara::core::Initialize nm -gDC libara_core.so | grep "ara::core::Initialize" # 查找apf::osa::OsApi相关的符号 nm -gDC libapf_osa.so | grep "apf::osa::OsApi" ``` ### 3. 检查库版本和兼容性 如果库存在但符号未找到,可能是由于: - **库版本不匹配**:编译时使用的头文件与链接的库版本不一致。 - **ABI不兼容**:特别是C++符号,不同编译器或编译选项可能导致名称修饰不同。注意`exec_tool[abi:cxx11]`表明该符号使用了C++11 ABI。 ### 4. 解决`exec_tool[abi:cxx11]`的ABI问题 `[abi:cxx11]`后缀表示该符号使用了新的C++11 ABI(由GCC 5.1+引入)。如果编译时使用了新旧ABI混合,会导致此错误。解决方法: - **统一ABI**:确保所有依赖库和当前项目使用相同的ABI。对于GCC,可以通过定义宏控制: ```c++ #define _GLIBCXX_USE_CXX11_ABI 1 // 或0,需与依赖库一致 ``` - **重新编译依赖库**:如果依赖库是用旧ABI编译的,而项目使用新ABI,则需重新编译依赖库并指定相同的ABI[^2]。 ### 5. 验证运行时库路径 如果编译链接通过,但运行时出现未定义符号,需确保动态链接器能找到正确的库: - 使用`ldd`检查可执行文件的库依赖: ```bash ldd ./your_executable | grep -E &#39;ara|apf&#39; ``` - 若库不在标准路径,可通过`LD_LIBRARY_PATH`添加: ```bash export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH ``` ### 6. 示例解决方案 假设缺失符号在`libara_core.so`和`libapf_osa.so`中,编译命令应调整为: ```bash g++ -o your_program main.cc -L/path/to/libs -lara_core -lapf_osa ``` 若库文件不在标准路径,需通过`-L`指定搜索路径。 ### 7. 检查头文件包含 确保源代码中包含了正确的头文件: ```c++ #include <ara/core/init.h> // 假设ara::core::Initialize在此 #include <apf/osa/OsApi.h> // 假设apf::osa::OsApi在此 ``` ### 8. 重建项目 如果依赖复杂,考虑使用构建系统(如CMake)管理依赖: ```cmake cmake_minimum_required(VERSION 3.10) project(YourProject) add_executable(your_program main.cc) # 链接库 target_link_libraries(your_program PRIVATE ara_core apf_osa ) # 指定库路径 target_link_directories(your_program PRIVATE /path/to/libs ) ``` --- ### 总结步骤 | 步骤 | 操作 | 命令/方法 | |------|------|-----------| | 1 | 确认库包含和链接顺序 | 调整`-l`顺序,基础库在后 | | 2 | 搜索符号定义 | `nm -gDC libXXX.so \| grep "symbol"` | | 3 | 检查ABI兼容性 | 统一`_GLIBCXX_USE_CXX11_ABI`值 | | 4 | 验证库路径 | `ldd`,`LD_LIBRARY_PATH` | | 5 | 包含正确头文件 | 检查`#include` | | 6 | 重建项目 | 使用构建系统管理 | --- §§相关问题§§ 1. 如何在CMake中指定C++11 ABI兼容性? 2. 如何查看动态库导出的符号列表? 3. 运行时出现`undefined symbol`错误与编译时有何不同?如何解决? </think> ### 解决编译时未定义引用错误指南 您在编译过程中遇到的未定义引用错误(undefined reference)表明链接器无法找到以下符号的定义: ```plaintext ara::core::Initialize apf::osa::OsApi::strlen apf::osa::OsApi::getenv apf::osa::OsApi::time apf::osa::OsApi::exec_tool[abi:cxx11] ``` 这些问题通常由库依赖或链接问题引起,以下是系统性的解决方法: --- ### 1. **确认依赖库是否包含这些符号** 使用 `nm` 命令检查相关库文件: ```bash # 检查 ara::core::Initialize nm -gC libara_core.so | grep "ara::core::Initialize" # 检查 apf::osa 相关符号 nm -gC libapf_osa.so | grep "apf::osa::OsApi" ``` - 如果输出中符号前有 `T`(已定义),说明库包含该符号 - 如果是 `U`(未定义),说明该库也依赖其他库 - **无输出**表示库中不存在这些符号 --- ### 2. **解决库链接问题** #### (1) 确保链接正确的库 在编译命令中添加缺失的库: ```bash g++ -o output main.cc \ -L/path/to/libs -lara_core -lapf_osa \ # 核心库 -lapf_os_specific \ # 可能包含OSApi实现 -lc -lstdc++ # 标准库 ``` #### (2) 检查链接顺序 调整链接顺序(依赖库放在右侧): ```bash # 正确顺序:被依赖的库在右边 g++ main.o -lara_core -lapf_osa -lapi_impl -lc ``` #### (3) 验证ABI兼容性 对于 `exec_tool[abi:cxx11]` 这类C++11 ABI问题: ```bash # 在编译命令中添加ABI标识 g++ -D_GLIBCXX_USE_CXX11_ABI=1 ... ``` 统一所有依赖库的ABI版本(0为旧ABI,1为新ABI)[^2]。 --- ### 3. **检查库版本兼容性** 不同系统版本的库可能导致符号缺失: ```bash # 检查库的GLIBC依赖 objdump -T libapf_osa.so | grep GLIBC # 对比开发环境与目标环境的兼容性 ldd --version ``` - 如果出现版本不匹配(如 `GLIBC_2.27` vs `GLIBC_2.23`),需在Ubuntu 16等低版本系统上重新编译库 --- ### 4. **完整解决方案流程** 1. **定位符号来源**: ```bash find /path/to/libs -name "*.so" -exec nm -gC {} \; | grep "OsApi::strlen" ``` 2. **添加缺失库路径**: ```bash export LD_LIBRARY_PATH=/correct/lib/path:$LD_LIBRARY_PATH ``` 3. **重建依赖关系**: ```bash sudo ldconfig ``` 4. **验证修复**: ```bash ldd your_executable | grep -E &#39;ara|apf&#39; nm -gC your_executable | grep "Initialize" ``` --- ### 常见问题排查表 | 错误类型 | 可能原因 | 解决方案 | |---------|----------|----------| | C++ ABI问题 | 新旧ABI混用 | 统一 `_GLIBCXX_USE_CXX11_ABI` 值 | | 版本不匹配 | 高版本库在低版本系统使用 | 在目标系统重新编译库 | | 路径错误 | 库未在链接器搜索路径 | 添加 `-L/path` 和 `-Wl,-rpath=/path` | | 名称修饰 | C++符号修饰不一致 | 使用 `extern "C"` 或统一编译器 | --- ### 示例编译命令(完整版) ```bash g++ -std=c++17 -D_GLIBCXX_USE_CXX11_ABI=1 \ -I/path/to/include \ -L/path/to/libs -Wl,-rpath=/path/to/libs \ -o hmi_app main.cc \ -lara_core -lapf_osa -lapf_os_impl -lpthread -ldl ``` > **关键参数说明**: > - `-Wl,-rpath`:设置运行时库路径 > - `-D_GLIBCXX_USE_CXX11_ABI=1`:统一C++11 ABI > - 库顺序:被依赖的库放在命令右侧 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值