且听疯吟 如此生活三十年
炉石卡牌实现机制的一点猜想

假设我们要实现一个炉石的对战机制,要怎么做呢?
并没有游戏开发经验,所以以下都是乱猜加瞎扯~

分类

首先,我们把炉石里的主要元素分成几类:

  • 法术
    法术很好理解,一般来说法术包括几个要素

    • 目标
      • 可能是一个目标也可能是多个目标
      • 可能包含一个筛选,比如「对非恶魔随从造成伤害」
    • 效果
      • 可能是给目标一个 buff 或者 debuff,也可能是造成伤害等等
      • 大部分法术都是立即效果
      • 也有一部分法术是触发效果,比如 奥秘,比如 本回合随从生命值不会降低到 1 点以下
  • 武器

  • 英雄

    • 英雄技能可以看作一个法术
  • 随从

    • 随从本身具有的属性

      • 花费/攻击/血量
      • 类别: 恶魔/鱼人/野兽
      • 其他
        我们以 https://hearthstonejson.com/ 上的卡牌火车王的 Json 数据为例:
      {
          "id": "EX1_116",
          "name": "Leeroy Jenkins",
          "text": "<b>Charge</b>. <b>Battlecry:</b> Summon two 1/1 Whelps for your opponent.",
          "rarity": "LEGENDARY",
          "type": "MINION",
          "cost": 5,
          "attack": 6,
          "health": 2,
          "collectible": true,
          "set": "EXPERT1",
          "faction": "ALLIANCE",
          "artist": "Gabe from Penny Arcade",
          "flavor": "At least he has Angry Chicken.",
          "mechanics": [
              "BATTLECRY",
              "CHARGE"
          ],
          "dust": [
              1600,
              3200,
              400,
              1600
          ]
      }
      
    • 随从效果

      • 即上面的 mechanics 数据
      • 目前炉石包括了 冲锋、亡语、发现、战吼、法术伤害、连击 等等大概二十多种效果

效果

  • 法术效果
    • 法术效果相对来说容易归纳
  • 随从效果
    • 实际上随从效果可以认为是法术效果,比如自带亡语的随从,可以认为是通过法术给予了亡语效果——毕竟,炉石里面确实存在着这样的法术
    • 具有亡语效果 随机召唤一个法力消耗为 3 的随从 的随从死亡时,可以认为是使用了一个 随机召唤一个法力消耗为 3 的随从 的法术
    • 光环是一种特殊的法术效果,拥有更加复杂的触发条件,比如 将你的治疗法术或技能改为造成等量的伤害

对局

  • 从对局中我们可以总结出一些规则,比如大家经常会讨论的 结算顺序
    • 虽然打出一张牌表面上看起来很简单,但是背后其实包括了多个阶段,比如:
      • 选择战吼目标并出牌,此时扣费
      • 登场效果触发,这个时候一部分其他卡牌的效果已经会被触发,比如 任务达人
      • 召唤效果触发,比如会触发 送葬者
      • 战吼效果触发,此时开始结算战吼效果
      • 奥秘效果触发,这也是为什么 谢娜 这张牌可以先偷到复制但是自己本身并不会被复制
      • 召唤结束,这时会触发 飞刀杂耍者 之类的效果
        (结算比较复杂,而且涉及到各种死亡结算和效果,而且暴雪也没有出官方的结算规则,所以,以上只是举个栗子~
  • 从上面的例子可以看到,不同的牌在不同的阶段触发效果
    假设我们需要实现一张 飞刀杂耍者,每召唤一个随从就发射一把飞刀
    • 我们可以很容易分开两个角色
      • 系统,它担任裁判的角色
      • 卡牌
        这样由系统去执行整个流程,在召唤了一个随从后,通知 飞刀杂耍者 去执行发射飞刀的任务
  • 显然我们没办法把所有卡牌逻辑都塞在 系统 这个角色中,假设我们有 500 张卡牌,那么 系统 这部分的调用代码可能会突破天际
  • 我们也不能让 飞刀杂耍者 自己去监控整场对局,从而决定什么时候发射飞刀,显然这样 系统 这个角色就失去了其意义,代码也会无比混乱
  • 实际上对于这样的问题,我们有一个经典的例子(或许你在面试中已经被问了无数次的 「猫叫老鼠跑人醒」)
    • 这就是观察者模式(事件-通知)
    • 我们只需要让 飞刀杂耍者系统 那里注册一个事件,告诉它,有随从被召唤的时候,通知我,然后由我来执行对应的逻辑
    • 系统 则需要维护一个注册的事件列表,比如随从被召唤的事件、随从死亡的事件等等
    • 系统 按结算规则来执行,并在对应的事件触发的时候,按一定的顺序去通知即可

其他

  • 炉石包含很多不同的效果,事实上这也正是它好玩的地方,但一来暴雪没有出明确的结算规则和效果解释,有些卡牌的效果也找不到同类和规律(比如改变战吼效果的 铜须 光环,和改变法术执行目标的 扰咒术 等等),所以有些时候想总结一套规则来套用所有卡牌不太容易
  • 对于单个的特殊的效果,hardcode 也是一个解决办法

插件

额外插一点关于炉石插件的内容,之前看到有童鞋在好奇

  • 炉石传说有一个隐藏的 debug-logging 模式,打开之后会产生非常详细的记录,通过解析这个 log 可以做到记录和获取对局信息
  • 网易的盒子貌似额外使用了抓包解析的方法,所以功能会强大一些,比如导入导出卡组的功能
  • 但是考虑到可能触犯 ToS ,其他插件没有这么做
  • log 大概是这样的:
    [Zone] ZoneChangeList.ProcessChanges() - id=1 local=False [name=Garrosh Hellscream id=4 zone=PLAY zonePos=0 cardId=HERO_01 player=1] zone from -> FRIENDLY PLAY (Hero)
    
    • 可以看出 log 是非常详细的,包含各种事件的触发
    • 解析完整的 log 可以帮助理解整个炉石的事件机制
  • 当初想要自己实现盒子的时候参考过这篇文章 https://www.reddit.com/r/hearthstone/comments/268fkk/simple_hearthstone_logging_see_your_complete_play
  • 当然现在很多开源的插件了,比如 https://github.com/HearthSim/Hearthstone-Deck-Tracker

待补充

想到哪写到哪,有什么想法再补充吧 =-=