线性兑换活动换皮逻辑
好的,继续输出线性兑换换皮活动的详细操作步骤。基于模板源码分析,以下是每个步骤的具体操作:
线性兑换换皮活动 — 详细操作手册
Step 1: 配置表配置
1.1 打开 Excel 配置文件
文件路径:
1 | D:\LetsGoEditor\Editor\letsgo_common\excel\xls\H_活动中心配置.xlsx |
操作 Sheet:根据业务选择对应 sheet,对应导出为以下 txt 之一:
ActivityMainConfigForLetsGo_common.txt— 通用活动ActivityMainConfigForLetsGo_modyunying.txt— 特色玩法运营ActivityMainConfigForLetsGo_design.txt— 策划专用
1.2 新增活动行
在对应 sheet 末尾新增一行,填写以下字段:
| 字段名 | 填写值 | 说明 |
|---|---|---|
id |
30999 | 服务端分配的活动ID(必须唯一) |
activityType |
ATLinearRedeem |
线性兑换枚举值 |
activityName |
春日兑换 |
活动显示名 |
activitySubName |
春日好礼 |
子标题(可空) |
activityUIDetail |
UI_ActivityTemplate_ExchangeLinearView |
★ 核心:指向线性兑换模板视图名 |
activityNameType |
ANTLinearRedeem |
名称类型枚举 |
tagId |
1 | 标签组ID(决定在活动中心哪个Tab下展示) |
activityShopType |
142 | 关联兑换商城的 mallId |
activityTaskGroup |
570011,570021 | 任务组ID列表(逗号分隔,对应不同Tab的任务分组) |
backgroundUrl |
spring_exchange_bg.astc |
背景图CDN地址 |
timeInfo.beginTime |
2026-07-20 00:00:00 | 活动开始时间 |
timeInfo.endTime |
2026-08-20 23:59:59 | 活动结束时间 |
suspend |
0 | 是否暂停(0=正常) |
platforms |
1,2,3,4 | 支持平台(1=iOS, 2=Android, 3=PC, 4=H5) |
lowVersion |
1.5.61.25 | 最低客户端版本 |
showInCenter |
true | 是否在活动中心居中展示 |
slapFace |
false | 是否拍脸弹窗 |
1.3 配置 clientParams(多Tab页签名)
在 clientParams 字段中填写 Tab 名称列表(JSON数组格式):
1 | clientParams: ["春日任务", "兑换商店"] |
说明:
- 模板代码第 68 行:
local tabNames = self.Data.clientParams or {} - 每个元素对应一个 Tab,第一个通常是兑换商店Tab(由
ExchangeTabIndex控制,默认=1) - 后续Tab对应
activityTaskGroup中的任务组
1.4 配置 activityParam(追赶机制参数,可选)
如果活动需要”消耗道具追赶到当前进度”功能:
1 | activityParam: [5, 1300001] |
activityParam[1]= 5(追赶倍数)activityParam[2]= 1300001(消耗的道具ID,需在背包表中存在)
模板代码第 218 行读取:
1 | local CoinId = self.ActivityInfo.activityParam and self.ActivityInfo.activityParam[2] |
1.5 导表
完成 Excel 编辑后,执行导表:
1 | # 使用项目导表工具 |
导出后检查 server/data/ActivityMainConfigForLetsGo_common.txt 中是否包含新增的 id: 30999 行。
导表后的数据服务器也会读取,然后服务端把这些配置表字段和玩家的动态数据打包在一起,通过协议推送给客户端
Step 2: 创建 UMG 蓝图
2.1 创建 WidgetBlueprint
在 UE4 编辑器中:
- Content Browser 中右键 →
User Interface→Widget Blueprint - 命名:
UI_ActivityTemplate_ExchangeLinearView(如果美术想用独立名字,如UI_ActivityInstance_SpringExchange,需在配置表和UIWndNameToLuaPath.lua中同步修改) - 保存路径:
/Game/Feature/System/Assets/CommercialRes/Activity/Activity_SpringExchange/Blueprints/
2.2 设置蓝图父类
- 打开蓝图 → 点击
Class Settings(类设置) - Parent Class:选择
MoeLuaWidget(或UMoeLuaUserWidget)
2.3 设置 View 属性(★ 关键)
- 在蓝图编辑器中,选中根节点
UI_ActivityTemplate_ExchangeLinearView - 在 Details 面板找到 View 属性
- 填入 Lua 模块路径:
1
Feature.System.Script.System.Activity.Public.Template.View.UI_ActivityTemplate_ExchangeLinearView
⚠️ 运行时
BaseViewClass.GetLuaViewPathByWndNameOrWidget()会先查UIWndNameToLuaPath.lua,查不到就读 UMG 蓝图的View属性。活动UMG通常走后者。
2.4 绑定 Widget 组件
在蓝图的 Widget Tree 中创建以下组件,名称必须与模板代码一致:
必须绑定的 Widget(来自源码分析)
| Widget 名 | UE4 类型 | 来源代码行 | 说明 |
|---|---|---|---|
w_btn_Exchange_1 |
UButton |
第7行 self.bp.w_btn_Exchange_1 |
兑换/追赶按钮 |
w_img_ActivityTitle |
UImage |
第46行 self.bp.w_img_ActivityTitle |
活动标题图 |
w_img_Activity_BG |
UImage |
第49行 self.bp.w_img_Activity_BG |
活动背景图 |
w_img_BigReward |
UImage |
第52行 self.bp.w_img_BigReward |
大奖励图(可选,如无此功能可省略) |
w_txt_Desc |
ULTGTextBlock |
第135行 self.bp.w_txt_Desc |
活动描述文本 |
w_size_SubTab |
USizeBox |
第159行 self.bp.w_size_SubTab |
子Tab容器(多Tab时显示,无Tab时隐藏) |
兑换商店相关 Widget
| Widget 名 | UE4 类型 | 来源代码行 | 说明 |
|---|---|---|---|
w_list_Exchange |
UGridPanel / UGridSlot |
第97行 self.bp.w_list_Exchange |
兑换商品列表 |
w_sizebox_Btn |
USizeBox |
第246行 self.bp.w_sizebox_Btn |
兑换按钮容器 |
w_sizebox_Exchange |
USizeBox |
第246行 self.bp.w_sizebox_Exchange |
兑换区域容器 |
w_sizebox_Retrieve |
USizeBox |
第246行 self.bp.w_sizebox_Retrieve |
兑回区域容器(隐藏) |
赶/追赶机制相关 Widget(如启用 activityParam)
| Widget 名 | UE4 类型 | 来源代码行 | 说明 |
|---|---|---|---|
w_img_RetrieveIcon |
UImage |
第273行 self.bp.w_img_RetrieveIcon |
追赶道具图标 |
w_img_Exchange |
UImage |
第274行 self.bp.w_img_Exchange |
兑换道具图标 |
w_txt_Retruevetxt |
ULTGTextBlock |
第275行 self.bp.w_txt_Retruevetxt |
“追回”文本 |
w_txt_Exchange_1 |
ULTGTextBlock |
第276行 self.bp.w_txt_Exchange_1 |
“兑换”文本 |
2.5 父类 TaskView 的 Widget(继承自上层模板)
线性兑换模板继承 UI_ActivityTemplate_TaskView,该层也有 Widget 需求。主要的有:
| Widget 名 | 说明 |
|---|---|
w_nameSlot_Activity |
活动子视图插槽(ActivityModel 通过 AddWidget 加载到此插槽) |
w_list_Task |
任务列表(展示任务项) |
w_img_Background |
背景图(可选) |
💡 最简单的方法:复制一个已有的线性兑换活动 UMG 蓝图作为基础,然后只替换图片和布局。
2.6 AssetNameMapping 注册
确保新UMG能被资产加载系统找到。在 AssetNameMapping.txt 中添加:
1 | ui_activitytemplate_exchangelinearview:/Game/Feature/System/Assets/CommercialRes/Activity/Activity_SpringExchange/Blueprints/UI_ActivityTemplate_ExchangeLinearView.UI_ActivityTemplate_ExchangeLinearView_C |
Step 3: 创建实例代码(可选)
判断是否需要
| 情况 | 是否需要写代码 |
|---|---|
| 纯换皮:逻辑完全相同,只换美术 | ❌ 不需要,Step 2 即完成 |
| 需要自定义Tab名称或数量 | ❌ 不需要,通过 clientParams 配置 |
| 需要特殊业务逻辑(如自定义领奖) | ✅ 需要创建实例视图 |
| 需要独立网络协议 | ✅ 需要创建子模型 |
3.1 创建目录结构
1 | D:\LetsGoEditor\Editor\LetsGo\Content\Feature\System\Script\System\Activity\Instance\SpringExchange\ |
3.2 注册子模型路径
文件:Feature/System/Script/System/Activity/Public/ActivityModelPath.lua
在 ActivityModelPath 表中添加:
1 | local ActivityModelPath = { |
注意事项:
- Key(
Activity_Instance_SpringExchange_Model)必须与子模型文件名完全一致,区分大小写 - Value 路径用
.分隔,对应文件系统的/ - 路径末尾不加
.lua
3.3 创建子模型文件
文件:Instance/SpringExchange/Model/Activity_Instance_SpringExchange_Model.lua
1 | local Activity_Instance_SpringExchange_Model = _MOE.class( |
关键点:
- 继承
_MOE.SystemSubModel(不是_MOE.BaseViewClass) - 文件末尾必须有
return Activity_Instance_SpringExchange_Model - 通过
_MOE.Models.ActivityModel.subModels.Activity_Instance_SpringExchange_Model访问
3.4 创建实例视图文件
文件:Instance/SpringExchange/SubView/UI_ActivityInstance_SpringExchange.lua
1 | -- 引用线性兑换模板 |
关键编码规则:
self.super:Init(self, Data)— 注意是:(冒号),传入selfself.super:InitData()— 先调父类再做自己的逻辑- 不能直接
require子模型,必须通过_MOE.Models.ActivityModel.subModels.XXX - 事件监听用
self.child:AddEventListener(OnClose 时自动清理) - ❌ 禁止继承另一个活动实例(只能继承模板)
3.5 注册 UIWndNameToLuaPath(如果用实例视图名)
如果配置表中 activityUIDetail 填的是 UI_ActivityInstance_SpringExchange(实例视图名而非模板名),需要在映射表中注册:
文件:LetsGo/Content/LetsGo/Script/Config/UIWndNameToLuaPath.lua
1 | local UIWndNameToLuaPath = { |
⚠️ 如果
activityUIDetail直接填模板名UI_ActivityTemplate_ExchangeLinearView,则不需要此步骤——运行时通过 UMG 蓝图的View属性定位。
Step 4: 配置统一参数
4.1 通过 clientParams 配置(最常用)
在配置表 Excel 的 clientParams 列填写 JSON 数组:
1 | ["每日任务", "兑换商店", "成就任务"] |
模板代码第 68 行读取:
1 | local tabNames = self.Data.clientParams or {} |
每个元素对应一个 Tab:
index == ExchangeTabIndex的 → 兑换商店 Tab- 其他 → 任务 Tab(按顺序对应
activityTaskGroup中的任务组)
4.2 通过 activityUnifiedParam 配置(如需自定义参数键值)
如果模板需要额外的参数(如特殊奖励ID、显示控制开关),在 activityUnifiedParam 字段中配置。
新增参数键值时,需要先在 ActivityUnifiedDefine.lua 中注册:
1 | -- 文件: Public/ActivityUnifiedDefine.lua |
然后在视图中读取:
1 | local paramValue = _MOE.Models.ActivityModel:GetActivityUnifiedParamByKey( |
Step 5: 红点逻辑
5.1 确认是否需要编码
| 情况 | 是否需要编码 |
|---|---|
| 活动上新红点 | ❌ 服务端自动推送 ActivityReadDotNtf |
| 用户点击后消红 | ❌ 服务端自动处理 |
| 客户端独立判断红点(如任务完成但未领奖) | ✅ 需要编码 |
5.2 如需客户端消红
在视图的 InitData 中调用:
1 | function UI_ActivityInstance_SpringExchange:InitData() |
5.3 如需刷新大厅红点
修改红点状态后必须调用:
1 | _MOE.Models.RedDotModel:UpdateRedDotByType( |
Step 6: 协议绑定(通常不需要)
判断是否需要
| 情况 | 是否需要 |
|---|---|
活动数据通过 GetActivityInfo 获取 |
❌ 不需要 |
| 活动有独立的网络通知 | ✅ 需要 |
| 活动需要监听通用协议(如任务更新) | ❌ 模板父类已处理 |
6.1 在子模型中绑定协议
1 | function Activity_Instance_SpringExchange_Model:BindAllNotify() |
Step 7: 测试验证
7.1 导表检查
1 | # 执行导表,确认无报错 |
7.2 编辑器 PIE 测试
- 打开 UE4 编辑器,点击 Play(PIE 模式)
- 进入大厅
- 打开活动中心
- 检查:
- 活动是否在对应 Tab 下显示
- 活动名称、子标题、背景图是否正确
- 点击活动后能进入线性兑换界面
- Tab 页签是否正确显示(如配置了 clientParams)
- 任务列表是否正确加载
- 兑换商店是否正确显示商品
- 点击兑换按钮能正常兑换
- 红点是否正确显示
- 返回后再次进入数据是否保持
7.3 日志检查
PIE 时查看 Output Log,确认无以下报错:
AddWidget Error, Load Result is nil→ UMG View 属性未设置或路径错误subModels.XXX返回 nil → ActivityModelPath.lua 未注册或路径错误Key not found→ activityUnifiedParam 键值未在 ActivityUnifiedDefine.lua 注册
检查清单
- 配置表已新增活动行(
activityUIDetail指向模板视图名) -
activityTaskGroup已配置正确的任务组 ID -
activityShopType已配置正确的商城 mallId -
clientParams已配置 Tab 名称列表 - 导表成功,无报错
- UMG 蓝图已创建,父类设为
MoeLuaWidget - UMG 蓝图
View属性已设置为模板 Lua 路径 - UMG 蓝图内 Widget 名称与模板代码一致
-
ActivityModelPath.lua已注册子模型路径(如有子模型) -
UIWndNameToLuaPath.lua已注册映射(如用实例视图名) - 编辑器 PIE 测试通过
本文从 LearnByCompany 原始文档 自动同步。
