《大型多人在线游戏开发》读书笔记

原作名:《Massively Multiplayer Game Development》 – Thor Alexander

一、MMP设计技术

【卡通城OL:面向大众的MMO】

  1. 游戏设计问题:
    • ①孩子家长也必须是销售对象 – a.儿童成人都喜欢; b.借助信赖的品牌; c.角色共通; d.可与家人分享;
    • ②允许有冲突但是须禁止暴力 – a.取消玩家对战; b.工作和娱乐的冲突; c.卡通式战斗; d.机器敌人; e.笑槽;
    • ③太多选择会让玩家无所适从 – a.指南(单人,互动,多人); b.任务(明确目标,提供故事线,多种升级系统提高趣味);
    • ④玩家希望立即享受游戏乐趣 – a.下载时插播游戏要素/背景故事; b.创建角色(定制); c.瞬间移动;
    • ⑤众人面前普通玩家惧怕失败 – a.确保成功; b.观看战斗; c.强调团队合作; d.新手老手一起游戏;
    • ⑥复杂的系统令玩家不知所措 – a.避免用数字描述状态(优先图); b.适当的冗余信息; c.背囊有限; d.合并并统一界面; e.避免不合理的按键; f.使用熟悉的界面; g.隐藏不必要细节; h.让探索充满乐趣; i.不要过于简单;
    • ⑦玩家通常只会玩一小段时间- - 明确的目标可以节约时间;
  2. 社会性问题:
    • ①受众对”捣乱”容忍度很低 – 捣乱(指以降低游戏完整性,在游戏中反复骚扰其他玩家的行为);
    • ②玩家无法容忍那些在现实生活中也会发生的社会问题–比如贵重物品被非法转移等;
    • ③家长不放心孩子上网 – a.提供安全的交流形式(基于菜单的聊天系统); b.现实朋友的私密聊天(48小时秘钥聊天频道);
    • ④与社会特性不一致 – a.永远不要阻止朋友; b.社交(群组友好,聊天泡泡); c.合作性迷你游戏;
    • ⑤刚开始游戏会害羞 – a.轻量级群组(任务临时队伍); b.打破沉默; c.共同的目标; d.朋友列表;
  3. 轻量级RPG经验:
    • ①让玩家可立即享受游戏带来的快乐 – 比如游戏最初,游戏指南带入一场战斗;
    • ②避免强迫玩家对不了解的事物进行选择 – 比如最初角色选择与游戏职业/能力分离;
    • ③地理布局应该完全由游戏模式决定 – 比如矿洞挖矿, 码头池塘钓鱼, 空地地标玩家聚集;
    • ④每次进行游戏的时间应该较短 – 比如3小时大任务分解成子任务,增量进行;
    • ⑤允许并鼓励玩家成为观众 – 比如观战;
    • ⑥相比独立做任务,团队合作更有意义 – 尽可能鼓励合作,加强玩家联系;

【每个人都需要某个人:怎样让玩家合作】

  1. 让玩家合作的缘由:
    • 降低系统开销 – 假设可承受3000并发玩家,不合作需处理3000个AI,反之,3人/队则只需提供1000个并发AI;
    • 使游戏更富于变化 – 使玩家能自行创造快乐会延长游戏生命周期,并带动朋友家人加入分享快乐;
    • 使玩家建立起牢固的社会关系从而不愿停止游戏;
  2. 玩家非必须下不会自主合作:
    • 合作游戏多数情况回报更高,但别错误地去掉所有单独游戏的机会,OL中有很多内向的人,占比超过现实比例;
    • 创建一系列不同的任务,它们中一部分适合独立游戏,另一部分适合玩家合作,这些任务最终提供了一个合作性的社会环境;
    • 示例: Ultima Online(矿工,炼金等职业任务是搜集并提供冒险物品,可独立完成;同时,通过市场/NPC代卖与其他玩家进行合作);
  3. 角色扮演是主流:在玩家可以提供独特功能时合作最为有效;
    • 人们参与MMP游戏是因为这些游戏可使他们获得成功,而所花时间比真实世界短很多[从心理学角度来说,这极具吸引力];
    • 游戏中成功的定义非常多 – 使玩家具有独特功能,每种功能都可用来满足一类基本的个性化需求,并有助于满足其他玩家的需求;
  4. 功能提供模式:
    • 预先定义 – “角色分类”(游戏加入很多特性使每种职业有各自的特色,并在合作中提供关键技能);
    • 功能定义 – “基于技能”(游戏角色可学习掌握任何技能,但只擅长练习最多的技能,应提供技能指导和搭配建议);
  5. 为游戏角色提供挑战:
    • 设计游戏内容不断地支持并加强各类型功能,只有组合各类型功能,才能发现和征服游戏中的每一个挑战;
    • 挑战,应让不同角色可按照不同策略来组合征服,避免唯一方法导致缺少必备技能玩家而无法征服;
    • 不要把角色设计得只能少数情况下使用,而应在不同情况下都有用,避免功能太窄而缺少意义;
  6. 保持功能的完整性:
    • 拓宽功能时,小心保持每个角色在游戏世界黑暗能地位的完整性,避免削弱某类职业的价值;
    • 不应该让某一类角色担当完成游戏中唯一类型的关键先生;比如死亡复活,牧师复活比跑尸复活装备掉更少耐久.
  7. 帮助玩家彼此找到对方:
    • 视觉区分 – 用差异化的原型/装备区分职业,便于玩家更易寻找;比如在餐馆,我们会方便的找到穿着制服的服务员;
    • 节点区分 – 创建可满足某种玩家共同需要的场所,比如拍卖行/教堂/广场,用于交易治疗或聊天;
    • 功能界面–例如冒险小组可通过组队UI,搜索特定职业设置为空闲的玩家;
  8. 帮助玩家进行交流:
    • 在实现玩家可便捷找到对方后,提供一些工具使玩家可管理彼此间的交互;
    • 简化交流方式 – 比如战略游戏提供某种界面便于发出简短命令来协调行动;
    • 交流不止于交谈 – 比如贸易系统; 比如玩家门口放置商人NPC售卖物品; 比如无主之地中的频死状态闪烁提醒;

【游戏平衡】

  1. 为游戏中的数值建立基线:从项目中的核心系统开始,比如战斗系统;
  2. 为数值编写模拟程序:简单地获取用户输入的数据,使用一些原型系统算法对他们进行处理并显示结果; [程序示例见P25];
  3. 建立游戏中的度量:对所关心的游戏数值进行长期(按天、月、年或特定时间段进行维护)跟踪和记录; 项目中期;
    需跟踪的因素:
    • 玩家升级 – 统计玩家升级情况,确定游戏进展是否符合预期速度;
    • 物品使用 – 统计物品使用频率如武器挥砍次数/装甲穿着时间,一般使用频率高的物品更强反之较弱;
    • 动作行为 –了解玩家在游戏中的时间究竟花在了哪里,是打怪还是制造?比如治疗是战斗时间的两倍,则需提高治疗效果;
  4. 内部和外部测试:仅当测试玩家数量接近正式运营期望值时,才可能对游戏进行正确的平衡调整; 封测是无痛测试平衡性的最后机会;
    观察玩家动作:
    • 玩家对物品/技能/动作的偏爱,升级速度等;
    • 注意力放在异常数据,比如过快的升级速度/大量财富; 游戏数据/行为异常通常可指出平衡中的错误;
    • 用心观察那些玩家花费大量时间的地方; 增加难度或缩减难度;
  5. 发布后对游戏进行平衡:
    • 如果某个修改对某些玩家不利,很可能导致他们离开游戏;
    • “相对于修复,保留这个失衡的地方是否会导致更多的问题” – “是”,那就应该修改;
    • 在修改前将问题告知玩家,并解释该失衡会对游戏的造成的危害;并尽可能补偿受影响玩家;
    • 提供论坛,便于玩家提供建议或看法;
  6. 对新功能进行平衡:
    • 即使加入非常小的功能,在和其他功能相互作用后都可能带来严重后果;须广泛测试避免失衡;
    • 建立测试服,鼓励玩家访问并使用它,这样,设计人员可安全地调节数值,降低发布后不良影响的可能;

【用支付矩阵来设计游戏平衡和AI】

  1. 支付矩阵:博弈论概念,表示博弈中两个或多个参与者在做出不同决定时的收益和损失;
  2. 囚徒困境:
    图1.8.囚徒困境支付矩阵

    简单的格斗游戏及其纳什均衡:
    图1.10.怎样达到纳什均衡状态的有向支付矩阵

  3. 延迟和停止:定义每个状态所需最少和最多时间,然后为每个状态添加一个转换表,显示该状态完成后可进入哪些状态;

  4. 自动化:
    • 自动化的矩阵测试; 记录模拟/游戏中的战斗日志;
    • 选定敌对者后识别他们可选的动作列表建立矩阵,对当前合法的目标状态进行估价后选则新状态,从而构造复杂的AI系统;
    • 估价函数是该AI系统复杂的部分,它必须考虑AI的当前状态及每个合法行为的支付;
    • 要在选项中做出选择,加权随机数可用来创建一个简单的[模糊逻辑系统];

