9.1 付费动机与付费点布局

付费点不是货架上摆得越多越好。本节先把玩家掏钱的动机拆成进度、竞争、收集、社交、便利五类,再用 config/n09_payment.json 把八个付费点铺到「动机 × 生命周期」两张轴上,用 S 层脚本把每个点归一化成每元玉璧等价,并算出 20 格布局矩阵的覆盖度与缺口。

前八章讲的是数值本身:属性、成长、战斗、兵种、掉落、抽卡、匹配、赛季膨胀。从这一章起换一个视角——这些数值最终怎么换成钱。在动定价之前,先要回答一个更前置的问题:玩家为什么要掏钱,以及我们把这些「掏钱的理由」摆在了游戏的哪些位置。这与 游戏商业化伦理 是两件事:那篇给的是商业化伦理清单(哪些做法会伤害玩家、红线在哪),本章给的是付费点布局与节奏的可跑设计——把动机、位置、价值都变成能算的数,红线由那篇守,结构由这一章搭。

先划清边界:定价与折扣留第 10 章,LTV 与回本留第 11 章。本节只做一件前置的事——把付费点按动机和生命周期阶段铺开,量化「铺得全不全、有没有结构性缺口」。9.2 讲首充 / 月卡 / 通行证三类常规付费点,9.3 讲付费节奏与体验保护。

玩家为什么掏钱:五类付费动机

SLG 玩家掏钱的理由不是「想要更强」这一句话能概括的。同一笔钱,背后可能是五种完全不同的心理:

  • 进度加速:想更快变强,把养成的时间压短。资源包、加速道具属于这类。
  • 竞争超越:想在 PVP、排行榜、联盟战里压过对手。这需要有人可比,所以它天然绑定中后期。
  • 收集养成:想要名将、图鉴、外观,追求「集齐」本身。
  • 社交展示:想在盟友面前有排面,付费买的是被看见。
  • 便利省时:想省操作、省时间,未必关心强度。自动建造、一键加速属于这类。

把动机分类不是为了学术,而是因为动机决定付费点该长什么样。同样是「给资源」,服务进度动机的是资源包,服务便利动机的是加速包——两者内容不同、定价不同、出现的阶段也不同。先问服务哪种动机,再决定做成什么形态,这是付费点设计的第一条顺序。

两张轴:动机 × 生命周期

一个付费点同时占据两个坐标:它服务哪种动机,它出现在哪个生命周期阶段。把动机当横轴、阶段当纵轴,就得到一张布局矩阵。矩阵里每个格子表示「在这个阶段,这种动机有没有被付费点覆盖」。

生命周期阶段本套统一为四段:新手期(1–7 天)、成长期(8–30 天)、成熟期(31–90 天)、赛季期(1–60 天,与前三段交叉)。赛季期是 SLG 特有的一段——每个赛季世界重开,玩家会重新经历一轮「开局到成型」,所以它是唯一一个横跨全周期的阶段。

有了矩阵,布局设计就从「拍脑袋摆货架」变成「填格子」。下面这段是本节的 D 层配置,定义五类动机、四个阶段和八个付费点:

{
  "version": 1,
  "note": "第 9 章付费点布局参数(n09 前缀,独立于卷一 ch*)。付费动机、生命周期阶段与付费点清单。金额一律整数分,价值一律整数玉璧等价,禁止浮点。直充基准取 config/pricing.json 的 tiers[0]。",
  "motivations": [
    { "id": "progress", "name": "进度加速" },
    { "id": "competition", "name": "竞争超越" },
    { "id": "collection", "name": "收集养成" },
    { "id": "social", "name": "社交展示" },
    { "id": "convenience", "name": "便利省时" }
  ],
  "stages": [
    { "id": "newbie", "name": "新手期", "dayFrom": 1, "dayTo": 7 },
    { "id": "growth", "name": "成长期", "dayFrom": 8, "dayTo": 30 },
    { "id": "mature", "name": "成熟期", "dayFrom": 31, "dayTo": 90 },
    { "id": "season", "name": "赛季期", "dayFrom": 1, "dayTo": 60 }
  ],
  "points": [
    { "id": "first_charge", "name": "首充", "priceCents": 600, "valueJade": 120,
      "motivations": ["progress", "collection"], "stages": ["newbie"] },
    { "id": "monthly_card", "name": "月卡", "priceCents": 3000, "valueJade": 900,
      "motivations": ["progress", "convenience"], "stages": ["growth", "mature"] },
    { "id": "battle_pass", "name": "赛季通行证", "priceCents": 6800, "valueJade": 3600,
      "motivations": ["progress", "collection", "competition"], "stages": ["season"] },
    { "id": "resource_bundle", "name": "资源礼包", "priceCents": 1200, "valueJade": 120,
      "motivations": ["progress"], "stages": ["growth"] },
    { "id": "speedup_bundle", "name": "加速包", "priceCents": 3000, "valueJade": 150,
      "motivations": ["convenience", "competition"], "stages": ["mature"] },
    { "id": "jade_direct", "name": "直充玉璧", "priceCents": 64800, "valueJade": 7776,
      "motivations": ["progress", "convenience", "collection"], "stages": ["newbie", "growth", "mature", "season"] },
    { "id": "alliance_gift", "name": "联盟礼包", "priceCents": 2000, "valueJade": 200,
      "motivations": ["social"], "stages": ["mature", "season"] },
    { "id": "gacha_pass", "name": "名将招募券礼包", "priceCents": 6800, "valueJade": 680,
      "motivations": ["collection", "competition"], "stages": ["season"] }
  ]
}

注意 stages 是一个列表:直充玉璧出现在全部四个阶段(它是「万能兜底」,任何阶段缺钱都能用),而赛季通行证只出现在赛季期(它天生绑定赛季)。一个付费点占据多个格子,这是正常的——布局矩阵算的是覆盖,不是唯一归属。

仿真:归一化与覆盖度

光有矩阵还不够,得能算两个数:每个付费点的价值归一化(不同内容怎么放到同一把尺子上比),以及矩阵的覆盖度(20 个格子里有几个被覆盖、缺口在哪)。下面这段是 S 层仿真脚本,它读上面的配置与 config/pricing.json 的直充基准,一次算出两者:

# file: sim/n09_payment_layout.py
# tier: S
# verify: python3 sim/n09_payment_layout.py --config config/ --out out/
"""付费点布局仿真:读 config/n09_payment.json 的付费点清单、动机与生命周期阶段,
以及 config/pricing.json 的直充基准(tiers[0]),把每个付费点按价值归一化成
「每元玉璧等价」与其相对直充的百分比,再算动机 × 阶段的布局覆盖度与缺口。
产出 out/n09_layout.json + out/n09_layout_points.csv + out/n09_layout_matrix.csv + out/n09_layout.svg。"""

from __future__ import annotations

import argparse
import csv
import json
import os

from svg_line import render


def load(cfg_dir: str, name: str) -> dict:
    with open(os.path.join(cfg_dir, f"{name}.json"), encoding="utf-8") as fh:
        return json.load(fh)


def jade_per_yuan(value_jade: int, price_cents: int) -> int:
    """每元玉璧等价:价值玉璧 × 100 / 售价(分),整数地板除。"""
    return value_jade * 100 // price_cents


