MeteorCat / 游戏活动设计

Created Wed, 04 Dec 2024 14:32:10 +0800 Modified Wed, 29 Oct 2025 23:24:54 +0800
2579 Words

签到活动

常规来说手游内部的签到活动分为 7天签到(周签到)30天签到(月签到) 的差异, 主要是增加玩家在线留存的手段.

这里采用 erlang 样例处理, 首先需要确定好结构:

%%% @doc 7天签到记录(每周定时入库刷新), 保存进程内存
-record(sign_of_7, {
  ymd :: non_neg_integer(), % Ymd 格式的当天记录: 20241204 之类
  state :: non_neg_integer() % 签到状态, 0 - 初始化| 1 - 可以签到 | 2 - 签到完成
}).

%%% @doc 7天签到日志(签到完成保存), 保存数据库
-record(sign_of_7_log, {
  ymd :: non_neg_integer(), % 同上
  item :: list() % 奖励
}).

这里就是设定 分钟级 别定时器确定上次签到更新时间, 比如 20241201 需要不断和当天 Ymd 做比较之后确认超过7天就刷新进度就行了.

同理30天签到也差不多是这种处理方式, 游戏内存只需要记录标识读取 Excel 道具发送给客户端消息即可, 日志库负责记录签到奖励数据入库.

注意: 日志库和游戏库要分开, 运营负责查询日志库做数据统计, 更像把Excel数据标识写入到数据库记录存底

材料副本

在游戏内部有每日常驻游戏材料本, 这种常驻活动比较时限和奖励固定(当天只能参与1次或者3次, 甚至还需要玩家疲劳值参与).

这种活动更多是奖励性质, 让玩家有固定关卡能够获取到资源, 所以对内部可以直接本地运算之后由服务端给出通关之后资源即可.

比如获取 晋升道具A * 5 这种其实让客户端那边自己运行游玩即可, 只需要结算时候让客户端返回奖励通知即可.

这种小活动性质没必要浪费时间精力在其中, 直接设计游戏玩法之后让玩家游玩返回奖励即可, 本身就是为了保障玩家在线的游戏活动.

自动功能

这里自动功能其实还有底层细分处理差别, 有的是作为核心玩法的官方插件( 相当于官方的挂机自动 收菜 ), 有的只是本来就是游戏玩法部分直接需要等级解锁( 相当于升级到一定登记解锁 自动寻路 ).

这里面如果是作为核心功能解锁则是要放置在服务端来运行并且返回给客户端结果, 比较典型自动寻路就是服务端得出行走路径然后推送给客户端移动.

有些自动功能本身就是为了方便玩家的功能, 最明显就是 扫荡 功能直接跳过游戏阶段获取通关奖励, 可以直接按照战力方式来通关结算奖励, 就没有必要在服务端去浪费CPU演算战斗过程直到得出最后结果.

直接按照战力值确定之后扣除体力值结算游戏奖励即可, 没必要直接服务端浪费性能去演算这个过程

等级功能

游戏当中涉及到不少等级晋升的功能, 包括但不限于 玩家升级|建筑升级|品阶升级 等, 算是游戏方面最常见的功能之一.

这里的等级一般需要策划配表加载, 常规来说以玩家等级表 ( 玩家等级_RoleLevel.xls ) 来说, 应该如下:

level exp awards
1 0 []
2 10 [{“1”:5}]
3 50 [{“1”:10}]
4 100 [{“1”:20},{“2”:50}]
5 150 [{“1”:30},{“2”:100}]
  • level: 玩家角色等级
  • exp: 玩家角色到达该等级所需经验值
  • awards: 玩家达到该等级的奖励数组列表: {道具ID: 道具数量}

这里就是相当比较简单的玩家角色等级, 游戏服务端挂载玩家 Actor 对象基本如下:

-record(role, {
  sid :: non_neg_integer(),
  uid :: non_neg_integer(),
  rid :: non_neg_integer(),

  %% 玩家等级属性
  level = 1 :: non_neg_integer(), % 玩家等级, 默认为 1
  exp = 0 :: non_neg_integer(), % 玩家经验值, 默认为 0
  %% 当获取到玩家经验值的时候加载 excel 配置表对比 exp 是否达到 level + 1 等级的经验条
  %% 升级时候通知客户端并且推送奖励道具信息, 让客户端去启动UI动画更新界面

  other % 其他属性
}).

这里就是玩家升级功能设计, 其他升级也是在此基础追加属性情况.

道具合成