【使用用例来描述游戏行为】

  1. 用于设计人员和程序员之间进行关于游戏需求的交流,把游戏设计中的创造性思想系统地映射到一个技术性的设计模型上;
  2. 每个用例代表了一个离散的行为单元,它具有定义清晰的作用域、清楚的步骤以及明确的前提条件和后置条件;
  3. 识别用例:
    • 角色:展示行为的实体; 角色通常位于系统的外部; 比如玩家角色(PC)、NPC、怪物;
    • 事件:需识别出产生事件的对象,并为每个事件提供一句话的描述;
    • 规则:一个事件是一件单独的事情;一个事件可以用一句话简单地描述;
  4. 用例中的元素 – 一个标准模板:
    图1.14.用例标准模板
  5. 用例模型图:
    • 为系统的作用域提供可视化表示;
    • 识别用例之间的关系;
    • 有助于重构和组织相关的用例来进行子系统设计;
  6. 开始实现:不建议从用例直接编码,而是在用例基础上建立更充实的设计模型(特别是序列图);
    • ①序列图 – 使开发人员有机会能更详细地考察类接口和对象互动,随着对对象和方法进行详细说明,可逐渐建模一个类结构;
    • ②候选抽象概念 – 确定宿主结构; 第一步,识别用例步骤中的名词,将候选的抽象概念具体化为类、数据结构或重要属性;
    • ③对抽象概念的分析 – 例如武器抽象:
      • 武器等装备与其他类物品有何不同?
      • 是否不能装备某些其他物品?
      • 是否每个装备了的物品都可以作为武器使用?
      • 为了让模型更简明,排除那些不会成为类、数据结构或属性的候选抽象;
    • ④开发一个类结构 – 通过研究候选对象,帮助建立游戏的结构视图;
      随着编写更多的用例,游戏的行为和结构建模将更为充实;
  7. 用例的指导方针:
    • 描写待解决的问题,而不是解决方案;
    • 迭代–用例是探索工具; 从一个与其他未实现的子系统依赖很少的子系统开始,尽可能实现,接着编写相关子系统用例;
    • 面对面的合作–设计文档很重要,但程序与设计的沟通与合作更重要;
    • 不要指望用例可以捕获所有需求 – 例如安全、性能、延迟、运行期支持(行动报告/客户支持调停)等无法构建用例;
    • 交流 – 在向团队领导、制作人、计划经理及其他团队成员描述正在开发的游戏时,作用巨大;
    • 避免线性思考 – 刻板坚持第一印象会遗漏重要的游戏需求或识别出无效需求;
    • 不要过于强调工具 – 超大型项目可能从某些工具受益,但多数情况会成为负担,最后造成放弃用例;
    • 把重点放在清晰的交流上而不是格式上;
    • 避免把注意力集中在客户端服务器细节上–比如哪个操作服务端执行,哪个在客户端执行等;
    • 把游戏和UI分离开 – 用例不应关心UI交互,比如按哪个键/菜单会导致某某行为; UI是UI,游戏是游戏,要分离,各自进行用例描述;
    • 不要强求完全覆盖 – 比如网络、数据库、进程管理等技术早已被实现者良好理解的,不需强求建立用例;

【使用生命值来设计转换因子】

  1. 根据物品造成/治疗伤害的能力为其赋予适当的价值,并以此为基础,确定游戏经济系统中大多数物品的价值;
  2. 武器的价值:
    • 根据武器损坏/可使用前所能造成的所有伤害来决定其价格,而不只是把价格建立在其造成伤害的速度上;
    • 假设一枚货币等价于一点生命值,该基础值可在以后调整;
    • 价值 = 攻击次数 * (损坏后的平均攻击力 + (全新时的平均攻击力 - 损坏后的平均攻击力) / 2)
    • 修复价格 = 基本成本 * 损坏百分比的平方 (鼓励玩家尽早修复武器,越晚越贵)
  3. 治疗、防具和减轻伤害:直接把生命值大小映射到货币就可确定它们的价格;
  4. 从NPC获得的战利品:
    • 战利品价值 = (玩家武器的损坏 + 玩家防具的损坏) ; [统计角度]战利品价值 = 2 * 玩家武器的损坏;
    • 总损坏量决定战利品参考价值,即每个怪物平均会带多少战利品; 或者,知道怪物战利品和减伤效果,即可确定其生命值是多少;
    • 玩家武器的损坏 = NPC受到的伤害 + NPC防具的损坏; 战利品价值 = 2 * (NPC受到的伤害 + NPC防具的损坏);
  5. 制造业:
    • 游戏中若有贸易功能并且允许玩家制造武器,就应鼓励玩家使用制造技能;
    • 部件价格之和不能超过武器价值,否则玩家不会去制造它们;部件价格也不可远低于武器价值,否则成了印钞机,破坏经济系统;
    • 必须确定玩家通过制造物品并且用低于NPC商人的价格出售可获得的最大利润,得到这个值后,就可确定部件的组合价值;
    • 如果发现部件成本太低,可通过增加制造过程中的人力成本来进行调整;
  6. 无关物品:
    • 有些物品与治疗/伤害毫无关系,可借助已知物品来得到与其他数据一致的价格;
    • 一旦对某个新物品类型中的某些物品初步定价后,就可通过配方把这些物品关联起来以保持它们彼此间的一致性;
  7. 校验:
    • 交易日志 – 将玩家间的交易价格和预设价格比较,如果实际交易价格有差异或交易量突然上下起伏,可得知价格制定有错误;
  8. 总结:切记一味遵循这些转换因子和定价方式; 这些只是用来帮助平衡的方法; 掌握基本思想,即可对物品价格进行各种变化;

【在MMP游戏设计中加入故事情节】

  1. 为了一个更有意义的MMP:
    • 单机游戏 – 设计需要更多的考虑故事情节、拟人化的角色交互以及为玩家的行动创建一个更广阔更有意义的环境;
    • MMP游戏 – 为一个典型RPG游戏创建40~80小时详细线性游戏经历,需要数百个月,传统单机方式不适合,需要更具伸缩性的方法;
  2. 游戏与故事情节–尴尬的结合:游戏的开放性与玩家对故事结构的期望是冲突的;
    • 游戏剧情里,玩家处于一个预定的故事结构之中,又想真正地拥有对结果的决定权,他们往往处于两者的折中中;
  3. 故事情节在游戏中的功能:
    • 故事情节为游戏提供了结构;
      1. 创造一个熟悉而有结构的切入点(日常生活中人们接触到的多数娱乐都是基于讲故事的);
      2. 创建了一个隐含的线性发展过程,利用玩家对故事情节发展的基本期望,推动故事,满足需求;
      3. 故事情节的存在保证了结局的存在 – 人们都希望在看故事的时候能够看到结局;
    • 故事情节使玩家的行动更有意义;
    • 通过把行动和“戏剧性场景”结合 – 比如为营救恋人杀6个怪物与为战斗乐趣杀死6个怪物是截然不同的;
    • 使玩家更易在游戏中投入感情 – 使玩家去关心场景,去鄙视坏人,去和英雄一起庆祝等等,把游戏中有意义的方面联系在一起;
  4. 挑战更多的认知能力:
    • 游戏能带来满足是因为玩家可以用交互方式来主动地使用各种认知能力;
    • “纯粹玩家” – 涉及认知能力有 反应、观察能力以及空间和逻辑智能;
    • “剧情玩家” – 涉及不同认知能力如 社交、叙事和情感智能;
    • 玩家更倾向于测试反应和空间能力的游戏,如《LOL》; 但《模拟人生》的成功展示了游戏也可使用和挑战玩家的社交和情感能力;
    • 当游戏中行动具有特定意义时,玩家会主动使用范围更广的认知能力;
  5. 使用有意义行动的最佳场所:
    • MMP游戏没有保存和重新开始,始终存在并持续发展,可以提供独一无二的“真实”感觉;
    • MMP游戏特别之处就是让玩家在(以身体、情感、社交等方式)做出行动时能被别人看见;
    • 如果游戏中唯一有意义的行动是机械的角色升级,那么玩家无法成为英雄或坏人,也就无法归属于这个世界;
  6. 为MMP游戏模式加入故事情节:
    • 在那些具有进展的游戏元素中加入故事情节 – 比如角色升级;
    • 通过创建背景来建立一些游戏世界中的戏剧性场景 – 为游戏行动建立上下文从而使行动自身成为一个逐渐展开的故事;
    • 创造机会让玩家卷入那些具有故事形式的公众事件或场景中去 – 使他们具有某个共同的目标就是一个很好的例子;
    • 1.把角色升级作为故事 – 可用奖励系统来确保并加强游戏行动的故事性,回报不一定是物质的,可以是荣誉、声望、社会地位等可衡量的;
    • 2.发掘戏剧性场景 – 背景故事和游戏真正目的必须协调;
      戏剧性场景可用於单个角色、某个区域、整个游戏世界;
      为了更令人信服,戏剧性场景需”写”入游戏世界中,简单或毫无新意并不重要,重要的是行动; 比如区域对抗,立雕像;
  7. 公共目标:创造具有独特生命力的、动态而一致的游戏元素;
    • 目标 – 能根据玩家行动而变化,且未来不确定; 例如《率土之滨》历史进程与州对抗; 《魔兽世界》安其拉开门等;
    • 危机 – 需玩家长时间持续行动才能解决的动态危机; 譬如某区域产生很多敌人对一条重要贸易路径带来危险;