def main() -> int:
    here = os.path.dirname(os.path.abspath(__file__))
    ap = argparse.ArgumentParser()
    ap.add_argument("--config", default=os.path.join(here, "..", "config"))
    ap.add_argument("--out", default=os.path.join(here, "..", "out"))
    args = ap.parse_args()
    os.makedirs(args.out, exist_ok=True)

    cfg = load(args.config, "n09_payment")
    pricing = load(args.config, "pricing")

    base = pricing["tiers"][0]
    base_jpy = jade_per_yuan(base["jade"], base["priceCents"])

    points = []
    for p in cfg["points"]:
        jpy = jade_per_yuan(p["valueJade"], p["priceCents"])
        points.append({
            "id": p["id"], "name": p["name"],
            "priceCents": p["priceCents"], "valueJade": p["valueJade"],
            "jadePerYuan": jpy,
            "vsDirectPct": jpy * 100 // base_jpy,
            "motivations": p["motivations"], "stages": p["stages"],
        })

    m_ids = [m["id"] for m in cfg["motivations"]]
    s_ids = [s["id"] for s in cfg["stages"]]
    matrix = {m: {s: 0 for s in s_ids} for m in m_ids}
    for p in points:
        for m in p["motivations"]:
            for s in p["stages"]:
                matrix[m][s] += 1

    total_cells = len(m_ids) * len(s_ids)
    covered_cells = sum(1 for m in m_ids for s in s_ids if matrix[m][s] > 0)
    gaps = [f"{m}×{s}" for m in m_ids for s in s_ids if matrix[m][s] == 0]
    stage_cov = {s: sum(1 for m in m_ids if matrix[m][s] > 0) * 100 // len(m_ids) for s in s_ids}
    motivation_cov = {m: sum(1 for s in s_ids if matrix[m][s] > 0) * 100 // len(s_ids) for m in m_ids}

    with open(os.path.join(args.out, "n09_layout_points.csv"), "w", encoding="utf-8", newline="") as fh:
        w = csv.writer(fh)
        w.writerow(["id", "name", "priceCents", "valueJade", "jadePerYuan", "vsDirectPct", "motivations", "stages"])
        for p in points:
            w.writerow([p["id"], p["name"], p["priceCents"], p["valueJade"], p["jadePerYuan"],
                        p["vsDirectPct"], "|".join(p["motivations"]), "|".join(p["stages"])])

    with open(os.path.join(args.out, "n09_layout_matrix.csv"), "w", encoding="utf-8", newline="") as fh:
        w = csv.writer(fh)
        w.writerow(["motivation"] + s_ids)
        for m in m_ids:
            w.writerow([m] + [matrix[m][s] for s in s_ids])

    render([stage_cov[s] for s in s_ids], os.path.join(args.out, "n09_layout.svg"),
           "motivation coverage pct by stage (5 motivations = 100)")

    report = {
        "version": 1, "baseJadePerYuan": base_jpy, "points": points,
        "totalCells": total_cells, "coveredCells": covered_cells,
        "overallCoveragePct": covered_cells * 100 // total_cells,
        "gaps": gaps, "stageCoveragePct": stage_cov, "motivationCoveragePct": motivation_cov,
    }
    with open(os.path.join(args.out, "n09_layout.json"), "w", encoding="utf-8") as fh:
        json.dump(report, fh, ensure_ascii=False, indent=2)
    print(json.dumps(report, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

本机实跑产出 out/n09_layout_points.csv(--config config/ --out out/,Python 3,零依赖):

id,name,priceCents,valueJade,jadePerYuan,vsDirectPct,motivations,stages
first_charge,首充,600,120,20,200,progress|collection,newbie
monthly_card,月卡,3000,900,30,300,progress|convenience,growth|mature
battle_pass,赛季通行证,6800,3600,52,520,progress|collection|competition,season
resource_bundle,资源礼包,1200,120,10,100,progress,growth
speedup_bundle,加速包,3000,150,5,50,convenience|competition,mature
jade_direct,直充玉璧,64800,7776,12,120,progress|convenience|collection,newbie|growth|mature|season
alliance_gift,联盟礼包,2000,200,10,100,social,mature|season
gacha_pass,名将招募券礼包,6800,680,10,100,collection|competition,season

同时输出的 out/n09_layout_matrix.csv 是 20 格矩阵(行=动机,列=阶段,格内数字=覆盖该格的付费点数):

motivation,newbie,growth,mature,season
progress,2,3,2,2
competition,0,0,1,2
collection,2,1,1,3
social,0,0,1,1
convenience,1,2,3,1

覆盖度汇总:20 格覆盖 16 格 = 80%。按阶段看:新手期 60%、成长期 60%、成熟期 100%、赛季期 100%。按动机看:进度 100%、收集 100%、便利 100%、竞争 50%、社交 50%。四个缺口是:竞争×新手、竞争×成长期、社交×新手、社交×成长期。

读这张表:80% 覆盖与四个缺口

覆盖度 80% 本身不是结论,缺口在哪才是。四个缺口要分两类看:

  • 竞争×新手、竞争×成长期——有意留白。新手期没有可比对象,硬塞竞争付费点只会让玩家觉得「还没玩明白就被逼着比」。竞争动机天然属于中后期,这两个格子空着是对的。
  • 社交×新手、社交×成长期——真缺口。联盟礼包(2000 分)只铺在成熟期与赛季期。但玩家在成长期就已经加入联盟(联盟是 SLG 的核心社交结构),这时却没有任何服务社交动机的付费点。这就是布局矩阵要抓的结构性问题:不是缺付费点,而是缺「在对的阶段服务对动机」的付费点。

这也说明覆盖度为什么不能当 KPI 追。如果把四个格子全填满,竞争×新手 那两个格子会变成劝退点。布局的目标不是 100%,而是「该覆盖的覆盖、该留白的留白」——80% 里藏着两个对、两个错,矩阵的作用就是把这四个格子摊开让人逐个判断。

价值归一化:每元玉璧等价

矩阵回答「摆在哪」,归一化回答「值多少」。八个付费点内容五花八门(玉璧、资源、加速、名将券),要比较就得折算到同一把尺子上。本套的尺子沿用 config/pricing.json 的直充基准:基准档 t1 是 600 分买 60 玉璧,也就是 10 玉璧/元。任何付费点的归一化价值 = 价值玉璧 × 100 / 售价(分),再除以基准就得到相对直充的百分比。

实跑结果把八个点分成了三层:

付费点售价(分)价值(玉璧)每元玉璧相对直充动机
赛季通行证6800360052520%进度 / 收集 / 竞争
月卡300090030300%进度 / 便利
首充60012020200%进度 / 收集
直充玉璧64800777612120%进度 / 便利 / 收集
资源礼包120012010100%进度
联盟礼包200020010100%社交
名将招募券680068010100%收集 / 竞争
加速包3000150550%便利 / 竞争

三层结构一目了然:

  • 200%–520%(时长绑定层):通行证、月卡、首充。它们都绑定玩家的后续行为——通行证绑赛季活跃、月卡绑 30 天登录、首充绑「第一次掏钱」这个动作。高性价比是为了换行为,不是为了送钱。
  • 100%–120%(等价兑换层):直充、资源礼包、联盟礼包、名将券。它们贴着基准线,是「不想比较时闭眼买」的标准品。直充略高(120%)是因为高价档有 bonus。
  • 50%(引导层):加速包只有基准线的一半。这是有意做低——加速道具在玩家心里比锚点便宜,如果礼包给到 100%,玩家会把它当加速优惠券囤积,冲击直充。压低它,是保护直充这个基本盘。

归一化与矩阵合起来,才是完整的布局诊断:矩阵说「这个阶段有没有对应动机的付费点」,归一化说「这个付费点该定在哪一层」。9.2 会把时长绑定层的三个点(首充、月卡、通行证)逐个拆开算清楚,它们为什么值得 200% 以上的溢价。

布局的三条纪律

做完这张表,可以抽出三条可复用的纪律:

  1. 动机优先于形态。先定「服务哪种动机」,再决定做成月卡、礼包还是通行证。形态是结果,不是起点。
  2. 留白要写进设计意图。竞争×新手 的空格不是遗漏,是决定。凡是有意留白的格子,都要能说出「为什么这里不该有付费点」,否则它迟早被运营塞满。
  3. 覆盖度是诊断,不是 KPI。80% 或 90% 都可能是好布局,关键看缺口落在哪。把矩阵当体检表,不当成绩单。

边界要说清楚:这张矩阵的动机归类是设计假设,不是玩家调研结果。把 资源礼包 归到「进度」还是「便利」,把 联盟礼包 归到「社交」还是「竞争」,都带主观判断。真实归属要靠付费行为数据回归(谁买了什么、之后留存如何),属于 X 层——需真实业务环境,命令行不可复现。本节脚本能做的是:给定动机归类,算出覆盖度与价值分层;它做不了的是:告诉你这个归类对不对。

小结

付费点布局 = 动机 × 生命周期 的覆盖矩阵 + 每元玉璧等价的价值分层。本节的 S 层脚本用 config/n09_payment.json 把八个付费点铺成 20 格矩阵,跑出 80% 覆盖度与四个缺口,再把它们归一化成 50%–520% 的三层价值带。付费点摆在哪、值多少,从今天起是两个能被脚本复算的数。

一句话记住本节:先分动机、再铺阶段、最后归一化。矩阵管位置,归一化管价值,两者合起来才是布局。

回到这一章的三节:9.1 铺布局、9.2 拆三类常规付费点、9.3 定节奏与保护线。下一节先把时长绑定层的三个点——首充、月卡、通行证——逐个算清楚。

阅读导航:上一节:目录 · 下一节:9.2 首充、月卡、通行证 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「slg」更多文章

  1. 12.3 留存与付费的联合分析
  2. 12.2 流失预警与召回
  3. 附录 C:全书公式、参数与数据集索引