道具合成功能也是最近游戏当中比较常见, 主要包含且不限于 人物碎片|物品碎片 等, 差异比较多就是合成差异数量( 3合1 或者 5合1 等 ).

对于道具合成有两种处理方式:

  1. 在道具表当中直接集成属性, 然后直接查询道具表合成公式即可
  2. 单独抽取合成公式表, 当合成的时候需要另外在这张表确认合成数量

这两种合成都各有利弊, 第一种就是方便汇总单表方便策划直接可视化, 但是属性配表大部分JSON格式不利于注释和理解; 第二种跨越另外表策划不好直观看到对应属性道具(需要对应查合成之后的道具id).

简单集成道具表合成( 游戏物品_Item.xls ):

id name props
10 绿色人物A []
11 绿色人物A碎片 [{“10”:[5]}]

这里 props 就是道具属性, [ {合成道具id : [合成数量]} ], 当玩家提交合成道具的时候直接检索背包内部有对应 id=11 道具数量 5 个即可.

当然这里只适合简单合成公式, 后续还有种交叉复杂合成道具的方式:

比如 道具A 可以通过 简单道具A+简单道具B, 但是又能被 简单道具B+简单道具C 合成, 那么就需要复杂合成公式表.

负责集成道具表合成( 合成公式_Formula.xls ):

id name props
100 木板 [{“10”:[1,10],“12”:[1,5]}]

这里 props 是另外的合成属性, 内部 [{物品ID:[物品数量,产出数量]}], 这里可以的 10|12 假定是两种不同木材id(榕树|柳树), 但是都能合成同一种素材且数量不同( 榕树产出10, 柳树产出5 )

那么玩家需要合成的时候只需要推送合成的成品道具id( id=100 ), 并且选中使用合成的道具( id=10 ) 提交到服务端:

// 伪数据, 仅仅展示需要提交的数据格式
{
  // 最终合成的道具id
  "id": 100,
  // 需要合成的道具素材id
  "use_id": 10
}

提交给服务端之后验证数量符合扣除之后追加即可, 而且后续策划如果扩展不同属性也方便处理, 假设限定玩家等级才允许合成, 则直接直接追加字段:

id name level props
100 木板 5 [{“10”:[1,10],“12”:[1,5]}]

这里假设要求玩家等级必须5级以上才能允许被合成, 可以有效让道具主表看起来简洁.

物品随机性

一般来说游戏当中道具是带有单独维护一张表的情况( 游戏物品_Item.xls ), 但是在物品当中除了固定道具属性的情况, 还有特殊随机性道具品质|数量的情况.

比如以 礼盒|箱子 为例, 这种盒子打开之后是随机获取道具和数量信息:
玩家打开盒子获取到 绿色(白->绿->紫->金品阶) 的道具数量 1~5

这种情况下物品表简略应该是这样:

id name(物品名称信息) rand_ty(随机类型) props(物品属性)
1 游戏金币 0 []
2 游戏水晶 0 []
3 白色碎片 0 []
4 绿色碎片 0 []
5 紫色碎片 0 []
6 金色碎片 0 []
7 神秘碎片盒 1 [{“3”:[50],“4”:[30],“5”:[15],“6”:[5] }]
7 神秘大宝箱 2 [{“1”:[45,1000],“2”:[5,2],“3”:[20,100],“4”:[10,20],“5”:[15,10],“6”:[5,5]}]
  • id: 道具id
  • name: 道具名称
  • rand_ty: 随机类型
  • props: 物品附加属性列表

注意: 随机类型最好是追加上方便以后扩展, 因为单纯物品随机并不只有随机抽单个物品, 还有随机品阶|数量|等级限定|复数道具等情况

这里按照 rand_ty 区分出随机的方式:

  1. 只需要抽取单个道具即可
  2. 抽取指定道具数量

这里物品属性采用 JSON 方式处理, 解析出来的 [ {道具ID: [数据概率]} ][ {道具ID: [道具概率, 道具数量]} ], 后续不断扩展出来随机类型也能追加上属性数组.

以简略的 [{"3":[50],"4":[30],"5":[15],"6":[5] }] 来说:

  • 盒子内部有 4 个道具
  • 抽取概率分别为 50%|30%|15%|5%, 这里合集 100% 演示后续采用合计概率抽取

概率抽取这里不多赘述, 代码自己实现即可, 同时复合属性的随机( 打开抽取指定道具的数量 )逻辑差不多只需要抽取道具单品之后再随机指定内部数量即可.