【客户服务和玩家声望:一切都和信任有关】

  1. 捣乱:指在游戏规则允许的范围内,故意通过一些方法来激怒、威胁或骚扰其他玩家;经常在没明显真实动机的情况下;
  2. 规则只是工具:如果不适应游戏设计的意图,再好的规则都可能会被破坏或滥用;
  3. 意图:不能单凭玩家自身的行动去猜测他的意图;
  4. 客服部门:为了解决那些开发团队无法通过游戏机制来发现或解决的问题、观察有问题的玩家、以及贯彻执行服务条款协定;
  5. 声望:1. a.一般人所能看到和判断的总体质量或特性;
    b.别人对某些特性或者能力的承认;
    2. 受到公众尊重或尊敬的地方:好名声; 比如淘宝的差评或好评;
  6. 正当行为:声望系统用来阻止尽可能多的不良行为,还可用来鼓励/奖赏游戏社区中的良好行为;
    仔细平衡良好声望的奖励是很重要的;
    1.当人们对于和别人的交互感到高兴时,应该让他们能够表达出来;
    2.以一种平衡的方式来奖励良好行为;
  7. 恶意行为:声望系统还应该能阻止恶意行为;
    1.必须给那些公认的”坏”人一些惩罚以促使他们改变或把他们从游戏社会中赶走;
    2.让玩家指控其他玩家的不良行为时,他必须小心的斟酌他的决定;
  8. 不能以封面来判断一本书的好坏,同样,对人也不能以偏概全:
    • 要判断一个玩家的好坏,不能只根据几个人的说法,而要根据他们对社会的实际影响;
    • 要根据玩家的行为模式来判断他们是不是在长期地捣乱;
  9. 行为模式跟踪方法:阿佛加多信任度量; 贝叶斯分析;
  10. 使用声望:
    • 避免把评价过程变得很麻烦,和其他功能一样,玩家需要尽快确定他们在和谁交互以及他们的感觉;
    • 要让客服部门把声望系统作为一个让游戏社区处于正规的主动工具来使用;
    1. 当玩家与另一玩家进行了一次良好交互后,这个玩家想给他的不仅是一句”谢谢你”;
    2. 当玩家与另一玩家进行了一次不好的交互后,他需要某种立即的方式来让对方及其他玩家知道他的感觉;
    3. 它允许玩家用很长时间来树立一个他们是怎样对待其他玩家或与其他玩家进行交互的真实形象;
    4. 有良好行为的玩家应该受到奖励;
    5. 玩家应该对他们的社区有真正的控制权;

【MMP体系结构】

【制作仿真框架,第一部分:结构建模】

  1. 体系结构纵览:
    • 1.客户/服务器组件 – 网络抽象层 → 分发消息数据包 → 游戏仿真层接受消息并处理,保持客户端和服务端游戏状态空间的一致性;
    • 2.通过代理仿真 – 服务端游戏仿真层保留对游戏状态空间的唯一精确表示,通过请求交互; 永远不要信任客户端对于状态空间的表示;
  2. 支持类:
    • 词典类/哈希表 – 词典类是抽象数据类型,存储按值访问的元素;
    • 仿真事件 – 系统中的事件对象,包含了事件类型、源标识、目标标识、参数以及频道(让接受者过滤只获得感兴趣的事件);
    • 仿真状态:该类是系统对状态模式实现的一种描述; 状态的基类 – CanTransition(能否转换)和Transition(进行转换);
    • 动作状态:该类标识那些典型的游戏仿真操作,譬如击打对手或打开一扇门;
    • 控制状态:定义了与它关联的行动者可以从哪里接受命令; 还可用在基于观察的训练中;
    • 用户控制状态:维护了一个等待执行的动作请求列表,这些动作由客户端发出并为服务端所接受;
    • AI控制状态:负责确定用于执行的合适动作; AI技术(有限状态机、行为树、神经网络或者模糊逻辑);
  3. 核心类:
    • 1.仿真对象类SOB:所有由仿真层处理的核心类的基类,包括Actor、Area、Item、Obstacle(障碍物);
      • 可包含其他SOB – 会维护一个内容词典(contents) 及 一个所有者标识(ownerID);
      • 联系词典links – 维护与其他对象之间的联系,提供SOB之间的聚合或”整体/局部”的关系;
      • 属性词典Property – 以数据驱动的方式存储每个对象特定于游戏系统的属性; 比如对象的位置/移动速度/生命值等;
      • 持久化机制 – 用一个通用的方式和存储系统合作; 维护dirty标识,数据变化时设置,Store定期检查进行保存或Restore;
    • 2.执行者Performer:为Actor和ActorProxy类提供了在客户和服务端共享的功能及接口;
      • 调度优先级 – 实现对调度的仿真;
      • 当前动作状态 – 标识该对象当前所执行的动作,由PerformAction(执行动作)方法确定并进行设置;
    • 3.行动者Actor:能与仿真环境进行交互的服务端SOB;
      • 控制状态 – 使其能被不同的空置房(agent)控制,包括玩家/AI或脚本驱动的过场动画;
      • eventQueue – 批量存储事件,延迟到下一次PerformAction被调度执行时一并处理;
      • ReceiveEvent – 可把需要立即处理的事件过滤出来,而不是放到事件队列eventQueue中;
    • 4.行动代理ActionProxy – 行动者在客户端的副本;
    • 5.非执行者类 – 那些不需要和仿真环境直接交互的核心类. 物品; 障碍物; 代理对象; 区域;
  4. 管理器类和工厂类:以单例模式实现; 初始化时创建直到仿真层终止;
    • 1.仿真对象工厂 – 负责创建SOB并确保他们具有独一无二的标识;
    • 2.仿真对象管理器 – 负责维护一个仿真对象的词典; 提供ID查找对象引用、保存、载入;
    • 3.调度管理器 – 调度活动的执行者仿真对象,以安排时间调用它们的PerformAction回调方法;
    • 4.查询管理器 – 为在运行时访问静态游戏数据提供了一个快速高效的机制;
  5. 仿真类:把支持类、核心类和管理类包装成一个良好的顶层接口方便管理;

【制作仿真框架,第二部分:行为建模】

  1. 把用户和行动者关联起来:
    • 服务端和客户端SOB都提供AttachUser(连接用户)和DetachUser(断开用户)的方法实现; 可实现接管玩家角色、变换玩家视角;
    • User(玩家)可被映射到服务端某个行动者实例以及与之对应的客户端行动代理对象上,SOB根据状态判断是否接受连接;
  2. 动作请求:ClientSOB → SendActionRequest → Server → ActorSOB eventQueue;
  3. 动作调度:物理层:Tick() → 服务端仿真层:ProcessTasks() → 调度管理器:PerformAction() → Actor:ProcessEventQueue;
  4. 事件广播和处理:
    • 当行动者试图进行转换时,获取控制状态对象的目标动作状态,随后检验是否可转换,进行切换或忽略;
    • 活动的SOB维护着一个订阅者词典(对其动作感兴趣的其他对象可进行登记),通过调用订阅者的ReceiveEvent方法进行通知;
  5. 服务端事件处理:当事件订阅者收到事件后,会传递给这个类型的事件所对应的事件处理程序,若该对象有用户连接,则发送给客户端;
  6. 客户端事件处理:事件消息 → 客户端 → 行动者管理器 → (创建/查找)对应的行动代理对象;
  7. 客户端代理:行动代理对象:收到消息 → 查找合适的处理程序 → 处理 → 状态转换 → 通知;
  8. 仿真与表示分离:观察者设计模式; 游戏的代理动作状态类作为被订阅对象,当状态改变时,通过自身的Notify方法,通知观察者Update;

【为游戏脚本创建一个”安全沙盘”】

  1. 脚本语言与MMP开发:
    • 网游不仅需要持续地保持可靠性,还需经常更新内容;
    • 使用脚本语言实现经常变动的内容(如任务,UI等),可在不断改进和修正的同时,保证代码的可维护和稳定性;
  2. 使用沙盘的理由:
    • 上层系统 – 游戏规则/有趣的部分,会频繁的修改(进行游戏平衡、加入特殊事件、加入新物品/技能时);
    • 底层系统 – 网络、数据库接口、物理、移动、骇客检测等,极少需要修改,且每次修改都必须非常小心;
    • 游戏编码和内容维护应当避免的做法:
      • 在正常的框架以外任意地创建和销毁游戏对象;
      • 直接控制游戏中对象的移动、位置和方向;
      • 为了适合特殊的关卡而对AI或寻路算法进行有条件的调整;
      • 绕开游戏数据库并且把游戏数据写到本地文件系统中;
      • 直接打开一个连接到其他服务端/客户端的套接字,而不是使用现有的消息系统;
      • 直接嵌入SQL来查询/更新数据库,而不是通过现有的数据更新和读取接口;
      • 向游戏客户端发送任意的文本消息;
      • 对某个现存子系统的使用与其设计目的不一致;
  3. 安全沙盘的设计:
    • 1.需限制脚本语言提供的服务,控制底层系统中哪些可用;
    • 2.安全沙盘的关键元素:
      • a.定制缺省的受限执行环境以满足游戏的需要;(比如禁用Python某些模块,用某些函数替代原始函数等);
      • b.支持对某些特定对象/属性的访问,同时禁止未经授权的访问;
      • c.包装对象和对象的属性,对其进行保护;
  4. 在安全沙盘中编写游戏代码: 无需处理权限和数据保护,沙盘框架已进行处理;

