EP4/EP5 把变现做出来了。但变现有个前提——得有人来玩。一款 F2P 游戏的引擎是两个齿轮咬合:留存供给流量,变现把流量变成钱。这一集(EP6)做留存这半边,三件套:离线收益、每日连签、主题皮肤。

这一集的三件套接上 UI 后,真机里长这样(Unity 实拍)——每日登录的 7 天连签阶梯(D7 金色大奖)+ 皮肤面板(4 套皮肤各带配色预览):

真机每日登录面板

真机皮肤面板

皮肤不是摆设——点"霓虹"装备后,棋盘上的方块配色实时切换(同一局,左前面是经典配色,这里换成霓虹):

换霓虹皮肤后棋盘实时变色

下面讲实现。我想先重点讲一个看似不起眼、却决定了"这套逻辑能不能被验证"的工程决定——怎么处理"今天"

工程关键:把"今天"做成可注入的参数

连签系统天生难测:它依赖"日期变化"。如果代码里直接写 DateTime.Now,那测试就得改系统时钟、或等到明天——根本没法在一次 execute_code 里跑完"首登→次日→断签"。

解法是把时间从逻辑里抽出来:留存账本只认一个 long todayDay(UTC 天序号),由调用方传入。真机用 DayOf(现在的 unix 秒),测试直接传 100, 101, 103

public class RetentionModel : Singleton<RetentionModel>
{
    public readonly Property<long> lastLoginDay = new("ret.lastLoginDay", 0L);
    public readonly Property<int>  loginStreak  = new("ret.loginStreak", 0);
    public readonly Property<int>  totalLoginDays = new("ret.totalLoginDays", 0);

    public CheckInResult CheckIn(long todayDay)
    {
        if (lastLoginDay.Value == todayDay && totalLoginDays.Value > 0)
            return CheckInResult.AlreadyToday;                       // 同日重复

        bool consecutive = lastLoginDay.Value != 0 && todayDay == lastLoginDay.Value + 1;
        loginStreak.Value = consecutive ? loginStreak.Value + 1 : 1; // 接上昨天→+1,否则归1
        lastLoginDay.Value = todayDay;
        totalLoginDays.Value += 1;
        return CheckInResult.NewLogin;
    }

    public static long DayOf(long unixSeconds) => unixSeconds / 86400L;
}

把不确定性(时钟)挡在边界上,核心逻辑就变成纯函数式的——给定 todayDay,输出确定。这一条让连签的 8 个断言能在一秒内跑完。

三件套都复用同一条经济曲线

留存奖励发的也是金币,所以它们全部复用 EP4 的 EconomyConfig——奖励金额跟着玩家进度(最高分)缩放。每日奖励表只配 coef

public int ClaimDaily(long todayDay)
{
    if (Model.CheckIn(todayDay) == CheckInResult.AlreadyToday) return 0;
    int streak = Model.loginStreak.Value;
    var day = Daily.ForStreak(streak);                  // 7 天循环
    int coins = Econ.CoinsFor(day.coinCoef, UserDataModel.Instance.curLevel.Value);
    CoinModel.Instance.ChangeCoin(coins, "daily:d" + streak);
    // ...发道具、广播 DailyRewardClaimedMsg
    return coins;
}

离线收益同理——按离开时长(封顶 8 小时)折算成一个 coef,再走经济曲线:

public int PreviewOffline(long lastQuitUnix, long nowUnix)
{
    if (lastQuitUnix <= 0 || nowUnix <= lastQuitUnix) return 0;
    float hours = (nowUnix - lastQuitUnix) / 3600f;
    if (hours > OfflineCapHours) hours = OfflineCapHours;   // 8h 封顶
    return Econ.CoinsFor(OfflineCoefPerHour * hours, UserDataModel.Instance.curLevel.Value);
}

画出来是这样——左边 7 天连签阶梯(D7 是大奖,最高分 30 整体比最高分 1 高,因为随进度缩放),右边离线收益涨到 8 小时后封顶:

连签阶梯 + 离线收益封顶

封顶是关键设计:没有它,玩家放一周回来一次性领走天量金币,经济就崩了;有它,最优策略变成"每 8 小时回来一次"——这正是离线收益想培养的回流习惯。

主题皮肤:三种解锁规则,数据化

皮肤是消耗变现之外的另一种付费/留存抓手。三种解锁规则(免费 / 金币 / 最高分),全在数据资产里配,加皮肤不改代码:

public UnlockResult TryUnlock(string id)
{
    if (!Cfg.TryGet(id, out var t)) return UnlockResult.NoSuchTheme;
    if (IsOwned(id)) return UnlockResult.Owned;
    switch (t.unlock)
    {
        case UnlockKind.Free:
            AddOwned(id); return UnlockResult.UnlockedFree;
        case UnlockKind.BestScore:
            if (UserDataModel.Instance.bestScore.Value < t.cost) return UnlockResult.NeedScore;
            AddOwned(id); return UnlockResult.UnlockedFree;
        case UnlockKind.Coins:
            if (!CoinModel.Instance.ChangeCoin(-t.cost, "theme:" + id)) return UnlockResult.NeedCoins;
            AddOwned(id); return UnlockResult.Bought;
        default:
            return UnlockResult.NoSuchTheme;
    }
}

金币解锁直接复用 CoinModel.ChangeCoin 的扣费——余额不足它返回 false,解锁自然失败。整个系统又一次站在 EP4 那套货币地基上。

验证:24 条断言

==== 24/24 PASS ====
A 首登发放金币>0 / streak==1 / 领取消息触发
A 同日重复领取==0 / 不增加累计登录
A 次日连签 streak==2
A 断签后 streak 重置为1 / 累计登录==3(去重)
B 离线2h预览>0 / 封顶(100h==8h) / 从未离开==0
B 离线结算余额增加 / 消息金币一致
C 默认拥有classic / 免费解锁 / 金币不足失败 / 金币足够购买且扣费
C 最高分不够失败 / 最高分达标解锁 / 装备成功且广播 / 装备未拥有失败

钉死的核心:连签断签必须归 1(不能漏一天还连着)、同日重复不能重复领、离线必须封顶(100h==8h)、主题金币不足/最高分不够必须解锁失败且不发放、装备只能装已拥有的。留存奖励直接发钱,错一条都是白送或刷取漏洞,所以全用断言锁死。

这一集的产物与诚实的话

  • RetentionModel(登录账本,时间可注入)+ RetentionController(连签 + 离线发放)+ DailyRewardConfig(7 天表)+ ThemeModel/ThemeConfig(皮肤)。
  • 两个数据资产进 Resources,运行时加载。
  • 24 条断言全绿。

诚实地讲:这一集做的是留存的逻辑与数值层。还没做的:弹窗 UI(登录领奖弹窗、离线收益结算弹窗、皮肤商店面板)——那是表现层,和 EP7 一起做;以及真正拉动留存的推送通知(本地/远程 push 提醒玩家回来),那需要平台能力和后台,属于发布阶段。但"明天回来能拿什么、连签怎么算、离线怎么折算、皮肤怎么解锁"——这套决定留存经济的算法,已经建好并验证了。

下一篇 EP7:表现层与手感(juice)——把前 6 集积累的纯逻辑接上动效、音频(程序化合成)、震动反馈,让它从"能跑的系统"变成"摸起来爽的游戏"。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