【大型多人游戏中的单元测试】

  1. 为什么需要单元测试:
    • 可在开发过程中保证代码的完整性,尤其是在整合过程中;
    • 在游戏发展过程中,它可以在成品代码中使引入错误的风险最小化;
    • 单元测试、持续代码整合、小型发布、结对编程、集体拥有代码等组成敏捷开发;
  2. 单元测试的定义:
    • 1.单元的定义 –
      • 须具有良好定义的接口且对其他单元的依赖较少;
      • 定义单元最有效的方式 – 从最底层或最基本的类开始,向系统上方进行直到高层类被定义;
    • 2.数据集的定义 –
      • 内部数据集:可直接硬编码在单元测试内以提供一/多组数据用于测试;
      • 外部数据集:从文件、数据库、套接字等单元测试代码以外的其他资源中读取数据;
      • 确保这些数据在测试时总是存在,并且在多次测试后不会改变; 保证其完整和一致!
    • 3.测试的定义 –
      • 应对所有衍生数据(根据单元状态计算出的数据)或改变单元状态的方法进行测试; 无需测试那些简单获取/改变数据的方法;
  3. 单元测试框架:
    • 使用语言对应的xUnit等测试框架;
    • 尽可能使用简单的测试方法;
  4. 测试先行的设计:
    • 在编写代码前编写测试代码 – 测试真正需要测试/可能会出错的代码;
    • 编码的步骤 –
      • 1.为一个还不存在的函数或方法编写测试代码;
      • 2.必要的话,编译测试代码; 编译将会失败;
      • 3.通过编写测试的函数或方法的存根版本(无实际功能,仅用来通过编译)来修正编译错误;
      • 4.运行测试:因功能未实现,测试将会失败;
      • 5.通过编写被测函数或方法的函数体来修正测试错误;
      • 6.运行测试:如果失败,修正代码; 如果成功,编写另一个测试;
      • 7.重复1-6的步骤;
    • 让自己成为最初的受害者 – 从使用者角度编写,是功能的作者也是设计决策的第一个受害者; 更快的理解设计决策所带来的影响;
    • 单元测试和重构 –
      • 1.辨认出那些需要重构的代码;
      • 2.编写单元测试来证明现存的代码能够工作;
      • 3.开始重构,对代码进行微笑的、慎重的修改;
      • 4.重新编译并且对每个修改运行单元测试; 单元测试将失败;
      • 5.重写测试使得它符合新的代码;
      • 6.重新运行测试,如果代码能工作,继续重构; 如果测试失败,修正新代码;
      • 7.重复1~6步骤;
  5. 使用因素:
    • 测试过程自动化 – 从代码库获取新代码 → 编译链接 → 运行所有单元测试 → 向团队报告结果; 每天测试,失败时优先修复;
    • 独立的测试程序 – 使用独立的可执行程序以批处理方式调用所有测试,每当代码有新测试加入,自动加入,并可生成报告发出邮件/网页;
    • 集成的运行时测试程序 –
      • 在运行环境中执行测试,单元测试可对宿主进程提供的资源进行访问;
      • 不要让对测试框架的调用破坏产品代码;
      • 调用点应只有一行代码,用来调用一个函数(测试识别、初始化、执行和报告等)以启动测试过程,这样就可通过条件编译选项去除该函数;
    • 测试异步执行的代码 – 关键点就是要在被测试代码执行的同时强制单元测试等待异步代码执行完; 系统函数或测试包含主循环;

【使用Twisted框架进行MMP服务整合】

【Beyond 2:构建虚拟世界的开源平台】

【使用并行状态机来创建可信的角色】

  1. 状态模式:利用多态为同一个对象的不同状态定义不同的行为;
  2. 并行状态层:若某个功能与某一层中其他功能只能以互斥的方式执行,就放入该层中;而可独立或并发执行的功能则放入不同层次;
    • 移动层:处理角色在游戏世界中移动相关的问题; 停止 - 前 - 后 - 左 - 右等移动状态;
    • 姿势层:(下半身行为)处理角色在移动时的外观; 站立 - 坐下 - 步行 - 跑步 - 坠落 - 游泳 - 骑马 - 平躺; 用途:
      • a.通知动画子系统什么时候该改变这个角色正在播放的动画;
      • b.接受或拒绝用户界面提出的状态改变请求;
    • 行动层:(上半身行为)处理角色可以进行的各种行动; 空闲 - 制造 - 施法 - 战斗 - 做手势 - 出生;
  3. 状态管理器:维护了每个状态层当前状态的引用 – 当前行动状态、当前移动状态、当前姿势状态;
  4. 跨层阻止:多数情况每层的状态可独立于其他层次执行,但总有例外,比如设计玩家处于空中时无法做出任何行动;
    • 实现 – 在移动抽象层增加blocked布尔变量,通过Block和Unlock方法设置或清除; 状态转换时判断blocked,为真表示不可转换;

【使用观察者/可观察者设计模式】

  1. 观察者和被观察者:
    • 一个被观察者对象具有其观察者的引用集合;
    • 当被观察者对象被修改时,调用所有观察者的Touch()/Update()方法通知它们;
    • 当观察者要获得被观察者对象的状态时,首先检查该对象是否已被修改,然后查询被观察者内部状态并更新自己的内部状态;
  2. 基本结构:
    • 该设计模式可使客户端和服务端使用完全相同的类;
    • 在服务端,对仿真观察并把检测到的改变传到客户端;然后客户端使用同样的仿真对象并使用一个图形观察者来观察它们;
  3. 服务端架构:
    • 由仿真对象、相应的通讯观察者以及通讯管理器组成;
    • 更新消息 – 服务端循环处理所有的仿真观察者,如果某个观察者被标记为脏,就查询其内部状态以获得一个将要发送给客户的更新缓存;
      服务端保留该缓存,并生成一个包含了观察者标识的修改消息,让通讯管理器发送,客户端接受消息后,进行同步处理;
    • 创建消息 – 服务端创建新的仿真对象 → 创建对应的通讯观察者并挂接到通讯管理器 → 发送类标识和对象标识 → 客户端接收后创建 → GUI;
    • 删除消息 – 根据观察者标识 → 销毁对应的所有观察者并从通讯管理器中移除 → 向所有正在监听的客户发送删除消息 → 销毁;
    • 新客户消息 – 当新客户订阅仿真时,必须先接收仿真中所有对象的创建消息;
      传输时基于优先级,最高的最先被更新,其次下个循环再更新,防止占用大量带宽引起性能问题;
  4. 客户端架构:
    • 由仿真对象、相对应的图形观察者和一个通讯控制器组成(处理方针对象的创建、修改、删除);
    • 每个仿真对象实现了可控制接口,用来解包服务端发来的消息并且更新它们的内部状态;
    • 创建消息 – 获取类标识 → 控制器获取相应类型 → 创建具体控制器类 → 加入映射 → 后续消息即可被发送给正确的实例了;
    • 更新消息 – 通讯控制器 → 获取标识映射到的对象实例引用 → 更新缓存发送给对象 → 对象的Unpack(解包)方法处理;
    • 删除消息 – 销毁相应的可控制对象(析构函数应销毁所有的图形观察者),并删除所有对它的引用;
  5. 增强:
    • 差别观察者 – 当某个属性改变时,必须用属性索引/标识调用Update(),而后只打包被标记的已修改内容,达到节省带宽的作用;
    • 每个连接一个观察者 – 低速接收者积累一段时间的数据后调用SendChanges(),高速接收者每帧发送改变;
      为所有观察者建立一个在独立线程中运行的公共队列来避免通知延迟;
    • 优先级和视野 – 只发送客户视野范围内对象的更新;
      游戏系统需实现一个方法来检查某个对象是否在给定客户的视野(九宫格/十字链表等AOI);

【服务端开发】

【无缝服务器:优点和缺点】

  1. 杀死怪物不止一个方法:
    • 1.分割物理和游戏计算 – 把检验角色移动、碰撞等物理空间计算与游戏部分分离,并使用独立服务器处理;
    • 2.让AI独立运行 – 把AI分离到独立服务器中,缺陷是AI通常依赖玩家角色等游戏对象属性,需要对数据进行复制,带来明显的同步问题;
    • 3.“暴力”方法 – 使用更强大的服务器; 使用多线程;
    • 把游戏世界分割为更小的部分伸缩性更好,同时便于在不影响当前服务器负载的情况下添加更多的游戏内容(比如新大陆);
  2. 无缝世界模式的原型:
    • 分割游戏世界 – 二维或部分三维游戏可按照网格划分; 对于那些真正的”6度空间”仿真游戏来说,八叉树等方式细分空间更适合;
    • 平均分配 – 相邻区域的共享边界,最小应与客户端的游戏世界或玩家的可感知范围一样大,再小会造成视野差别;
    • 详细的代理对象还是精确的代理对象(两者不可兼得) – 边界区域中的对象可跨越服务器边界进行交互;
      • 当对象进入边界区域时,所在服通知相邻服,使其创建代理对象来表示远程对象;当其从边界移至邻服”内”时,该代理对象将被销毁;
      • 代理对象需提供多少信息 – 必须包含位置、方向及对象类型等基本属性; 对象属性赋予优先级,尽快或延迟更新;
    • 定义边界线 – 当对象越过”刚性”服务器边界时,它的所有权会立即转移给邻服,没任何延迟; “柔性”在转移前只允许”略微跨越”边界;
    • 静态或动态边界 – “静态”不可变; “动态”根据负载(玩家数/AI数)调整边界,必须通过一个原子事务低延迟的把一组对象整体转移;
  3. 无缝世界模式的有点:
    • 拥有更大的游戏空间 – 而分区游戏区域大小受限於单个服务器所能处理的玩家数量; 一个更大的游戏世界与更好更有趣的游戏无必然联系;
    • 可伸缩性和可靠性 – 动态平衡调整以适应不断增加的负载; 静态亦可停机时根据玩家数量和分布调整;
    • 不确定的边界线 – 错误常与服务器间来回移动数据有关,动态不确定的边界可降低玩家对这些错误的滥用行为,但错误必须找到并修正;
    • 不需要载入地图 – 载入操作会被平摊到游戏世界每一个分块,仅在需要时才会被载入;
  4. 无缝世界的缺点:
    • 不确定法则:不仅仅是客户端 – 每个玩家有自己的视野,多人游戏必然引入不确定性,而客户端必须对其进行处理(航位推测法);
      服务端代理对象不可能和其对应的真实对象完全同步,交互需通过异步处理,而缺乏同步是很多错误的根源;
    • 对设计的影响 – 系统复杂会出现大量竞争和失败问题; 这会直接导致开发周期延长/使游戏更不稳定;
    • 示例:给一个物品 – 详细见P182事件序列; 复杂度是单服操作的好几倍;
    • 构筑游戏世界/美工 – 地形建模、贴图绘制、对象放置等,分块操作,整合等需特别小心处理; 尺寸需小于边界大小;
    • 运营和扩展 – 常见问题为”物品复制”,根本原因是竞争条件,代理和相应的对象不能保持完全同步会导致大量”失效状态”错误;
    • 对额外的复杂度处理失当 – 比如只支持同服玩家交易,会暴露边界,为更多的游戏侵入行为打开大门(比如反复跨服休整后打BOSS);

【服务端对象的更新频率】

  1. 视觉连贯性与精确度:目标是视觉和感觉上都很好,即使牺牲一小部分视觉精确度; 指导方针是”如果玩家发现不了,那就不要紧!”
  2. 需要发送哪些数据:
    • 环境变化 – 极高的优先级; 不一致会造成大量碰撞和同步问题,环境数据应包含打开/关闭的门及旋转风车等循环移动等;
    • 玩家之间/玩家与NPC的交互 – 战斗信息至少需要和环境变化一样及时; 交易聊天等可略微延迟;
    • PC和NPC的移动 – 服务端必须以足够高的频率发送其移动信息,保证玩家视觉上感觉是连贯的;
  3. 带宽限制:
    • 更新频率 – UDP包头28字节,TCP包头72字节; 频率高会使包头部分消耗额外带宽; 频率低会加重视觉上的跳跃和偏差感,丢包影响大;
    • 分区的地形和连续的地形 – 分区地形会自动为最远范围赋予上限,连续地形中需使用额外代码确定界限;
  4. 每个用户在服务端需要的数据:每个玩家在服务器上都应有一个发送队列和位置列表(包含最近几次发送更新时玩家的位置),且长度相同;
  5. 管理数据的大小:应建立某种机制将游戏环境划分成区域,在这些区域中可方便知道某个特定玩家的视野中有哪些玩家(比如九宫格AOI);
  6. 更新队列:玩家发送队列由一系列时间槽组成循环队列; 循环更新(比如位置)发送后移动到特定槽(控制频率),一次性更新(比如聊天)发送后丢弃;
  7. 缺省的更新频率:近距离物体频繁更新,远距离放缓更新;
  8. 计算范围:
    • 精确的范围计算需要大量CPU时间 – 等式3-1(P190);
    • 可用曼哈顿距离等方法近似处理 – 等式3-2; 可计算出从一点走到另一点时所需经过的正方形街区数;
    • 得到近似距离并知道最大的可视范围,即可通过线性函数计算出更新应置入哪个时间槽中;
  9. 调整优先级:
    • 长时间保持静止的PC和NPC,服务端可以一开始就发送位置,之后偶尔更新以防数据包的丢失;
    • 处于同一群组的玩家 或 被选为目标的PC/NPC,应提高更新频率; 这表示玩家想要了解目标更多信息;
    • 根据玩家过去的位置列表调整 – 比如停留超过几秒则调低频率, 直线奔跑可预测中等频率, 不规则转向或移动使用更高频率;
  10. 调整队列:若玩家优先级调整突然发生很大变化,应在队列中加入一个新的更新(一次性的);

【MMP服务器开发和维护】

  1. 正在使用什么服务器:让系统的每个组件都向与它连接的其他组件报告版本;
  2. 应该和谁建立连接:将可连接的服务器等信息集中放在一个随时可访问的地方比如一个网页上;
  3. 怎样才能知道角色出了什么问题:
    • 服务端应尽可能向客户端提供精确有用的出错反馈,比如错误代码;
    • 让用户可看到服务器日志或日志的某些合理部分,比如使用服务器进程日志网页;
    • 不断监视所有服务器 – 用脚本周期性检查可能问题,比如网络、进程、内存等问题,并转发给开发团队;
  4. 对复杂度进行管理:
    • 分支:
      • a.坚持使用命名规范(包含”Dev”),所有测试服都必须进行相应的命名;
      • b.为开发服务器和运营服务器建立独立的环境,不要交叉;
      • c.应使用一个自动构建系统来进行每日构建和用于检查的构建;两台独立电脑来构建运营和开发版本;
    • 共享代码 – 服务端和客户端怎样构建?是否相同的OS构建?是否相同OS和硬件环境下运行?
      客户端和服务端代码共享还应考虑是否隐藏了服务端内部实现;

【使用Python进行精确的游戏事件广播】

  1. 事件驱动编程:和线程相比,事件是非抢占式的,只在调用时才执行,且持续执行直到任务完成;
    • 同步和异步调用 – 同步(阻塞)调用在执行完前不会把控制权返回给调用者; 异步(非阻塞)调用立即返回,独立于调用者的执行而继续执行;
    • 并发模拟 – 通过把玩家的请求分解成原子操作,在每个游戏循环里依次处理,因完成时间短,会制造出并发处理的假象;
    • 高级游戏事件 – 比如游戏世界中的物品、其他玩家或是关键的游戏系统进行交互; 底层(网络/物理/碰撞)则可提供钩子;
    • 游戏服务端主循环 – (WaitForRequests() → ProcessRequests()); 请求包含客户端玩家请求/游戏某次循环的异步调用;
    • 事件和线程并不是互斥的 – 主线程游戏循环,其他线程对网络消息等进行处理,通过一个队列放入取出请求;
  2. 延迟调用:使用请求的方式来对函数或者方法进行调用,从而使它们可以在未来的某个时间被处理;
    • 6个主要元素 – a.调用的目标对象; b.调用本身; c.调用的参数,必须符合形参列表; d.调用的执行时间,这必须是将来的某个时间; e.当延迟调用完成后所调用的回调函数; f.回调函数的参数;
    • 延迟调用接口 – Call(target, call, args, delay, cb, cbArgs);
    • 延迟调用的实现 – a.延迟调用必须能被缓存在某种类型的容器里,并可在以后取出; b.延迟调用不能在期望的执行时间之前执行,若安排在同一时间,则依据FIFO(先进先出)方式被处理;
    • 调用 – 与普通函数调用区别在于怎样指定所调用的对象和方法;决定是否提供回调函数接收通知;
    • 延迟调用缺点 – 调用方必须知道被调用的目标对象的标识; 游戏中的事件往往导致某些动作的执行,状态的改变,调试和维护会变得困难;
  3. 事件广播:对事件驱动系统的第一个改进 – 在它之上加入一个层次来为游戏事件实现广播机制;
    • 游戏事件 – 一个整形常量标识,用于表示游戏中发生的某件事情;
    • 事件处理器 – 任何可调用的对象/函数/方法,它们在特定事件发生后被调用;
    • 事件广播器 – 把事件派发给对其感兴趣的对象,这些对象会为某个特定事件向事件广播器注册(register)一个事件处理器;
    • 事件参数 – 事件必须是函数式的,可接受参数以包含更多意义;
    • 使用事件广播 – 首先为关心的事件声明一/多个处理器;接着把处理器注册到事件广播,并传入实现这些处理器的函数或方法的引用;
    • 优势与劣势 – 成功解耦了事件发送者和接收者; 事件分发只有一段代码方便添加日志和调试; 但会造成很多低效的无效调用;
  4. 精确的事件广播 – 对事件驱动系统的最后改进 – 精确注册,不仅可指定关心的事件还可指定在什么情况调用处理器;
    • 游戏事件索引 – 索引可根据事件、事件源和目标组合;
    • 事件索引派生类 – 若要使用更多标准来注册事件处理器,可从游戏事件索引基类派生;
    • 使用游戏事件索引来注册事件处理器或发送游戏事件;

【实现移动和物理模块的注意事项】

  1. 可以发布游戏吗:保证足够的真实性从而让玩家持续游戏,并加以足够限制使游戏可及时而经济的被实现; 团队达成共识;
  2. 这是一场战争:对设计和实现评估时,必须考虑恶意玩家会怎样利用这些信息以欺骗服务器;
  3. 服务端永远是对的:比如防止客户端侵入房屋获取屋内物品 –
    • 先确认是否合法进入,而后才把房屋内容发送给这个客户端;
    • 要求把房屋中的物品保存在一个固定的保险箱里,并有一把单独的钥匙;
    • 把进入房屋实现成将玩家传输到另一区域,这样就不能仅仅通过移动进入房屋;
  4. 移动的代价:
    • 假设每秒15个移动数据包(20byte) – 每玩家300byte/s,若同屏20人则需6Kbyte/s,这还仅仅是雕像般的移动; 占用太高!
    • “暂时频道”法 – 客户端仍然产生数据包,但只发送一个更新周期中最新的移动数据; 这对于瞬时信息非常有用;
    • 采样点:
      • a.服务端收到移动数据包时会根据该前一个包做判断(前后位置以及采样点合法),若无效发送修正数据包(实际移动),并广播给附近玩家;
      • b.关键要确保两个位置之间的采样点距离应小于游戏中最小的碰撞/触发体; 避免穿过门等障碍物;
      • c.另一关键要对两次更新的移动距离设置上限; 比如最大速6m/s,每秒更新4次,上限设为2m,超速修正,防止手工数据包;
      • d.增加欺骗检测机制,比如记录玩家最大移动速度历史,统计非法移动,使GM可针对性细致监视;
  5. 移动速度:
    • 应了解在游戏中允许提高移动速度会加大系统对移动数据包的检验错误;
    • 保守做法是只允许两种速度(快速和慢速); 或缩小地图尺寸比例;
  6. 玩家可从这里到那里吗?
    • 游戏世界中的移动 – 开始设计时假定玩家哪都不能去,随后开辟道路来指定可合法移动到的位置,会相比障碍物阻挡少很多漏洞;
    • 瞬间移动 – 确定有效目的地,无碰撞会使传输更稳健,即时偶尔角色重叠,玩家亦会很快移动走;
    • 平移动画 – 跳跃轻功等,比如瞬移5米,可在服务器确认后开始动画; 也可立即显示动画,失败时在障碍处被迫停止; 都比无法移动感觉好;
  7. 碰撞检测:基本方针是尽量把在任何时刻必须进行碰撞检测的物体数量最小化;
    • 碰撞体 – 先用一个简单的几何形状来构建碰撞体并用于粗略判断是否碰撞,若碰撞再使用更细致的几何体进行精确判断;
    • 角色碰撞体 – 使用躯干圆柱体(不低于膝盖上方,不高于肩膀),这样角色不会被简单物体(如楼梯)阻挡;
      障碍物碰撞体的长宽需大于角色合法移动的最大距离,且高度要高于角色碰撞体的最低点;
    • 角色间碰撞:
      • 优势:a.使游戏更真实; b.避免角色重合的视觉问题; c.实现简单,碰撞通用处理; d.更有趣的机制,比如攻城阻挡战略的实现;
      • 劣势:a.CPU负荷增加; b.瞬间移动实现难度加大; c.碰撞骚扰(比如阻挡出口等); d.多玩家抢点代码复杂; e.AI碰撞;
    • 缩放 – 应考虑角色模型大小的多样性和独特性; 把握针对不同尺寸变化实施独特游戏机制的机会;
  8. 物品放置:允许”放置”,使玩家可在游戏世界留下自己的”标志”; 比如获取房屋并装饰,是非常诱人的;
    • 可能被利用的地方:应尽可能避免在公共区域任意的放置物品;
      • 在对战区域放置大量物品,使其他进入玩家暂时失控(因物品数据包会占用大量带宽);
      • 通过富有创造性的方式堆叠物品形成通路,进入通常无法进入的区域; 或是站在物品上,收取物品放置到其他地方;
    • 可行方案:
      • 归属权在一定时间内属于原主人,之后可被其他玩家捡取,若一段时间未被认领则自动销毁;
      • 将放置物抽象为某种通用的容器,类似袋子,并且不能被堆叠也不能放置在其他容器中;
      • 指定一些预定义/可接受的位置用于放置,比如公共基座允许团体放置装饰;
      • 不允许公共区域放置,只允许放置在安全区域,比如玩家的房屋中;
      • 实现一些四处走动并会拾取放置物品的NPC;
      • 物品只能在预定义的放置处有限叠加,比如画挂墙上,花瓶放桌上;
      • 发送数据时,与物品相关的信息设置一个上限,赋予那些会影响游戏的对象更高的优先级,比如有威胁的怪物;
  9. 侵入检测:
    • 加密只是为了赢得更长时间,来持续加固系统以检测和防止恶意玩家的侵入;
    • 对设计进行评估时,优先选择那些很难活不可能被侵入的游戏机制;
    • 记录玩家行为,但不要过量也不能影响性能,构建于商业数据库系统上的异步日志机制是强有力的工具;
    • 用更多的侵入检测代码对有恶意嫌疑的玩家进行更细致的评估; 比如不停试图达到允许的移动距离上限玩家,进行更多检测或通知GM跟踪;

【客户端开发】

【客户端移动预测】

  1. 游戏需良好的移动预测:原因 – 玩家需要获得即时反馈; 网络数据包延迟的不确定性;
  2. 命令时间同步:
    • 即时战略游戏如《星际争霸》必须基于寻路请求来把对象移动到特定的位置;
    • 仅发送”移动X到达位置P”不如”移动X使其在未来的某个时间T到达P”,若客户端与服务端时间同步,可通过调整X客户端速度达到精确同步;
    • 服务端通过X的速度V以及最低和最高延迟验证命令是否正确后,通知所有客户端X必须在T时刻移动到P;
    • 在调整速度时,注意使用平均速度;为了平缓移动速度的骤然变化(比如10m/s到7m/s),可在到达P前等量减慢X的最终速度;
  3. 合并路点:
    • 路点 – 物体移动路径上的一系列关键点; 例如怪物,无路点不可移动;若有则始终朝第一个路点移动,达到后删除首路点;
    • 方法 – 服务端只需要在移动开始的时候发送一个初始的路点列表,在这个怪物停止移动前就不用再去更新它了;
    • 客户端发现它到终点的直线上无障碍物则可自行移动,若一个对象撞上另一对象时服务端发出停止命令; 两端有差异时,合并路点;
  4. 插值和推导:
    • 推导 – 使用最后得到的位置和对象的速度来预测其未来的位置和速度; 延迟越大,差异越大,需插值平滑防止跳跃;
    • 将对象的移动路径切割成100ms-200ms的时间片进行推导,当服务端和客户端路径点不同时,客户端插值调整到服务端的路径点;
    • 线性插值; 曲线插值(比如FPS游戏中,不是在跳跃就是在地上,需要拖回地面的曲线平滑,否则会造成滑翔的视觉错误);
  5. 为瞄准延迟使用反向仿真:
    • 上述方法不足以解决FPS中的问题 – 当玩家延迟较大时,可能已经瞄准目标并在合适的时刻按下了扳机,但已有方法会使击中无效;
    • 如果服务端可以知道客户端进行射击时的情景,它就能正确地判断目标是否被击中了;
    • 得到确认的消息序列沿着历史记录回溯,并计算出发送命令时客户端对象的位置,完成击中/未击中计算后,疑问对象被放到它当前的时间和位置中去;
    • 示例 – 客户端A在400ms前收到B最后一个移动数据包,因此,根据此时B的速度和方向,推断A按下扳机时B的位置,如果击中,则判定击中;

【保持流畅:异步客户和时空穿梭】

  1. 共享状态的基本问题:
    • MMP游戏里必然有一些对玩家都必须相同的共享数据,有些数据还会以不可预见的方式改变,怎样发送这些共享状态的改变?
    • 重要成果 – 分布式交互仿真(DIS)、仿真网络(SIMNET)、高级架构(HLA);
  2. 航位推测法:客户端预测方法,广泛应用于需要发布位置数据的游戏中比如FPS; 减少发送数据; 补偿网络延迟;
    • 使用带有时间戳的信息进行预测可使移动更流畅;
    • 很难对会突然变向的对象预测,对其流畅的显示意味着不精确;若该对象并不需要在每个玩家视野中都具有相同表现,亦可使用航位推测;
  3. 仿真时间:通常并非真实时间(wall-clock time);
    • 服务端需要对分发时间值所花费的时间进行补偿 – 简单方法是用一个集中的时间源发出一堆访问,而后把平均回复时间的一半加在接收到的值上;
    • 仿真时间必须完全独立于帧频率,对客户端时间的操作应独立于画面更新的节奏;
  4. 直接操纵时间:
    • 常用方法 – 让所有客户端的仿真事件略微落后于实际时间,服务端需要使用某个网络消息时,可提供一个到达客户端的时间;
    • 上述方法会引起以个固定的延迟,但可通过一些声音和动画效果立即对玩家的请求进行确认,并马上开始玩家的行动;
    • 控制时间 – a.最小更新时间(一个对象的状态发生改变到它的状态可以再次发生改变所要经过的最短时间);
      b.时间戳下限(一个参与者可能获得下一个更新的最早时间);
  5. 总结:
    • 让客户端保持流畅比精确更重要; 让每个玩家都觉得他才是游戏中唯一的玩家; 不惜一切代价避免停滞和跳跃;
    • 让玩家能够知道游戏中发生的事并能参与其中; 让玩家可以掌控自己的游戏世界比让他们为其他玩家的游戏世界做贡献更为重要;

【使用程序生成游戏世界:避免数据激增】

  1. 运行时生成的优点:
    • 有效减少数据量 – 用一个随机数种子和一个良好的随机数发生器就可生成整个游戏世界,只要玩家使用相同的种子和生成函数,所见便相同;
    • 细节生成 – 只需通过发布新的生成程序和生成DLL进行更新,地形/对象/新贴图等改变都可在各个客户端自动生成;
  2. 运行时生成的缺点:
    • 性能影响 – 须谨慎决定哪些数据在运行时生成?哪些在载入游戏关卡时预先生成?哪些在更新/发行时预先生成?
    • 增加复杂度延长开发时间 – 生成函数本身不复杂,但动态的细节层次函数可能非常复杂;
    • 多数生成函数很难控制 – 简单解决方案是预先生成到某个特定的细节层次,然后动态生成来补充其余的细节;
  3. 地形生成算法的分类:
    • 静态算法 – 先确定网格大小而后对整个网格操作,因控制方便,可用来把地形预先生成到一定的细节层次,而后动态算法补充;
      断层线算法(迭代次数越多,生成的地形越美观);
    • 细分算法 – 等离子算法(静态算法); 可建立一个树状结构来模拟自适应网格算法;
    • 动态算法 – Perlin噪声算法; 分型布朗运动(fBm); 多重分型算法(MojoWorld虚拟世界创建程序的主要驱动力);
  4. 修改程序生成的地形:手工修改; 静态算法修改; 伪动态算法修改;
  5. 高效地渲染程序生成的地形:ROAM算法;
  6. 生成贴图:
  7. 在程序生成的地形进行碰撞检测:避免在碰撞检测时进行三角形判断;
  8. 大型游戏中世界中的比例问题:
    • float在1000公里左右不够精确,double在一万亿公里时不够精确;
    • 尽量少用双精度,仅用于表示物体位置或关键位置,其他使用单精度;
    • 替身(Impostor)渲染;

【为固定大小的对象编写一个高速有效的分配器】

  1. 游戏系统会频繁地分配很多对象,像矩阵、向量等,这些对象更适合于分配在栈上,不仅可减少内存/高速缓存不一致带来的问题,也可避免使用指针;
  2. 一个简单的向量分配器:分配一块连续的内存,大小是类T大小的整数倍,用指针数组保存空余内存块;最初每个分块指针都在数组中,用索引指示下一个空余块(初始为0),分配时返回索引位置的内存块,将索引递增1指向下一可用空闲内存,释放分块时索引减1,,并将内存块指针放回指针数组中;
  3. 重载操作符,使调用者不需做额外工作即可使用分配器功能,比如重载C++中的new和delete运算符;
  4. 字节对齐:所有分配都应该至少和8个字节边界对齐,以获得最佳性能; 针对缓存线和处理器中的向量单元,分配16位或32位对齐可能更好;
  5. 降低分配器内存开销:把管理分配的数据结构放在未分配的内存块中;
    • 不再需要内存指针数组,而只需在每个空闲块开始的几个字节里,保存指向下一空闲块的指针; 循环链表;

【使用贴图定制三维角色】

  1. 角色定制的类型:
    • 网格定制 – 可改变角色轮廓; 分段网格交换; 避免引起光照或碰撞问题;
    • 贴图定制 – 网格已固定,所需资源较少,对引擎功能依赖低,可提供大量变化;
  2. 贴图合成简介:定义和构造一个可用于贴图合成的区域,最好支持调色(hueing)和Alpha混合;
  3. 分层:例如 – 0皮肤 → 1身体艺术<纹身/伤痕> → 2毛发 → 3衣服 → 4外衣 → 5徽章;
  4. 贴图定制模板和样本:贴图到网格的正确映射是贴图定制成败的关键; 定义贴图区域的结构称为贴图模板;
  5. 样本集合:提供一个抽象层来简化用户与贴图定制系统之间的交互;隔离细节并确保在对模板修改或细分时不会影响用户已作出的关联;

【游戏机平台上MMP游戏的独特挑战】

  1. 环境:游戏机更多地处于一个共享的环境中–人们聚集和社交的地方;
    • 分屏模式 – 让2-4人在同一台游戏机上共同游戏可降低很多问题的复杂度,包括交流、分组和交易;
    • 减少单次游戏持续时间 – 加快连接寻找朋友、决定做什么、到达目的地这一过程,使玩家半小时内足以进行一次有效游戏;
  2. 登录:简化登录过程,记住用户名,密码可通过一系列按键动作来输入,或同用户名一样使用虚拟键盘;
  3. 分辨率:小心决定低分辨率下的文本显示方式; 分屏模式进行组合显示(如小组名单/雷达地图);
  4. 聊天频道:一对一聊天; 和少量玩家分组式聊天; 和大量朋友或在行会中聊天; 大型事件中关于战略/战术的聊天;
    • 语音 – 通道切分; 无法过滤内容; 带宽需求高(可用P2P分布式聊天);
    • 表情 – 自定义表情需要额外传输时间,可能导致某些玩家不愿使用,一组不需额外传输时间的缺省表情非常重要;
    • 简短的固定表达 – 形象的手势、简短而固定的文本消息、热键触发的声音事件等;
  5. 选择目标:就近/最弱/团队目标/小组成员; 隐式目标选取 – 系统自动把处于攻击范围的对手作为目标(例如FPS中对准什么就攻击什么);
  6. 菜单:a.功能分组置于顶层菜单,从而平铺开使玩家可用手柄中不同的按键来触发; b.通常建议大部分菜单功能组合起来,置于一个独立的顶层菜单上;
  7. 背囊管理和交易:可使用虚拟指针拖拽; 装备、保存、交易、物品使用,需特别注意;
  8. 补充界面:若可通过行会网站、玩家组织、关于游戏诀窍的站点或其他Web拓展来建立游戏以外的存在,会加强玩家集体感;
    • 鼓励外部集体的一个方法是给与他们访问任何游戏数据的权限,只要不带来安全/隐私的风险、带宽问题、不涉及专有知识;

【游戏系统】

【从原料到成品:社会经济中的职业生涯】

  1. 原料获取和加工:
    • 原料采集系统 – 玩家能力/技能/属性可影响采集结果(数量、质量、耗时); 原料核心亦可控制采集结果;
    • 超越期望的乐趣 – 引入制造系统的每一阶段,概率结果不应进行惩罚,而是用一些超出预期的结果来奖励玩家;
    • 时间投入和原料产出以及风险和回报 – 比如缩短时间降低质量获取更多低级原料; 危险地点采集稀有物品;
    • 实例 – 制造专家委托 → 采集专家 → 危险区域护送(任务公告栏)/朋友 → 复杂技巧获取高质量原料 → 采集附产品 → 活着回来丰厚回报;
  2. 社会经济中的合作制造:通过对原料采集、物品需求度、合理的技能多样化及丰富的制造配方进行考虑;
    • 制造物品 – 制造技能 → 配方 → 详细描述所需工具、原料或其他物品;出问题时所需原料 → 原料/工具质量决定成品质量 → 制造时间;
    • 时间投入与产品价值 – 稀有度决定价值,通过对原料/工具的技能等级或产出控制; 玩家合作制造;
    • 原料、工具和物品的作用 – 工具可由玩家制造,独特限制,成品质量影响; 成品可作为其他物品部件,比如零件与引擎;
    • 对新制造的工具进行改进和修理 – 使用和制造物品相同的方式进行修理和改进,简单把所需修理或改进的物品组合起来;
  3. 物品制造在社会经济中起到的作用:
    • 社会作用 – a.设计为需要很多不同的技能集合; b.调整风险和回报间的关系使从事制造业的玩家依赖于冒险玩家;
    • 制造业、物品和声望 –
      • a.把信息提供给感兴趣的玩家 – 广告栏、任务发布栏;
      • b.外部网页建立公告栏镜像使玩家游戏外可寻找合作伙伴;
      • c.可获取制造物品的特定信息非常有用(总数、质量、杀怪数、使用者平均声望技能等级等); 大型战役致命一击信息可获取/传播等;
    • 保持需求(重要) – a.让物品会损坏; b.让玩家的物品保持较高的周转率;

【玩家房屋供给:我的房屋就是你的房屋】

  1. 成长之路:价格高供应量少 → 不断存钱 → 选址(地产有限) → 内部装饰 → 升级更好的房屋。<成就感、展示、商业、收藏>
  2. 商业方法:雇佣商人NPC销售货物 → 增加房屋需求。
  3. 地段、地段、地段:a.直接在房屋边通过的人流更易带来顾客(拍卖将降低房屋重要性); b.战利品展示等可炫耀的事情;
  4. 应该把戟放在哪里:个性摆放来展示创造力和设计能力; 珍惜品市场; 垃圾储藏室(人们不喜欢放弃) – 建议开始就进行限制;
  5. 让玩家管理一家商店、开家酒馆或拥有一座壮丽的城堡可让玩家以一种难以置信的方式对身边的世界产生影响;

【社会游戏系统:促进玩家社会化并提供游戏回报的另一途径】

  1. 社会游戏系统:就是那些给予不同的社会行为支持、鼓励、回报和惩罚的系统;
    • 吸收新成员融入虚拟世界 – 良好的设计可帮助玩家学习和应用游戏世界中的社会期望(譬如进入图书馆就知道那是安静的地方不应打扰他人);
    • 促进玩家的交流和联系 – 公开的、私人的、近距离的、群体中的聊天系统; 但社交不止于交谈;
    • 支持和促进合作游戏 – 积极回报正确的社会行为并阻止反社会行为;
    • 培养归属感 – 马斯洛需要层次第三步,归属、联系、被他人接受、付出与获得爱和友谊;
    • 小型世界网络 – 六度分离; 通过提供更强的社会系统,降低所需度数,进一步增强玩家间联系;
  2. 为什么要让玩家社会化?
    • 创建自洽社会 – 尽量创建一个不需开发人员参与即可独立运转和发展的自洽世界,缩减开支,增强虚拟世界玩家的联系;
    • 减少”反社会”玩家 – “玩家捣蛋投诉”占客服时间40%,而将其花费在帮助技术困难或遇到程序错误的玩家身上,会更有建设性;
    • 增加玩家的股份 – 玩家对虚拟世界投入(朋友/虚拟活动/金钱等)越多,忠诚度越高;
    • 创建更丰富的游戏世界 – “广度”指实现更多游戏系统尤其是社会系统; “深度”指提供更丰富的游戏体验;
      • 更好的AI、更复杂的任务以及更广阔的地理区域; 更复杂的社交系统;
      • 它不仅仅是一个游戏 – 有些玩家在游戏中发现了他所未开发的技能或天赋; 领袖体验、克服游泳恐惧、虚拟婚姻到真实婚姻等;
  3. 目前使用的社会系统:
    • 聊天 – 频道聊天; 广播; 图形表情; 语音; 肢体动作如”挥手”;
    • 层次结构 – 行会系统; 效忠君主系统; 金字塔效应;
    • 声望 – “根据某人的人格或其他品质对其作出一般评价;某个人或某种事物所受到的相对评价或尊重;” 玩家可评价他人;
    • Bartle类型 – 根据玩家动机分为四种类型:探险、获得成就、杀人和社交;
      • 探险者希望了解游戏世界,会绘制地图,测试游戏机制/数据等;
      • 获得成就的人为自己创建游戏相关目标并完成(积攒战利品或寻求地位);
      • 杀手会缠着其他玩家,寻求展示比其他玩家更为优越的机会; PK或寻求各种方法来和其他玩家捣蛋;
      • 社交玩家喜欢与其他玩家进行交互,即进行社会化;
    • 匹配服务 – 帮助玩家寻找或加入其他玩家; 譬如梦幻西游的剧情/任务队伍查询/加入(等级职业限制等);
  4. 回报社会性游戏的创新方法:
    • 对目前的社会游戏系统进行改进 – 更易用的界面; 根据玩家反馈和建议完善; 借助问卷帮助系统选择组合玩家队伍; 重要信息手机通知;
    • 增加社会联系 – 马尔科姆.格拉德威尔《引爆流行》少数法则,”链接者”能认识大量其他人,找到他们并给予回报,即可创建和加强社交网络;
    • 开发与真实世界平行的社交系统 – 玩家聚集点往往都都是那些建立起真正友谊的玩家;
      • 应该使用人们在真实生活中使用的社交系统并且把它们运用在游戏世界中,譬如虚拟饮食/服装经营,增强投入感和满足感;
    • 为新的社会行为定义规范和礼节 – 命名规范; 鼓励符合游戏文化的社会规范;
    • 通过仪式 – 设计通过仪式(成就里程碑)增强参与感;譬如5级才可选一个专业领域,10级才可选择一个姓;
    • 新的经济体系 – 货币、战利品或商业组成; 货币可使用不同类型等价物,譬如有用的物品、时间、空间、声望等;
    • 导师 – NPC管理的学徒/导师系统;
    • 社会化 – 要想方设法报答社会性玩家 – 譬如长期在公共频道分享故事,帮助其他玩家,向不熟悉游戏的玩家介绍游戏系统的玩家;

【为创建和管理行会设计灵活的命令集】

  1. 创建:对初始成员的最小数量做出要求避免滥用行会创建; 允许行会某些成员可改变行会名(投票制?);
  2. 领导:数字表示等级,比如领袖为0,普通成员为100; 可对每个等级进行定义和命名,并指定职责和能力;
  3. 标识:提供除名称外的其他标识; 譬如纹章/饰章,使用源自游戏的完全虚构的图记,避免带来“真实世界”问题; “纹章学”; “可预览”;
  4. 行会维护:增删成员; 等级设置; 管理权限等;
  5. 财产:行会银行/仓库; 共享装备; 金钱捐赠/提取; 查询财产提存记录;
  6. 专用区域:特定区域供行会成员使用; 特定建筑供特定等级的成员进入;
  7. 交流:行会内部交流; 限定可加入行会的临时频道; 指定多个所有者; 成员移除/禁言;

【创建声望系统】

  1. 友谊和仇恨的实现:每个NPC都属于某个派系,定义不同关系(友好→中立→仇恨)时的可能反应; 声望调整; 目击者传递; 派系声望;
  2. 宽恕:个人声望; 标记”全局”或”非全局”,比如兽人士兵攻击精灵士兵,目击者为全局的,则会引发种族对抗; 仇恨衰减;
  3. 投降:提供不会消逝的永久个人声望调整,避免投降场景短期可用,长期则出现问题;
  4. 玩家对战的设置:玩家追随者/召唤兽使用主人的声望; 可通过”玩家关系”面板设置是否仇视其他玩家,确保宠物行为符合期望;

【城邦政府在在线社区中的作用】

  1. 公民生涯:赋予玩家初始归属感,并提供一些导引; 无论参与度公民都可享受归属和导引带来的社会优越性; 避免城邦间流动性过大;
    • 国籍 – 国籍获得、更改所需步骤、对国籍滥用带来的问题及对策;
      • 登录时授予国籍,提供城邦简单数据,比如总资产、总人口、占领区域、完成的任务、平均声望; 默认玩家无选择时平均分配并给予奖励;
      • 更改申请 → 缓冲时间 → 流浪状态 → 找到担保人 → 缴纳统治者规定的物资/费用 → 加入新国籍;
      • 限制每个账户只能拥有一个国籍; 避免”傀儡型”赏金猎人、滥用选举系统等;
    • 国籍可能带来的权益 – 包括可从玩家及周围环境获得保护; 根据角色能力获得奖励; 参与城邦相关行动和任务;
      • 国籍权益与城邦核心特征以及所占区域的核心特征挂钩; 譬如倾向魔法/战斗/生活职业;
      • 权益与城邦扩张相关,占据特定区域获得相连的技能奖励,亦可区域类采集、冒险或资源占领,鼓励玩家在该区域聚集,加强公民联系;
      • 权益与参与政府任务相关,消灭采集区惹麻烦的NPC、获得建造资源、守卫/侦查特定区域;玩家为其社会权益工作,冒险将更有意义;
  2. 参与城邦工作:强健的在线政府系统可为玩家提供大量的参与机会;
    • 领袖选举 – 投票权限制公民在线时长/等级/活跃度; 提供候选者简单数据(属性、成就、声望)及宣言; 胜利者广播并发布到网页上;
    • 政府职业如”赏金猎人” – 玩家满足基本要求(时长/战力)后可申请,统治者通过查看成就/玩家评价决定是否授予;
      • 玩家需要时即可呼叫赏金猎人,之后可瞬移至玩家身边,为避免滥用,需支付一定费用;
      • 鼓励赏金猎人扩大巡逻范围,比如设置动态路点,到达时刻获得一定报酬,促使巡逻到不常去的地点;
      • 提供工具识别玩家杀手并跟踪,基于声望、行会关系、所杀玩家数等,在一定时间内驱逐出城邦;
      • 使负责的赏金猎人付出的时间和努力的回报要远高于正常冒险; 记录行为(应答数,忽略数,杀敌,路点),用于清除滥用职位能力的玩家;
    • 让玩家能自行参与城邦工作可让他们感到自己是社会的一份子; 选举,影响发展方向,职位参与等各种形式包容并引导,建立更强的社会联系;
  3. 定义政治过程:
    • 成为统治者:
      • 满足基本的等级在线时长/行会领袖,一定数量(总人口特定百分比)玩家宣誓(付出一定代价如钱或资源)支持后,成为候选人;
      • 候选者接受相应条款(要求捐献大量金钱,与总人口通胀等挂钩;公开账户角色的行为等信息)后,提出宣言(治理计划等)后,开始参与选举;
      • 选举持续一定时间,避免服务器压力过大以及控制权力转移是的改变和混乱; 限制连任次数或一定时期内担任次数(譬如每年不超过三次);
      • 罢黜 – 考验公民的团结度,超过一定百分比即自动废除,在下次选举前,系统NPC代管(根据历任平均数据开展工作);
      • 辞职 – 可选择立即辞职; 登入次数/行动数不达标,将自动失去职位;
    • 统治者权力与义务:确定法律,指定税率,负责职位及城市发展支出间的财政分配,任命赏金猎人等不需选举的政府职位;
      • 法律包括a.是否允许攻击公民;b.安全区设置;c.不同声望可享受的权益;d.物品制造/销售限制;e.技能限制等; 限制法律变更次数及时限;
      • 在预先指定的范围内调整税率(对内/对外),税收存入国库,不可直接提取,但能分配职位收入/发展城市/建造银行等;
  4. 城邦为不同政体间的大规模战争及领土扩展提供了有意义的背景;一个强有力的在线政府系统为解决在线社会中的很多问题提供了强大的框架;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章