Compare commits
44 Commits
ca023844c9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bc1cd45c38 | |||
| 2342b63fc2 | |||
| ac7a3abda9 | |||
| 3b851a195e | |||
| 39a34577da | |||
| fd40217ab8 | |||
| 85c2062318 | |||
| 5df451011c | |||
| 00ca7044c7 | |||
| a4fd3d3092 | |||
| 8ee21e5e80 | |||
| c4ea51b7e6 | |||
| caadd87d8f | |||
| 82fb409a9e | |||
| 0b060b0a74 | |||
| 91b390d577 | |||
| 6f8b599629 | |||
| 3d0b835593 | |||
| f86ffb511e | |||
| 7d0bfc123b | |||
| e63ae56021 | |||
| 4c6c8db1a8 | |||
| 86967bb256 | |||
| e982464cb3 | |||
| ac8c67ffc6 | |||
| 2f7d0fa2f8 | |||
| ca78e9c4cf | |||
| 042bebe9d7 | |||
| 17fbf9fe3f | |||
| 810c3a030c | |||
| cbdf941da5 | |||
| f74883701d | |||
| fe770daf77 | |||
| 3c69445d90 | |||
| f1932667aa | |||
| f2f4d0f382 | |||
| 2cf295f95d | |||
| 9b23cb1d24 | |||
| c509223e08 | |||
| b8f27221b2 | |||
| 7a2436a612 | |||
| a951009dae | |||
| a20eec8d57 | |||
| bb34641bfe |
@@ -1,4 +1,5 @@
|
||||
# 策划 Agent Memory Index
|
||||
|
||||
- [千禧年怀旧文化灵感](nostalgia-culture-inspirations.md) — 电视剧/广播体操/广场舞/电话热线游戏的灵感记录与共识
|
||||
- [千禧年怀旧文化灵感](nostalgia-culture-inspirations.md) — 电视剧/广播体操/广场舞/电话热线/零食/小孩游戏/乡下活动灵感汇总
|
||||
- [建筑与区域规划](building-area-plan.md) — 城市主场景完整建筑清单、可进入室内、新增设施共识
|
||||
- [v0.1执行案状态](v01-execution-status.md) — 三份执行案已通过二次质量门审查,流水线可推进至④程序设计
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
name: building-area-plan
|
||||
description: 城市主场景建筑与区域规划共识,包含完整建筑清单、可进入室内、新增设施
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
## 城市主场景建筑清单(2026-06-10 确认)
|
||||
|
||||
来源:头脑风暴-2026-06-10-建筑与区域规划.md
|
||||
|
||||
### 关键变更(vs 原场景设计)
|
||||
|
||||
- 小伙伴家:原"全部不可进入" → 4家可进入(简化室内)
|
||||
- 包机房:合并进街机店后屋
|
||||
- 废品回收:固定摊位 + 流动收废品车
|
||||
- 秘密基地:多处散布(工地围挡后、平房区死角等)
|
||||
- 新增店铺:粮油店、服装店/裁缝铺、鞋店(主街东侧)、储蓄所(西侧)
|
||||
- 新增设施:棋牌室(纯氛围)、公交站牌(纯装饰)、公共厕所、自行车棚、信报箱
|
||||
|
||||
### 主街布局(东西排列)
|
||||
|
||||
东→:学校操场 | 小卖部 | 粮油店 | 书店 | 服装店 | 鞋店 · 公交站 · 棋牌室 | 储蓄所 | 录像出租 | 网吧 | 街机店 ←西
|
||||
|
||||
### 可进入室内(~12个)
|
||||
|
||||
完整:主角家、合并小卖部、书店、街机店、网吧、录像出租点
|
||||
简化:死党A家(小区内)、死党B家(平房区)、老板儿子家(小卖部后屋)、女班长家(主角家同楼)
|
||||
|
||||
### 不做的元素
|
||||
|
||||
菜地(留乡下)、装修、游泳(河边不下水)
|
||||
|
||||
### How to apply:
|
||||
- 场景与世界观.md 已更新为最新清单
|
||||
- 新增店铺和设施在后续版本逐步添加(见版本映射)
|
||||
- 概念草案不变(冻结),变更记录在系统设计案中
|
||||
@@ -54,3 +54,34 @@ metadata:
|
||||
- 广播体操和广场舞适合作为场景氛围事件
|
||||
- 迈皋桥考据直接用于场景设计的"半城半乡"氛围塑造
|
||||
- 华电子弟学校、工厂宿舍区、菜地、老街都是高还原度的场景元素
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-10 灵感补充
|
||||
|
||||
来源:头脑风暴-2026-06-10-建筑与区域规划.md
|
||||
|
||||
### 重点新发现(⭐⭐⭐)
|
||||
|
||||
1. **钻狗洞的秘密基地** — 多处散布(工地围挡后、平房区死角),高探索叙事价值
|
||||
2. **叠纸飞机** — 纸张收集+折叠选择+飞行结果三层玩法
|
||||
3. **不知道名字的小哥哥** — 一次性邂逅NPC,极高情感潜力微型叙事线
|
||||
4. **体力系统+家庭动态事件** — 吃饭补充体力→不吃炒饭→换速冻水饺→给饭钱
|
||||
5. **爷爷奶奶家亲戚小孩** — 乡下NPC角色体系(之前乡下NPC完全空白)
|
||||
|
||||
### 新零食/小吃(具体品牌品种)
|
||||
|
||||
大大泡泡糖、秀逗(超酸糖)、无花果丝、老鼠屎(盐津葡萄)、跳跳糖、烤鱿鱼、烤里脊
|
||||
|
||||
### 新小孩游戏
|
||||
|
||||
双人拍手/互推游戏、猜在哪个手里、跑步比赛、叠纸飞机
|
||||
|
||||
### 新人物/社交
|
||||
|
||||
- 北方来南方的同学(与"转学生"角色互补)
|
||||
- 等着去别人家(串门文化)
|
||||
|
||||
### 新乡下活动
|
||||
|
||||
钓鱼(鱼竿)、游泳、挤牛奶、喂鸡掏鸡蛋、菜地浇水、打水漂
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
- [UE5.7 Python API](ue57-python-api.md) — 实测 API 差异(set_actor_rotation、new_level、CWD、import 路径、Rotator 关键字参数)
|
||||
- [V01 Bugfix](level-builder-bugfix-v01.md) — 8个白模关卡问题诊断修复(搭建指南6+解析器双重解析+构建器静默fallback)
|
||||
- [BSP Pivot Types](bsp-pivot-types.md) — 38种 BSP 资产实测锚点+自动补偿机制(角落/底边中心/底面中心)
|
||||
- [交互系统架构](interaction-effect-architecture.md) — v1.0 Effect/Action 数据驱动架构(Manager在GI、AInfo Tick、门派生、Prompt独立)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: interaction-effect-architecture
|
||||
description: 交互系统 v1.0 Effect/Action 数据驱动架构决策记录
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
## 交互系统架构决策(v1.0 重构,2026-06-11)
|
||||
|
||||
### 核心架构:Effect/Action 数据驱动
|
||||
|
||||
交互物不关心"交互后发生什么",只配置 Effect(由 Action 组成)交给 EffectManager 执行。
|
||||
|
||||
**Why:** v0.1 用 switch(Type) 硬编码,新增交互类型需改代码。v1.0 配数据即可。
|
||||
|
||||
### Manager 归属
|
||||
- FInteractionManager / FEffectManager 是普通 C++ 类,不是 UObject
|
||||
- 由 ASystemDriver (AInfo) 持有,随 World 生灭
|
||||
- 不依赖 UE Subsystem 生命周期,显式控制创建顺序和 Tick 顺序
|
||||
- 所有 UObject 引用用 TWeakObjectPtr,回调用 TFunction
|
||||
- GameInstance 不持有任何交互系统对象,只有 UPersistenceSubsystem 跨 World
|
||||
|
||||
### 分层规则
|
||||
- 表现层只读 Manager 缓存(getter),不碰 Component
|
||||
- Manager 在选择变化时从 Component 读一次并缓存
|
||||
- 逻辑事件仅用于 "A 影响 B"(如 Consume → Persistence)
|
||||
|
||||
### 协调方式
|
||||
- Character 输入回调通过 ASystemDriver::Get(World) 访问两个 Manager
|
||||
- Driver::BeginPlay 中 TFunction 连线 EffectManager.OnEffectComplete → Manager.OnInteractionFinished
|
||||
- PromptComponent 通过 Driver 获取 Manager,只读缓存
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: subagent-permissions
|
||||
description: 后台子 Agent 需要预授权 Edit/Write 权限才能修改文件
|
||||
metadata:
|
||||
type: feedback
|
||||
---
|
||||
|
||||
后台子 Agent(game-dev 等)无法弹出交互式权限确认,缺少 Edit/Write 授权时会直接被拒绝文件修改。
|
||||
|
||||
**Why:** 首次启动 game-dev 后台 Agent 实现 P-011 时,因 settings.json 缺少 Edit/Write 权限,Agent 只读了技术文档但无法修改源码。
|
||||
|
||||
**How to apply:** 在 `.claude/settings.json` 的 `permissions.allow` 中添加 `"Edit"` 和 `"Write"`(2026-06-10 已添加)。如果后续新增需要后台运行的工具,同样需要预授权对应权限。
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
- [Gitea Token Permission](gitea-token-permission.md) — reviewer token 仅可评论,标签操作需用 PM token
|
||||
- [P-006 Review](p006-review-note.md) — Issue #17 白模搭建审查通过记录
|
||||
- [P-009 Review](p009-review-note.md) — Issue #20 收集系统程序设计审查通过记录
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: p009-review-note
|
||||
description: Issue #20 P-009 收集系统程序设计审查通过记录
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
## P-009 收集系统程序设计审查 (2026-06-10)
|
||||
|
||||
- Issue: #20
|
||||
- 审查类型: 程序设计(质量门 2)
|
||||
- 产出文件: `docs/technical/收集系统-技术方案.md`
|
||||
- 结果: **通过**
|
||||
|
||||
### 审查要点
|
||||
- 技术方案文档路径实际为中文文件名 `收集系统-技术方案.md`(非 Issue 中标注的 `collection-system-tech.md`)
|
||||
- 执行案文件名也是中文:`收集系统-执行案.md`(非 `collection-system-execution.md`)
|
||||
- 6 个检查维度全部通过:执行案覆盖度、美术资源需求、架构清晰度、数据流、技术风险、工作量与拆分建议
|
||||
- 标签操作:移除了 gate:art-fail(30) 和 status:in-review(14),添加了 review:pass(33)
|
||||
@@ -243,6 +243,34 @@ GameConfig/ # 数值配置表
|
||||
|
||||
---
|
||||
|
||||
## Git 工作流(develop 分支模型)
|
||||
|
||||
项目使用 `develop` 长期开发分支。所有 agent 在 develop 上工作,迭代结束时由 PM 发起 PR 合并回 main。
|
||||
|
||||
### 开始工作
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
```
|
||||
|
||||
### 提交文档
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh commit docs <scope> "中文描述"
|
||||
```
|
||||
示例:`bash .claude/scripts/git-workflow.sh commit docs design "交互系统执行案"`
|
||||
|
||||
### 推送
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh push
|
||||
```
|
||||
|
||||
### 完成工作后
|
||||
1. 推送文档到 develop
|
||||
2. 通过 gitea-collab 在对应 Issue 下评论汇报进度
|
||||
3. 更新 Issue 标签为 `status:in-review`
|
||||
4. 启动 `game-reviewer` 子代理
|
||||
|
||||
---
|
||||
|
||||
## 审查交接
|
||||
|
||||
完成工作并发布 Issue 评论后,启动审查流程:
|
||||
|
||||
@@ -221,6 +221,42 @@ skills:
|
||||
|
||||
---
|
||||
|
||||
## Git 工作流(develop 分支模型)
|
||||
|
||||
项目使用 `develop` 长期开发分支。所有 agent 在 develop 上工作,迭代结束时由 PM 发起 PR 合并回 main。
|
||||
|
||||
### 开始开发
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
```
|
||||
确认在 develop 分支上且代码最新。
|
||||
|
||||
### 提交代码
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh commit <type> <scope> "中文描述"
|
||||
```
|
||||
- ⚠️ 只提交自己修改的文件,避免提交其他 agent 的 WIP
|
||||
- 蓝图(.uasset)和 C++ 分开提交
|
||||
- commit message subject ≤ 50 字符
|
||||
|
||||
### 推送
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh push
|
||||
```
|
||||
|
||||
### 完成开发后
|
||||
1. 推送代码到 develop
|
||||
2. 通过 gitea-collab 在对应 Issue 下评论汇报进度
|
||||
3. 更新 Issue 标签为 `status:in-review`
|
||||
4. 启动 `game-reviewer` 子代理
|
||||
|
||||
### 开发中发现 main 有更新
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh catchup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 代码规范
|
||||
|
||||
- C++ 和蓝图遵循 UE5 编码规范
|
||||
|
||||
@@ -103,6 +103,36 @@ skills:
|
||||
|
||||
---
|
||||
|
||||
## Git 工作流(develop 分支模型)
|
||||
|
||||
项目使用 `develop` 长期开发分支,所有 agent 在 develop 上工作。
|
||||
|
||||
### PM 日常
|
||||
```bash
|
||||
# 会话开始时同步
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
```
|
||||
|
||||
### 迭代完成 → 发布
|
||||
当所有 Issue 都 review:pass 且用户确认发布时:
|
||||
|
||||
```bash
|
||||
# 创建 develop → main 的 PR
|
||||
bash .claude/scripts/git-workflow.sh release "迭代名称"
|
||||
# 或手动:
|
||||
# node .claude/skills/gitea-pm/gitea.js --role pm pr create --base main --head develop --title "标题" --body "描述"
|
||||
```
|
||||
|
||||
通知用户在 Gitea 审查并合并 PR。
|
||||
|
||||
### 用户合并后同步
|
||||
```bash
|
||||
bash .claude/scripts/git-workflow.sh post-release
|
||||
```
|
||||
自动同步 main 并将 merge commit 同步回 develop。
|
||||
|
||||
---
|
||||
|
||||
## 决策框架
|
||||
|
||||
### 你可以自主决定:
|
||||
|
||||
@@ -6,23 +6,30 @@
|
||||
|
||||
## 分支策略
|
||||
|
||||
**轻量 Feature Branch** — 单人开发,`main` 永远可玩可编译。
|
||||
**develop 长期开发分支模型** — 单人开发 + 多 Agent 协作。
|
||||
|
||||
```
|
||||
main ─────────── 永远可玩可编译,受保护,禁止直接推送
|
||||
│
|
||||
│ PR (Gitea) ← 里程碑/迭代结束时,PM 发起
|
||||
│
|
||||
└── develop ──── 长期分支,所有 agent 在此工作
|
||||
```
|
||||
|
||||
| 分支 | 生命期 | 说明 |
|
||||
|---|---|---|
|
||||
| `main` | 永久 | 稳定版本,受保护 |
|
||||
| `develop` | 永久 | 日常开发分支,所有 agent 共用 |
|
||||
|
||||
**辅助分支(可选,用于实验):**
|
||||
|
||||
| 分支 | 前缀 | 生命期 | 说明 |
|
||||
|---|---|---|---|
|
||||
| 主线 | `main` | 永久 | 稳定版本,不直接在上面开发 |
|
||||
| 功能 | `feature/` | 合并后删 | 新系统、新功能 |
|
||||
| 修复 | `fix/` | 合并后删 | Bug 修复 |
|
||||
| 原型 | `prototype/` | 实验完即删 | 技术验证,随便写 |
|
||||
| 发布 | `release/` | 永久 | 从 main 切出,版本标记 |
|
||||
|
||||
**命名规则:** `<类型>/<小写连字符描述>`
|
||||
```
|
||||
feature/player-movement fix/camera-clipping release/v0.1
|
||||
```
|
||||
|
||||
**流程:**
|
||||
1. 从 `main` 拉分支 → 2. 开发并提交 → 3. 测试通过后合并回 `main` → 4. 删除分支
|
||||
1. 所有开发在 `develop` 上进行 → 2. 迭代完成时创建 PR → 3. 审查通过后合并回 `main`
|
||||
|
||||
---
|
||||
|
||||
@@ -100,3 +107,33 @@ Host gitea micecola.top
|
||||
**内网地址**(家里用):`ssh://sc-gitea@192.168.1.22:2223/starmen1265/ChildHood.git`
|
||||
|
||||
完整规范见 → [GIT-GUIDE.md](GIT-GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
## 自动化工作流
|
||||
|
||||
`git-workflow.sh` 脚本封装了常用 git 操作:
|
||||
|
||||
```bash
|
||||
# 开始工作:确保在 develop 上且最新
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
|
||||
# 提交修改
|
||||
bash .claude/scripts/git-workflow.sh commit <type> <scope> "中文描述"
|
||||
|
||||
# 推送到远程
|
||||
bash .claude/scripts/git-workflow.sh push
|
||||
|
||||
# 查看状态
|
||||
bash .claude/scripts/git-workflow.sh status
|
||||
```
|
||||
|
||||
### PM 发布流程
|
||||
|
||||
```bash
|
||||
# 创建 develop → main PR
|
||||
bash .claude/scripts/git-workflow.sh release "迭代名称"
|
||||
|
||||
# 用户在 Gitea 合并后同步
|
||||
bash .claude/scripts/git-workflow.sh post-release
|
||||
```
|
||||
|
||||
+36
-60
@@ -7,81 +7,57 @@
|
||||
|
||||
## 一、分支策略
|
||||
|
||||
采用**轻量级 Feature Branch 模型**,避免企业级复杂流程,保持 `main` 分支随时可玩。
|
||||
采用 **develop 长期开发分支模型**,适合单人开发 + 多 AI Agent 协作场景。所有 agent 在 `develop` 上工作,迭代结束时通过 PR 合并回 `main`。
|
||||
|
||||
### 1.1 分支总览
|
||||
|
||||
```
|
||||
main ──────────────────────────────────────── 稳定主线
|
||||
│
|
||||
├── feature/player-movement ───→ 合并后删除
|
||||
├── feature/inventory-system ──→ 合并后删除
|
||||
├── fix/camera-clipping ───────→ 合并后删除
|
||||
├── prototype/procedural-gen ──→ 实验完即删
|
||||
└── release/v0.1 ──────────────→ 永久保留
|
||||
main ──────────── 永远可玩可编译,受保护,禁止直接推送
|
||||
│
|
||||
│ PR (Gitea) ← 里程碑/迭代结束时,PM 发起
|
||||
│
|
||||
└── develop ──── 长期分支,所有 agent 的日常工作分支
|
||||
│
|
||||
├── 程序1 提交代码
|
||||
├── 策划 提交文档
|
||||
├── 程序2 提交代码
|
||||
└── 迭代就绪 → PR develop→main
|
||||
```
|
||||
|
||||
### 1.2 分支类型
|
||||
|
||||
| 分支 | 前缀 | 用途 | 合并目标 | 生命周期 |
|
||||
|---|---|---|---|---|
|
||||
| 主线 | `main` | 稳定可玩版本,每次提交都能编译运行 | — | 永久 |
|
||||
| 功能 | `feature/` | 新系统、新功能开发 | `main` | 完成后删除 |
|
||||
| 修复 | `fix/` | Bug 修复 | `main` | 完成后删除 |
|
||||
| 原型 | `prototype/` | 技术验证、玩法实验 | 合并或丢弃 | 实验完即删 |
|
||||
| 发布 | `release/` | 版本发布标记,只从 `main` 切出 | — | 永久保留 |
|
||||
| 分支 | 用途 | 生命周期 |
|
||||
|---|---|---|
|
||||
| `main` | 稳定可玩版本,受保护 | 永久 |
|
||||
| `develop` | 日常开发,所有 agent 共用 | 永久 |
|
||||
| `prototype/` | 技术验证、玩法实验 | 实验完即删 |
|
||||
| `release/` | 版本发布标记,只从 main 切出 | 永久保留 |
|
||||
|
||||
### 1.3 命名规范
|
||||
|
||||
格式:`<类型>/<简短描述>`,全小写,用连字符分隔单词。
|
||||
### 1.3 工作流程
|
||||
|
||||
```
|
||||
# ✅ 好的命名
|
||||
feature/player-movement
|
||||
feature/inventory-system
|
||||
feature/dialogue-tree
|
||||
fix/camera-clipping-through-walls
|
||||
fix/enemy-ai-stuck-on-navmesh
|
||||
prototype/procedural-dungeon
|
||||
release/v0.1
|
||||
1. 开始工作(agent 自动执行)
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
|
||||
# ❌ 不好的命名
|
||||
my-new-feature
|
||||
fix-bug
|
||||
test
|
||||
feature/AddPlayerMovement
|
||||
2. 开发并提交
|
||||
bash .claude/scripts/git-workflow.sh commit <type> <scope> "描述"
|
||||
|
||||
3. 推送到远程
|
||||
bash .claude/scripts/git-workflow.sh push
|
||||
|
||||
4. 迭代完成,PM 创建 PR
|
||||
bash .claude/scripts/git-workflow.sh release "迭代名称"
|
||||
|
||||
5. 用户在 Gitea 合并后同步
|
||||
bash .claude/scripts/git-workflow.sh post-release
|
||||
```
|
||||
|
||||
### 1.4 工作流程
|
||||
### 1.4 核心原则
|
||||
|
||||
```
|
||||
1. 开始新功能
|
||||
git checkout main
|
||||
git pull
|
||||
git checkout -b feature/xxx
|
||||
|
||||
2. 开发过程中(随时提交)
|
||||
git add .
|
||||
git commit -m "wip(xxx): 进度描述"
|
||||
|
||||
3. 功能完成,测试通过
|
||||
git checkout main
|
||||
git merge feature/xxx
|
||||
git branch -d feature/xxx # 删除已合并分支
|
||||
|
||||
4. 到达里程碑
|
||||
git checkout main
|
||||
git tag -a v0.1.0 -m "第一个可玩原型"
|
||||
git checkout -b release/v0.1
|
||||
git push origin release/v0.1
|
||||
```
|
||||
|
||||
### 1.5 核心原则
|
||||
|
||||
- **`main` 永远可玩**:坏了就留在 feature 分支继续改,不要合并进 main
|
||||
- **功能分支粒度**:一个分支做一件事,不要在一个分支里同时做多个系统
|
||||
- **原型不怕乱**:`prototype/` 分支随便写,验证完再决定合并还是丢弃
|
||||
- **定期清理**:已合并的 feature/fix 分支及时删除,避免分支堆积
|
||||
- **`main` 永远可玩**:通过 develop → main PR 合并,不直接推送
|
||||
- **develop 是工作台**:所有 agent 在 develop 上并行工作
|
||||
- **不同文件不冲突**:各 agent 修改不同文件,可真正并行
|
||||
- **同一文件需协调**:两个 agent 修改同一文件时需顺序执行
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
> 本模板供策划产出关卡执行案时使用。关卡执行案是场景设计案的"空间精度版本"——将氛围描述转化为带有坐标、尺寸和资产建议的结构化搭建指南,供程序在 UE5 编辑器中搭建白模。
|
||||
>
|
||||
> **注意**:交互物和收集品的放置**不在本模板范围内**,由交互系统/收集系统后续在白盒关卡上叠加。
|
||||
>
|
||||
> 文件命名:`关卡-v<XX>-<名称>-执行案.md`(如 `关卡-v01-城郊街区-执行案.md`)
|
||||
> 存放位置:`docs/design/<阶段>/`(与其他执行案同目录)
|
||||
|
||||
@@ -131,30 +133,18 @@
|
||||
| Zx-P02 | | | | | |
|
||||
| ... | | | | | |
|
||||
|
||||
#### 3.x.4 可交互物体标记
|
||||
#### 3.x.4 组合资产标记
|
||||
|
||||
<!-- 引用交互系统执行案中的交互物,此处只标注空间位置 -->
|
||||
<!-- 需要多个 Primitives 拼搭的物件(无直接 BSP 匹配)。如无此类物件可删除本节。 -->
|
||||
|
||||
| 交互编号 | 物件名称 | 交互类型 | 相对原点偏移 (ΔX,ΔY,ΔZ) | 触发半径 (cm) | 引用 |
|
||||
|---------|---------|---------|----------------------|-------------|------|
|
||||
| Zx-I01 | <!-- 如 旧冰箱 --> | <!-- 如 观察 --> | (200,400,10) | <!-- 如 150 --> | 交互系统-执行案 #n |
|
||||
| Zx-I02 | | | | | |
|
||||
| ... | | | | | |
|
||||
|
||||
> 交互类型参照交互系统执行案中的分类(观察/拾取/操作/对话等)。
|
||||
> "引用"列填写交互系统执行案中对应交互物的编号,确保跨文档一致。
|
||||
|
||||
#### 3.x.5 收集品标记
|
||||
|
||||
<!-- 引用收集系统执行案中的收集品,此处只标注空间位置 -->
|
||||
|
||||
| 收集编号 | 物品名称 | 稀有度 | 相对原点偏移 (ΔX,ΔY,ΔZ) | 引用 |
|
||||
|---------|---------|--------|----------------------|------|
|
||||
| Zx-C01 | <!-- 如 彩色弹珠 --> | <!-- 如 普通/稀有 --> | (500,200,0) | 收集系统-执行案 #n |
|
||||
| 编号 | 物件名称 | 期望尺寸 (约, cm) | 推荐拼搭方案 | 说明 |
|
||||
|------|---------|-----------------|-------------|------|
|
||||
| Zx-C01 | <!-- 如 旧收音机 --> | <!-- 如 20x15x12 --> | <!-- 如 Cube(0.2,0.15,0.12) + Cylinder天线 --> | <!-- 如 放在柜台上 --> |
|
||||
| Zx-C02 | | | | |
|
||||
| ... | | | | | |
|
||||
|
||||
> 稀有度影响拾取物的视觉效果标识(普通=白色光,稀有=金色光),具体表现由收集系统技术方案定义。
|
||||
> 组合资产将在搭建指南生成阶段展开为多个 Primitive Actor,并在组合资产清单中记录拼搭方案。
|
||||
> 用户确认后的组合资产方案将回馈到 asset-catalog 模板库,供后续关卡直接引用。
|
||||
|
||||
---
|
||||
|
||||
@@ -183,14 +173,6 @@
|
||||
| G-E02 | | | | | |
|
||||
| ... | | | | | |
|
||||
|
||||
### 4.3 收集品位置汇总
|
||||
|
||||
| # | 物品名称 | 所在区域 | 绝对坐标 (X,Y,Z) | 稀有度 | 引用 |
|
||||
|---|---------|---------|-----------------|--------|------|
|
||||
| 1 | | | | | 收集系统-执行案 #n |
|
||||
| 2 | | | | | |
|
||||
| ... | | | | | |
|
||||
|
||||
---
|
||||
|
||||
## 五、场景边界与遮挡
|
||||
@@ -225,10 +207,10 @@
|
||||
### 策划填写要点
|
||||
|
||||
1. **先确定区域坐标布局**(第二章),确保所有区域在总尺寸内不重叠、流线合理
|
||||
2. **逐区域填写**(第三章),按"结构体 → 布景 → 交互物 → 收集品"的顺序
|
||||
2. **逐区域填写**(第三章),按"结构体 → 布景 → 组合资产"的顺序
|
||||
3. **BSP 资产建议是方向性指引**:写资产类别名和组合方式即可(如 "Wall_400x300 × 2"),不需要写文件路径
|
||||
4. **尺寸以 cm 为单位**,对应 UE5 的 1 uu = 1 cm
|
||||
5. **交叉引用**:交互物和收集品必须引用对应系统执行案中的编号,保持跨文档一致
|
||||
5. **组合资产**:无法用单个 BSP 资产匹配的物件,在 3.x.4 中记录拼搭方案
|
||||
|
||||
### 不要填写的内容
|
||||
|
||||
@@ -237,6 +219,7 @@
|
||||
- ❌ Blueprint 类名
|
||||
- ❌ 精确的硬编码参数值(标注"建议值,可调"并附范围)
|
||||
- ❌ 代码或脚本
|
||||
- ❌ 交互物和收集品位置(由系统后续叠加)
|
||||
|
||||
### 与场景设计案的关系
|
||||
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
#!/usr/bin/env bash
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# git-workflow.sh — ChildHood 项目 Git 工作流自动化
|
||||
#
|
||||
# 基于 develop 长期开发分支模型。
|
||||
# 所有 agent 在 develop 上工作,迭代结束时通过 PR 合并回 main。
|
||||
#
|
||||
# 用法: bash .claude/scripts/git-workflow.sh <command> [args...]
|
||||
#
|
||||
# 命令:
|
||||
# ready 确保在 develop 上且最新
|
||||
# commit <type> <scope> "<msg>" 格式化提交
|
||||
# push 推送 develop 到远程
|
||||
# submit <issue-number> 一键 commit + push(从 Issue 拉取信息)
|
||||
# release [milestone-name] 创建 develop→main 的 PR
|
||||
# post-release 合并后同步 main 和 develop
|
||||
# catchup 将 develop 合并最新 main 的内容
|
||||
# status 显示当前分支和状态
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ─── 配置 ───
|
||||
DEVELOP_BRANCH="develop"
|
||||
MAIN_BRANCH="main"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
GITEA_PM_CLI="node $PROJECT_ROOT/.claude/skills/gitea-pm/gitea.js"
|
||||
GITEA_COLLAB_CLI="node $PROJECT_ROOT/.claude/skills/gitea-collab/gitea.js"
|
||||
|
||||
# ─── 颜色 ───
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||
ok() { echo -e "${GREEN}✅ $*${NC}"; }
|
||||
warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||
fail() { echo -e "${RED}❌ $*${NC}"; exit 1; }
|
||||
|
||||
# ─── 当前分支 ───
|
||||
current_branch() { git rev-parse --abbrev-ref HEAD; }
|
||||
|
||||
# ─── 检查是否有未提交的修改 ───
|
||||
has_changes() { [ -n "$(git status --porcelain)" ]; }
|
||||
|
||||
# ─── 检测 UE5 二进制文件 ───
|
||||
has_ue5_binaries() {
|
||||
git diff --cached --name-only 2>/dev/null | grep -qE '\.(uasset|umap)$'
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# 命令实现
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
cmd_ready() {
|
||||
info "准备工作环境..."
|
||||
|
||||
local branch
|
||||
branch=$(current_branch)
|
||||
|
||||
# 如果不在 develop 上,切换过去
|
||||
if [ "$branch" != "$DEVELOP_BRANCH" ]; then
|
||||
if has_changes; then
|
||||
warn "有未提交的修改,暂存中..."
|
||||
git stash push --include-untracked -m "auto-stash-$(date +%s)"
|
||||
fi
|
||||
git checkout "$DEVELOP_BRANCH" 2>/dev/null || {
|
||||
# 本地没有 develop 分支,从 main 创建
|
||||
info "本地没有 $DEVELOP_BRANCH 分支,从 $MAIN_BRANCH 创建..."
|
||||
git checkout "$MAIN_BRANCH"
|
||||
git pull origin "$MAIN_BRANCH"
|
||||
git checkout -b "$DEVELOP_BRANCH"
|
||||
}
|
||||
fi
|
||||
|
||||
# 拉取最新 develop
|
||||
if git remote get-url origin &>/dev/null; then
|
||||
info "拉取远程 $DEVELOP_BRANCH..."
|
||||
git pull origin "$DEVELOP_BRANCH" 2>/dev/null || {
|
||||
# 远程没有 develop,首次推送
|
||||
warn "远程没有 $DEVELOP_BRANCH 分支,将首次推送"
|
||||
}
|
||||
fi
|
||||
|
||||
local commit_hash
|
||||
commit_hash=$(git rev-parse --short HEAD)
|
||||
ok "已在 $DEVELOP_BRANCH 分支上 (${commit_hash})"
|
||||
}
|
||||
|
||||
cmd_commit() {
|
||||
local type="${1:-}"
|
||||
local scope="${2:-}"
|
||||
local message="${3:-}"
|
||||
|
||||
if [ -z "$type" ] || [ -z "$scope" ] || [ -z "$message" ]; then
|
||||
fail "用法: git-workflow.sh commit <type> <scope> \"<message>\"\n 示例: git-workflow.sh commit feat player \"实现角色跳跃\""
|
||||
fi
|
||||
|
||||
# 校验分支
|
||||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||||
warn "当前不在 $DEVELOP_BRANCH 分支上 (当前: $(current_branch))"
|
||||
read -rp "继续提交? [y/N] " confirm
|
||||
[[ "$confirm" != [yY] ]] && { info "已取消"; return; }
|
||||
fi
|
||||
|
||||
# 暂存所有修改
|
||||
if ! has_changes; then
|
||||
warn "没有检测到修改"
|
||||
return
|
||||
fi
|
||||
|
||||
git add -A
|
||||
|
||||
# UE5 二进制文件检测
|
||||
if has_ue5_binaries; then
|
||||
warn "检测到 .uasset/.umap 文件,请确保 commit message 清楚描述了变更内容"
|
||||
fi
|
||||
|
||||
# 格式化 commit message
|
||||
local commit_msg="${type}(${scope}): ${message}"
|
||||
|
||||
# subject ≤ 50 字符检查(仅消息部分)
|
||||
local msg_len=${#commit_msg}
|
||||
if [ "$msg_len" -gt 72 ]; then
|
||||
warn "提交消息较长 ($msg_len 字符),建议精简"
|
||||
fi
|
||||
|
||||
git commit -m "$commit_msg"
|
||||
ok "已提交: $commit_msg"
|
||||
}
|
||||
|
||||
cmd_push() {
|
||||
local branch
|
||||
branch=$(current_branch)
|
||||
|
||||
info "推送 $branch 到远程..."
|
||||
|
||||
# 设置上游分支(首次)
|
||||
if ! git rev-parse --abbrev-ref "@{upstream}" &>/dev/null; then
|
||||
git push -u origin "$branch"
|
||||
else
|
||||
git push origin "$branch"
|
||||
fi
|
||||
|
||||
ok "已推送 $branch 到远程"
|
||||
}
|
||||
|
||||
cmd_submit() {
|
||||
local issue_number="${1:-}"
|
||||
if [ -z "$issue_number" ]; then
|
||||
fail "用法: git-workflow.sh submit <issue-number>"
|
||||
fi
|
||||
|
||||
info "提交工作 (Issue #$issue_number)..."
|
||||
|
||||
# 从 Issue 拉取标题作为 commit 参考
|
||||
local issue_title=""
|
||||
issue_title=$($GITEA_COLLAB_CLI --role dev issue get "$issue_number" --json 2>/dev/null | grep -o '"title":"[^"]*"' | head -1 | sed 's/"title":"//;s/"//') || true
|
||||
|
||||
# 提交
|
||||
if has_changes; then
|
||||
if [ -n "$issue_title" ]; then
|
||||
info "Issue 标题: $issue_title"
|
||||
fi
|
||||
warn "有未提交的修改,请先运行: git-workflow.sh commit <type> <scope> \"<message>\""
|
||||
return
|
||||
fi
|
||||
|
||||
# 推送
|
||||
cmd_push
|
||||
|
||||
ok "工作已提交到 $DEVELOP_BRANCH (关联 Issue #$issue_number)"
|
||||
}
|
||||
|
||||
cmd_release() {
|
||||
local milestone_name="${1:-}"
|
||||
|
||||
info "准备发布 PR ($DEVELOP_BRANCH → $MAIN_BRANCH)..."
|
||||
|
||||
# 确保在 develop 上
|
||||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||||
fail "请先切换到 $DEVELOP_BRANCH 分支"
|
||||
fi
|
||||
|
||||
# 确保本地最新
|
||||
git pull origin "$DEVELOP_BRANCH"
|
||||
|
||||
# 获取里程碑名称
|
||||
if [ -z "$milestone_name" ]; then
|
||||
# 尝试从当前里程碑获取
|
||||
milestone_name=$($GITEA_PM_CLI --role pm milestone list --state open --json 2>/dev/null | grep -o '"title":"[^"]*"' | head -1 | sed 's/"title":"//;s/"//') || "迭代发布"
|
||||
if [ -z "$milestone_name" ]; then
|
||||
milestone_name="迭代发布"
|
||||
fi
|
||||
fi
|
||||
|
||||
local pr_title="Merge develop → main: ${milestone_name}"
|
||||
|
||||
# 构造 PR body(汇总已关闭的 Issue)
|
||||
local pr_body="## 发布合并\n\n将 \`${DEVELOP_BRANCH}\` 分支的成果合并到 \`${MAIN_BRANCH}\`。\n\n### 里程碑\n${milestone_name}"
|
||||
|
||||
# 创建 PR
|
||||
info "创建 PR: $pr_title"
|
||||
local pr_result
|
||||
pr_result=$($GITEA_PM_CLI --role pm pr create \
|
||||
--base "$MAIN_BRANCH" \
|
||||
--head "$DEVELOP_BRANCH" \
|
||||
--title "$pr_title" \
|
||||
--body "$(echo -e "$pr_body")" \
|
||||
--json 2>&1) || {
|
||||
fail "创建 PR 失败: $pr_result"
|
||||
}
|
||||
|
||||
local pr_number
|
||||
pr_number=$(echo "$pr_result" | grep -o '"number":[0-9]*' | head -1 | sed 's/"number"://') || true
|
||||
|
||||
if [ -n "$pr_number" ]; then
|
||||
ok "PR #$pr_number 已创建: $pr_title"
|
||||
info "请在 Gitea 审查并合并: http://micecola.top:8418/starmen1265/ChildHood/pulls/$pr_number"
|
||||
else
|
||||
ok "PR 已创建,请查看 Gitea"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_post_release() {
|
||||
info "合并后同步..."
|
||||
|
||||
# 同步 main
|
||||
info "同步 $MAIN_BRANCH..."
|
||||
git checkout "$MAIN_BRANCH"
|
||||
git pull origin "$MAIN_BRANCH"
|
||||
ok "$MAIN_BRANCH 已更新"
|
||||
|
||||
# 切回 develop 并合并 main(保持 develop 包含 merge commit)
|
||||
info "同步 $DEVELOP_BRANCH..."
|
||||
git checkout "$DEVELOP_BRANCH"
|
||||
git merge "$MAIN_BRANCH" --no-edit
|
||||
git push origin "$DEVELOP_BRANCH"
|
||||
ok "$DEVELOP_BRANCH 已同步(包含 $MAIN_BRANCH 的 merge commit)"
|
||||
|
||||
local commit_hash
|
||||
commit_hash=$(git rev-parse --short HEAD)
|
||||
ok "完成,当前在 $DEVELOP_BRANCH (${commit_hash})"
|
||||
}
|
||||
|
||||
cmd_catchup() {
|
||||
info "将 develop 跟上最新的 $MAIN_BRANCH..."
|
||||
|
||||
if [ "$(current_branch)" != "$DEVELOP_BRANCH" ]; then
|
||||
fail "请先切换到 $DEVELOP_BRANCH 分支"
|
||||
fi
|
||||
|
||||
git fetch origin
|
||||
git merge "origin/$MAIN_BRANCH" --no-edit
|
||||
ok "$DEVELOP_BRANCH 已合并最新 $MAIN_BRANCH"
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
local branch
|
||||
branch=$(current_branch)
|
||||
local commit_hash
|
||||
commit_hash=$(git rev-parse --short HEAD)
|
||||
local changed
|
||||
changed=$(git status --porcelain | wc -l | tr -d ' ')
|
||||
|
||||
echo -e "${BLUE}═══ Git 工作流状态 ═══${NC}"
|
||||
echo " 当前分支: ${branch} (${commit_hash})"
|
||||
|
||||
if [ "$branch" = "$DEVELOP_BRANCH" ]; then
|
||||
echo -e " ${GREEN}✓ 在 develop 开发分支上${NC}"
|
||||
elif [ "$branch" = "$MAIN_BRANCH" ]; then
|
||||
echo -e " ${YELLOW}⚠ 在 main 分支上,请切换到 develop 开始工作${NC}"
|
||||
else
|
||||
echo -e " ${YELLOW}⚠ 在非标准分支上: $branch${NC}"
|
||||
fi
|
||||
|
||||
echo " 未提交修改: ${changed} 个文件"
|
||||
|
||||
if [ "$changed" -gt 0 ]; then
|
||||
echo ""
|
||||
git status --short
|
||||
fi
|
||||
|
||||
# 远程同步状态
|
||||
if git rev-parse "@{upstream}" &>/dev/null; then
|
||||
local ahead behind
|
||||
ahead=$(git rev-list --count "@{upstream}..HEAD" 2>/dev/null || echo "0")
|
||||
behind=$(git rev-list --count "HEAD..@{upstream}" 2>/dev/null || echo "0")
|
||||
echo " 远程状态: ahead ${ahead}, behind ${behind}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# 入口
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
case "${1:-}" in
|
||||
ready) cmd_ready ;;
|
||||
commit) shift; cmd_commit "$@" ;;
|
||||
push) cmd_push ;;
|
||||
submit) shift; cmd_submit "$@" ;;
|
||||
release) shift; cmd_release "$@" ;;
|
||||
post-release) cmd_post_release ;;
|
||||
catchup) cmd_catchup ;;
|
||||
status) cmd_status ;;
|
||||
*)
|
||||
echo "git-workflow.sh — ChildHood 项目 Git 工作流自动化"
|
||||
echo ""
|
||||
echo "用法: bash .claude/scripts/git-workflow.sh <command> [args...]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " ready 确保在 develop 上且最新"
|
||||
echo " commit <type> <scope> \"<msg>\" 格式化提交"
|
||||
echo " push 推送 develop 到远程"
|
||||
echo " submit <issue-number> 推送并关联 Issue"
|
||||
echo " release [milestone-name] 创建 develop→main PR"
|
||||
echo " post-release 合并后同步 main 和 develop"
|
||||
echo " catchup 将 develop 合并最新 main"
|
||||
echo " status 显示当前分支和状态"
|
||||
echo ""
|
||||
echo "工作流模型: develop 长期开发分支 → 迭代完成时 PR 合并回 main"
|
||||
;;
|
||||
esac
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(dir:*)",
|
||||
"Bash(git:*)",
|
||||
"mcp__web-reader__webReader",
|
||||
"mcp__zread__get_repo_structure",
|
||||
"mcp__web-search-prime__webSearchPrime",
|
||||
"WebSearch",
|
||||
"Read:*",
|
||||
"Bash(\"C:/Program Files/Epic Games/UE_5.7/Engine/Build/BatchFiles/Build.bat\":*)"
|
||||
"Read",
|
||||
"Edit",
|
||||
"Write",
|
||||
"Bash"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
|
||||
@@ -148,7 +148,43 @@ node .claude/skills/gitea-collab/gitea.js --role reviewer issue labels <number>
|
||||
|
||||
---
|
||||
|
||||
## 7. 汇报模板
|
||||
## 7. PR 查询
|
||||
|
||||
非 PM 角色可以查看 PR 状态(创建和合并由 PM 负责):
|
||||
|
||||
```bash
|
||||
# 列出 PR
|
||||
node .claude/skills/gitea-collab/gitea.js --role <角色名> pr list
|
||||
|
||||
# 查看 PR 详情
|
||||
node .claude/skills/gitea-collab/gitea.js --role <角色名> pr get <number>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Git 工作流
|
||||
|
||||
所有 agent 在 `develop` 长期开发分支上工作:
|
||||
|
||||
```bash
|
||||
# 开始工作时:确保在 develop 上
|
||||
bash .claude/scripts/git-workflow.sh ready
|
||||
|
||||
# 提交代码/文档
|
||||
bash .claude/scripts/git-workflow.sh commit <type> <scope> "中文描述"
|
||||
|
||||
# 推送到远程
|
||||
bash .claude/scripts/git-workflow.sh push
|
||||
|
||||
# 查看当前状态
|
||||
bash .claude/scripts/git-workflow.sh status
|
||||
```
|
||||
|
||||
详见 `.claude/refs/GIT-GUIDE-LITE.md` 的"自动化工作流"章节。
|
||||
|
||||
---
|
||||
|
||||
## 9. 汇报模板
|
||||
|
||||
### 策划汇报
|
||||
|
||||
|
||||
@@ -222,6 +222,27 @@ class GiteaAPI {
|
||||
});
|
||||
}
|
||||
|
||||
// ====== Pull Requests ======
|
||||
|
||||
listPullRequests(params = {}) {
|
||||
return this.request('GET', '/pulls', null, { state: 'open', limit: 50, ...params });
|
||||
}
|
||||
|
||||
getPullRequest(number) {
|
||||
return this.request('GET', `/pulls/${number}`);
|
||||
}
|
||||
|
||||
createPullRequest(data) {
|
||||
return this.request('POST', '/pulls', data);
|
||||
}
|
||||
|
||||
mergePullRequest(number, data = {}) {
|
||||
return this.request('POST', `/pulls/${number}/merge`, {
|
||||
Do: data.style || 'merge',
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 辅助方法 ======
|
||||
|
||||
/** 通过名称查找标签,返回 ID(不存在则返回 null) */
|
||||
|
||||
@@ -520,6 +520,84 @@ cmd.pipeline = {
|
||||
},
|
||||
};
|
||||
|
||||
// ──────── pr ────────
|
||||
|
||||
cmd.pr = {
|
||||
async list(api, opts) {
|
||||
const params = {};
|
||||
if (opts.options.state) params.state = opts.options.state;
|
||||
if (opts.options.base) params.base = opts.options.base;
|
||||
if (opts.options.head) params.head = opts.options.head;
|
||||
|
||||
const prs = await api.listPullRequests(params);
|
||||
out(prs);
|
||||
if (!opts.options.json) {
|
||||
outText(`\n🔀 Pull Requests (${prs.length || 0})\n`);
|
||||
if (!prs || !prs.length) { outText(' (无)'); return; }
|
||||
table(
|
||||
['#', '标题', '状态', 'Base', 'Head', '合并'],
|
||||
prs.map(p => [
|
||||
p.number,
|
||||
truncate(p.title, 35),
|
||||
p.state,
|
||||
p.base?.ref || '—',
|
||||
p.head?.ref || '—',
|
||||
p.merged ? '✅' : '—',
|
||||
])
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async get(api, opts) {
|
||||
const num = opts.rest[0];
|
||||
if (!num) { fail('用法: pr get <number>'); return; }
|
||||
const pr = await api.getPullRequest(num);
|
||||
out(pr);
|
||||
if (!opts.options.json) {
|
||||
outText(`\n🔀 PR #${pr.number}: ${pr.title}`);
|
||||
outText(` 状态: ${pr.state}`);
|
||||
outText(` ${pr.base?.ref} ← ${pr.head?.ref}`);
|
||||
outText(` 合并: ${pr.merged ? '✅ 已合并' : '❌ 未合并'}`);
|
||||
if (pr.body) {
|
||||
outText(`\n--- Body ---\n${pr.body.slice(0, 500)}${pr.body.length > 500 ? '…' : ''}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async create(api, opts) {
|
||||
const base = opts.options.base || 'main';
|
||||
const head = opts.options.head;
|
||||
const title = opts.options.title;
|
||||
const body = opts.options.body || '';
|
||||
|
||||
if (!head || !title) {
|
||||
fail('用法: pr create --head <分支> --title "标题" [--base main] [--body "描述"]');
|
||||
return;
|
||||
}
|
||||
|
||||
const pr = await api.createPullRequest({ base, head, title, body });
|
||||
out(pr);
|
||||
if (!opts.options.json) {
|
||||
ok(`PR #${pr.number} 已创建: ${pr.title}`);
|
||||
outText(` ${pr.html_url}`);
|
||||
}
|
||||
},
|
||||
|
||||
async merge(api, opts) {
|
||||
const num = opts.rest[0];
|
||||
if (!num) { fail('用法: pr merge <number> [--style merge|squash|rebase]'); return; }
|
||||
const style = opts.options.style || 'merge';
|
||||
|
||||
const pr = await api.getPullRequest(num);
|
||||
if (pr.merged) { fail(`PR #${num} 已合并,无需重复操作`); return; }
|
||||
if (pr.mergeable === false) { fail(`PR #${num} 存在冲突,无法自动合并。请先解决冲突。`); return; }
|
||||
|
||||
const result = await api.mergePullRequest(num, { style });
|
||||
out(result);
|
||||
if (!opts.options.json) ok(`PR #${num} 已合并 (${style})`);
|
||||
},
|
||||
};
|
||||
|
||||
// ──────── test ────────
|
||||
|
||||
cmd.test = {
|
||||
@@ -682,6 +760,11 @@ Gitea CLI — 项目管理工具
|
||||
pipeline status 查看当前流水线进度
|
||||
pipeline update <#> 更新 Pipeline 字段 --field <阶段|当前迭代> --value <值>
|
||||
|
||||
pr list 列出 Pull Requests [--state open|closed|all] [--base <分支>] [--head <分支>]
|
||||
pr get <#> 查看 PR 详情
|
||||
pr create 创建 PR --head <分支> --title "标题" [--base main] [--body "描述"]
|
||||
pr merge <#> 合并 PR [--style merge|squash|rebase]
|
||||
|
||||
test 验证所有 API 接口
|
||||
|
||||
角色自动映射:
|
||||
|
||||
@@ -218,7 +218,36 @@ Pipeline Tracker 是一个 Meta Issue,仅记录**无法从 Issue/Milestone 推
|
||||
|
||||
---
|
||||
|
||||
## 8. 标签体系
|
||||
## 8. PR 操作(发布合并)
|
||||
|
||||
迭代完成时,PM 负责创建 develop → main 的 PR:
|
||||
|
||||
```bash
|
||||
# 列出当前 PR
|
||||
node .claude/skills/gitea-pm/gitea.js --role pm pr list
|
||||
|
||||
# 创建发布 PR
|
||||
bash .claude/scripts/git-workflow.sh release "迭代名称"
|
||||
|
||||
# 或手动创建
|
||||
node .claude/skills/gitea-pm/gitea.js --role pm pr create \
|
||||
--base main --head develop \
|
||||
--title "Merge develop → main: 迭代名称" \
|
||||
--body "发布描述"
|
||||
|
||||
# 查看 PR 详情
|
||||
node .claude/skills/gitea-pm/gitea.js --role pm pr get <number>
|
||||
|
||||
# 合并 PR(用户审查确认后)
|
||||
node .claude/skills/gitea-pm/gitea.js --role pm pr merge <number> --style merge
|
||||
|
||||
# 合并后同步
|
||||
bash .claude/scripts/git-workflow.sh post-release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 标签体系
|
||||
|
||||
从 `gitea-config.json` 的 `labels` 字段定义。`label init` 命令从此配置创建标签。
|
||||
|
||||
|
||||
@@ -222,6 +222,27 @@ class GiteaAPI {
|
||||
});
|
||||
}
|
||||
|
||||
// ====== Pull Requests ======
|
||||
|
||||
listPullRequests(params = {}) {
|
||||
return this.request('GET', '/pulls', null, { state: 'open', limit: 50, ...params });
|
||||
}
|
||||
|
||||
getPullRequest(number) {
|
||||
return this.request('GET', `/pulls/${number}`);
|
||||
}
|
||||
|
||||
createPullRequest(data) {
|
||||
return this.request('POST', '/pulls', data);
|
||||
}
|
||||
|
||||
mergePullRequest(number, data = {}) {
|
||||
return this.request('POST', `/pulls/${number}/merge`, {
|
||||
Do: data.style || 'merge', // merge | squash | rebase
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 辅助方法 ======
|
||||
|
||||
/** 通过名称查找标签,返回 ID(不存在则返回 null) */
|
||||
|
||||
@@ -520,6 +520,87 @@ cmd.pipeline = {
|
||||
},
|
||||
};
|
||||
|
||||
// ──────── pr ────────
|
||||
|
||||
cmd.pr = {
|
||||
async list(api, opts) {
|
||||
const params = {};
|
||||
if (opts.options.state) params.state = opts.options.state;
|
||||
if (opts.options.base) params.base = opts.options.base;
|
||||
if (opts.options.head) params.head = opts.options.head;
|
||||
|
||||
const prs = await api.listPullRequests(params);
|
||||
out(prs);
|
||||
if (!opts.options.json) {
|
||||
outText(`\n🔀 Pull Requests (${prs.length || 0})\n`);
|
||||
if (!prs || !prs.length) { outText(' (无)'); return; }
|
||||
table(
|
||||
['#', '标题', '状态', 'Base', 'Head', '合并'],
|
||||
prs.map(p => [
|
||||
p.number,
|
||||
truncate(p.title, 35),
|
||||
p.state,
|
||||
p.base?.ref || '—',
|
||||
p.head?.ref || '—',
|
||||
p.merged ? '✅' : '—',
|
||||
])
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async get(api, opts) {
|
||||
const num = opts.rest[0];
|
||||
if (!num) { fail('用法: pr get <number>'); return; }
|
||||
const pr = await api.getPullRequest(num);
|
||||
out(pr);
|
||||
if (!opts.options.json) {
|
||||
outText(`\n🔀 PR #${pr.number}: ${pr.title}`);
|
||||
outText(` 状态: ${pr.state}`);
|
||||
outText(` ${pr.base?.ref} ← ${pr.head?.ref}`);
|
||||
outText(` 合并: ${pr.merged ? '✅ 已合并' : '❌ 未合并'}`);
|
||||
outText(` 创建: ${pr.created_at?.slice(0, 10)}`);
|
||||
outText(` 更新: ${pr.updated_at?.slice(0, 10)}`);
|
||||
if (pr.body) {
|
||||
outText(`\n--- Body ---\n${pr.body.slice(0, 500)}${pr.body.length > 500 ? '…' : ''}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async create(api, opts) {
|
||||
const base = opts.options.base || 'main';
|
||||
const head = opts.options.head;
|
||||
const title = opts.options.title;
|
||||
const body = opts.options.body || '';
|
||||
|
||||
if (!head || !title) {
|
||||
fail('用法: pr create --head <分支> --title "标题" [--base main] [--body "描述"]');
|
||||
return;
|
||||
}
|
||||
|
||||
const pr = await api.createPullRequest({ base, head, title, body });
|
||||
out(pr);
|
||||
if (!opts.options.json) {
|
||||
ok(`PR #${pr.number} 已创建: ${pr.title}`);
|
||||
outText(` ${pr.html_url}`);
|
||||
}
|
||||
},
|
||||
|
||||
async merge(api, opts) {
|
||||
const num = opts.rest[0];
|
||||
if (!num) { fail('用法: pr merge <number> [--style merge|squash|rebase]'); return; }
|
||||
const style = opts.options.style || 'merge';
|
||||
|
||||
// 先检查 PR 状态
|
||||
const pr = await api.getPullRequest(num);
|
||||
if (pr.merged) { fail(`PR #${num} 已合并,无需重复操作`); return; }
|
||||
if (pr.mergeable === false) { fail(`PR #${num} 存在冲突,无法自动合并。请先解决冲突。`); return; }
|
||||
|
||||
const result = await api.mergePullRequest(num, { style });
|
||||
out(result);
|
||||
if (!opts.options.json) ok(`PR #${num} 已合并 (${style})`);
|
||||
},
|
||||
};
|
||||
|
||||
// ──────── test ────────
|
||||
|
||||
cmd.test = {
|
||||
@@ -682,6 +763,11 @@ Gitea CLI — 项目管理工具
|
||||
pipeline status 查看当前流水线进度
|
||||
pipeline update <#> 更新 Pipeline 字段 --field <阶段|当前迭代> --value <值>
|
||||
|
||||
pr list 列出 Pull Requests [--state open|closed|all] [--base <分支>] [--head <分支>]
|
||||
pr get <#> 查看 PR 详情
|
||||
pr create 创建 PR --head <分支> --title "标题" [--base main] [--body "描述"]
|
||||
pr merge <#> 合并 PR [--style merge|squash|rebase]
|
||||
|
||||
test 验证所有 API 接口
|
||||
|
||||
角色自动映射:
|
||||
|
||||
@@ -42,14 +42,14 @@ tools/world-sketcher/
|
||||
|
||||
## 画笔颜色 → 材质映射
|
||||
|
||||
| 画笔 | 颜色 | 地形 | UE 材质 |
|
||||
|------|------|------|---------|
|
||||
| 道路 Road | `#909090` 灰 | 道路 | MI_DevGray |
|
||||
| 建筑 Building | `#E07020` 橙 | 建筑物 | MI_DevOrange |
|
||||
| 水域 Water | `#40A0D0` 天蓝 | 河流/水塘 | MI_DevSkyBlue |
|
||||
| 植被 Greenery | `#40B040` 绿 | 树木/草地 | MI_DevGreen |
|
||||
| 不可通行 Blocked | `#A07040` 棕 | 山体/围墙 | MI_DevBrown |
|
||||
| 区域 Zone | `#D04040` 红 | 区域划分 | MI_DevRed |
|
||||
| 画笔 | 颜色 | 地形 | UE 材质 | 默认高度 |
|
||||
|------|------|------|---------|---------|
|
||||
| 道路 Road | `#909090` 灰 | 道路 | MI_DevGray | — |
|
||||
| 建筑 Building | `#E07020` 橙 | 建筑物 | MI_DevOrange | 3m |
|
||||
| 水域 Water | `#40A0D0` 天蓝 | 河流/水塘 | MI_DevSkyBlue | — |
|
||||
| 植被 Greenery | `#40B040` 绿 | 树木/草地 | MI_DevGreen | 2m |
|
||||
| 不可通行 Blocked | `#A07040` 棕 | 山体/围墙 | MI_DevBrown | 3m |
|
||||
| 区域 Zone | `#D04040` 红 | 区域划分 | MI_DevRed | 3m |
|
||||
|
||||
---
|
||||
|
||||
@@ -71,12 +71,15 @@ tools/world-sketcher/
|
||||
5. 进入 L2 后用建筑、道路等画笔细化区域内部
|
||||
6. 完成后点"保存全部",将文件保存到 `output/` 目录
|
||||
|
||||
### 步骤 3:AI 分析草图
|
||||
### 步骤 3:AI 读取布局数据
|
||||
|
||||
1. 读取 PNG 草图(使用 vision 分析)
|
||||
2. 读取 JSON 伴随数据(scale、elements、层级关系)
|
||||
3. 交叉参考场景设计案 `场景-v<XX>-<名称>.md` 的氛围描述
|
||||
4. 产出布局解读文档
|
||||
**数据源以 JSON 为准,不依赖 PNG 像素分析。**
|
||||
|
||||
1. 读取 JSON 布局数据(`*-scene.json`):elements(含 `height_m`、`connections`)、regions(含 `bounds_world_m`)、层级关系
|
||||
2. 交叉参考场景设计案 `场景-v<XX>-<名称>.md` 的氛围描述,将 JSON 区域与场景设计案的区域描述建立映射
|
||||
3. 如需视觉确认,可参考预览 PNG(非必须,仅用于核对区域形状)
|
||||
|
||||
> **说明**:PNG 文件仍保存在 ZIP 中用于保存/加载画布,但 AI 分析流程以结构化 JSON 为准。
|
||||
|
||||
### 步骤 4:产出布局解读文档
|
||||
|
||||
@@ -99,8 +102,8 @@ tools/world-sketcher/
|
||||
## L1 场景总览
|
||||
|
||||
### 识别区域
|
||||
| 区域编号 | 名称 | 推测坐标范围 (cm) | 推测尺寸 | 地形类型 | 标识色建议 |
|
||||
|---------|------|-------------------|---------|---------|-----------|
|
||||
| 区域编号 | 名称 | 推测坐标范围 (cm) | 推测尺寸 | 地形类型 | 高度 (m) | 连通到 | 标识色建议 |
|
||||
|---------|------|-------------------|---------|---------|---------|--------|-----------|
|
||||
|
||||
### 识别道路/河流
|
||||
| 编号 | 名称 | 类型 | 走向 | 长度 |
|
||||
@@ -111,7 +114,7 @@ tools/world-sketcher/
|
||||
## L2 区域详图(如有)
|
||||
|
||||
### <区域名>
|
||||
| 编号 | 名称 | 类型 | 推测坐标 | 尺寸 |
|
||||
| 编号 | 名称 | 类型 | 推测坐标 | 尺寸 | 高度 (m) | 连通到 |
|
||||
|
||||
## 待确认问题
|
||||
1. ...
|
||||
@@ -120,6 +123,12 @@ tools/world-sketcher/
|
||||
- ...
|
||||
```
|
||||
|
||||
**数据来源说明**:
|
||||
- 区域坐标、尺寸:来自 JSON 中 `regions[].bounds_world_m`,乘以 100 转为 cm
|
||||
- 高度:来自 JSON 中 `elements[].height_m`,直接采用(无需 AI 推断)
|
||||
- 连通关系:来自 JSON 中 `elements[].connections`,直接采用(无需 AI 推断)
|
||||
- 地形类型和标识色:来自 JSON 中 `elements[].type` → brush_legend 映射
|
||||
|
||||
### 步骤 5:用户确认
|
||||
|
||||
将解读文档呈现给用户,等待用户确认或修正。确认后,该文档作为关卡执行案的前置输入。
|
||||
@@ -143,3 +152,5 @@ tools/world-sketcher/
|
||||
- 坐标系与 `zone_config.py` 一致:原点西南角,X+ 东,Y+ 北,单位 cm
|
||||
- AI 解读时如有不确定之处,**必须**列入"待确认问题",不要自行假设
|
||||
- L3 建筑内部本期不实现,仅预留 `has_interior` 标记
|
||||
- **高度 (`height_m`)**:由用户在双击命名时输入,AI 直接采用,不做推断
|
||||
- **连通关系 (`connections`)**:由用户在双击命名时勾选,双向同步,AI 直接采用
|
||||
|
||||
@@ -111,6 +111,11 @@ scripts/.gitea-tokens.json
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# ==============================
|
||||
# AI 生图工具 — API 密钥
|
||||
# ==============================
|
||||
ai-art-research/.env
|
||||
|
||||
# ==============================
|
||||
# 其他
|
||||
# ==============================
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -25,6 +25,7 @@ public class ChildHood : ModuleRules
|
||||
|
||||
PublicIncludePaths.AddRange(new string[] {
|
||||
"ChildHood",
|
||||
"ChildHood/Interaction",
|
||||
"ChildHood/Variant_Platforming",
|
||||
"ChildHood/Variant_Platforming/Animation",
|
||||
"ChildHood/Variant_Combat",
|
||||
|
||||
@@ -11,60 +11,79 @@
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
#include "InputActionValue.h"
|
||||
#include "ChildHood.h"
|
||||
#include "Interaction/InteractionManager.h"
|
||||
|
||||
AChildHoodCharacter::AChildHoodCharacter()
|
||||
{
|
||||
// Set size for collision capsule
|
||||
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
|
||||
|
||||
|
||||
// Don't rotate when the controller rotates. Let that just affect the camera.
|
||||
bUseControllerRotationPitch = false;
|
||||
bUseControllerRotationYaw = false;
|
||||
bUseControllerRotationRoll = false;
|
||||
|
||||
// Configure character movement
|
||||
GetCharacterMovement()->bOrientRotationToMovement = true;
|
||||
GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f);
|
||||
|
||||
// Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint
|
||||
// instead of recompiling to adjust them
|
||||
GetCharacterMovement()->JumpZVelocity = 500.f;
|
||||
GetCharacterMovement()->AirControl = 0.35f;
|
||||
GetCharacterMovement()->MaxWalkSpeed = 500.f;
|
||||
GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
|
||||
GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
|
||||
GetCharacterMovement()->BrakingDecelerationFalling = 1500.0f;
|
||||
// Configure character movement — v0.1 player controller tech design parameters
|
||||
auto* CMC = GetCharacterMovement();
|
||||
CMC->bOrientRotationToMovement = true; // 角色朝移动方向旋转
|
||||
CMC->RotationRate = FRotator(0.0f, 720.0f, 0.0f); // 转向速度 720°/s(远快于鼠标 150°/s)
|
||||
CMC->MaxWalkSpeed = 450.0f; // 跑步速度 4.5 m/s
|
||||
CMC->MaxAcceleration = 2250.0f; // 起步加速 0.2s (450/0.2)
|
||||
CMC->BrakingDecelerationWalking = 1500.0f; // 停止减速 0.3s (450/0.3)
|
||||
CMC->BrakingDecelerationFalling = 1500.0f;
|
||||
CMC->MinAnalogWalkSpeed = 20.f;
|
||||
|
||||
// Create a camera boom (pulls in towards the player if there is a collision)
|
||||
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
||||
CameraBoom->SetupAttachment(RootComponent);
|
||||
CameraBoom->TargetArmLength = 400.0f;
|
||||
CameraBoom->TargetArmLength = 350.0f; // 摄像机距离 3.5m
|
||||
CameraBoom->SocketOffset = FVector(0.f, 0.f, 80.f); // 摄像机高度 0.8m(头部上方)
|
||||
CameraBoom->bUsePawnControlRotation = true;
|
||||
|
||||
// 摄像机软跟随
|
||||
CameraBoom->bEnableCameraLag = true;
|
||||
CameraBoom->CameraLagSpeed = 6.0f;
|
||||
CameraBoom->bEnableCameraRotationLag = false;
|
||||
|
||||
// 摄像机碰撞处理
|
||||
CameraBoom->bDoCollisionTest = true;
|
||||
CameraBoom->ProbeSize = 12.0f;
|
||||
CameraBoom->ProbeChannel = ECC_Camera;
|
||||
|
||||
// Create a follow camera
|
||||
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
||||
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
||||
FollowCamera->bUsePawnControlRotation = false;
|
||||
|
||||
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
|
||||
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
|
||||
// 创建交互管理器组件
|
||||
InteractionManager = CreateDefaultSubobject<UInteractionManager>(TEXT("InteractionManager"));
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
// Set up action bindings
|
||||
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
|
||||
|
||||
// Jumping
|
||||
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
|
||||
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
|
||||
|
||||
// Moving
|
||||
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Move);
|
||||
|
||||
// Looking (gamepad + mouse)
|
||||
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Look);
|
||||
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Look);
|
||||
|
||||
// Looking
|
||||
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Look);
|
||||
// Interaction — delegates to InteractionManager
|
||||
if (InteractAction)
|
||||
{
|
||||
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnInteract);
|
||||
}
|
||||
if (CancelAction)
|
||||
{
|
||||
EnhancedInputComponent->BindAction(CancelAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnCancel);
|
||||
}
|
||||
if (SwitchInteractAction)
|
||||
{
|
||||
EnhancedInputComponent->BindAction(SwitchInteractAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnSwitchInteract);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -90,8 +109,42 @@ void AChildHoodCharacter::Look(const FInputActionValue& Value)
|
||||
DoLook(LookAxisVector.X, LookAxisVector.Y);
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::OnInteract(const FInputActionValue& Value)
|
||||
{
|
||||
if (UInteractionManager* IM = GetInteractionManager())
|
||||
{
|
||||
// E 键双重功能:Free 发起交互,Active 结束交互
|
||||
IM->BeginInteract();
|
||||
IM->CancelInteract();
|
||||
}
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::OnCancel(const FInputActionValue& Value)
|
||||
{
|
||||
if (UInteractionManager* IM = GetInteractionManager())
|
||||
{
|
||||
IM->CancelInteract();
|
||||
}
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::OnSwitchInteract(const FInputActionValue& Value)
|
||||
{
|
||||
if (UInteractionManager* IM = GetInteractionManager())
|
||||
{
|
||||
float DirectionValue = Value.Get<float>();
|
||||
int32 Direction = (DirectionValue >= 0.f) ? 1 : -1;
|
||||
IM->SwitchTarget(Direction);
|
||||
}
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::DoMove(float Right, float Forward)
|
||||
{
|
||||
// 交互中屏蔽移动
|
||||
if (bIsInteracting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetController() != nullptr)
|
||||
{
|
||||
// find out which way is forward
|
||||
@@ -101,10 +154,10 @@ void AChildHoodCharacter::DoMove(float Right, float Forward)
|
||||
// get forward vector
|
||||
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||||
|
||||
// get right vector
|
||||
// get right vector
|
||||
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
||||
|
||||
// add movement
|
||||
// add movement
|
||||
AddMovementInput(ForwardDirection, Forward);
|
||||
AddMovementInput(RightDirection, Right);
|
||||
}
|
||||
@@ -120,14 +173,27 @@ void AChildHoodCharacter::DoLook(float Yaw, float Pitch)
|
||||
}
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::DoJumpStart()
|
||||
// ============================================================================
|
||||
// 交互系统方法
|
||||
// ============================================================================
|
||||
|
||||
UInteractionManager* AChildHoodCharacter::GetInteractionManager() const
|
||||
{
|
||||
// signal the character to jump
|
||||
Jump();
|
||||
return InteractionManager;
|
||||
}
|
||||
|
||||
void AChildHoodCharacter::DoJumpEnd()
|
||||
void AChildHoodCharacter::SetInteracting(bool bValue)
|
||||
{
|
||||
// signal the character to stop jumping
|
||||
StopJumping();
|
||||
bIsInteracting = bValue;
|
||||
}
|
||||
|
||||
bool AChildHoodCharacter::IsInteracting() const
|
||||
{
|
||||
return bIsInteracting;
|
||||
}
|
||||
|
||||
bool AChildHoodCharacter::IsRunning() const
|
||||
{
|
||||
return GetVelocity().SizeSquared() > 100.f // 速度 > 10 cm/s 阈值
|
||||
&& GetCharacterMovement()->IsMovingOnGround();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
class USpringArmComponent;
|
||||
class UCameraComponent;
|
||||
class UInputAction;
|
||||
class UInteractionManager;
|
||||
struct FInputActionValue;
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
|
||||
@@ -30,12 +31,8 @@ class AChildHoodCharacter : public ACharacter
|
||||
/** Follow camera */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||
UCameraComponent* FollowCamera;
|
||||
|
||||
protected:
|
||||
|
||||
/** Jump Input Action */
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
UInputAction* JumpAction;
|
||||
protected:
|
||||
|
||||
/** Move Input Action */
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
@@ -49,10 +46,45 @@ protected:
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
UInputAction* MouseLookAction;
|
||||
|
||||
/** Interact Input Action (E key) — delegates to interaction system */
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
UInputAction* InteractAction;
|
||||
|
||||
/** Cancel Input Action (ESC key) — delegates to interaction system */
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
UInputAction* CancelAction;
|
||||
|
||||
/** Switch Interact Target Input Action (Tab / Mouse Wheel) — delegates to interaction system */
|
||||
UPROPERTY(EditAnywhere, Category="Input")
|
||||
UInputAction* SwitchInteractAction;
|
||||
|
||||
/** 交互管理器组件 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interaction", meta = (AllowPrivateAccess = "true"))
|
||||
UInteractionManager* InteractionManager;
|
||||
|
||||
/** Whether the character is currently in an interaction */
|
||||
bool bIsInteracting = false;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
AChildHoodCharacter();
|
||||
AChildHoodCharacter();
|
||||
|
||||
/** 获取交互管理器组件 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Interaction")
|
||||
UInteractionManager* GetInteractionManager() const;
|
||||
|
||||
/** Set interaction state — called by interaction system */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void SetInteracting(bool bValue);
|
||||
|
||||
/** Query: is the character currently interacting? */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Interaction")
|
||||
bool IsInteracting() const;
|
||||
|
||||
/** Query: is the character currently running (moving on ground)? */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Interaction")
|
||||
bool IsRunning() const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -67,6 +99,15 @@ protected:
|
||||
/** Called for looking input */
|
||||
void Look(const FInputActionValue& Value);
|
||||
|
||||
/** Called for interact input (E) — delegates to InteractionManager */
|
||||
void OnInteract(const FInputActionValue& Value);
|
||||
|
||||
/** Called for cancel input (ESC) — delegates to InteractionManager */
|
||||
void OnCancel(const FInputActionValue& Value);
|
||||
|
||||
/** Called for switch interact target input (Tab/Wheel) — delegates to InteractionManager */
|
||||
void OnSwitchInteract(const FInputActionValue& Value);
|
||||
|
||||
public:
|
||||
|
||||
/** Handles move inputs from either controls or UI interfaces */
|
||||
@@ -77,14 +118,6 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category="Input")
|
||||
virtual void DoLook(float Yaw, float Pitch);
|
||||
|
||||
/** Handles jump pressed inputs from either controls or UI interfaces */
|
||||
UFUNCTION(BlueprintCallable, Category="Input")
|
||||
virtual void DoJumpStart();
|
||||
|
||||
/** Handles jump pressed inputs from either controls or UI interfaces */
|
||||
UFUNCTION(BlueprintCallable, Category="Input")
|
||||
virtual void DoJumpEnd();
|
||||
|
||||
public:
|
||||
|
||||
/** Returns CameraBoom subobject **/
|
||||
@@ -93,4 +126,3 @@ public:
|
||||
/** Returns FollowCamera subobject **/
|
||||
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// ChildHood Project - 跨关卡持久数据持有者 实现
|
||||
|
||||
#include "ChildHoodGameInstance.h"
|
||||
|
||||
bool UChildHoodGameInstance::IsItemCollected(FName ItemId) const
|
||||
{
|
||||
return CollectedItemIDs.Contains(ItemId);
|
||||
}
|
||||
|
||||
void UChildHoodGameInstance::MarkItemCollected(FName ItemId)
|
||||
{
|
||||
CollectedItemIDs.Add(ItemId);
|
||||
}
|
||||
|
||||
bool UChildHoodGameInstance::IsDoorOpen(FName DoorId) const
|
||||
{
|
||||
const bool* Found = DoorStates.Find(DoorId);
|
||||
return Found ? *Found : false;
|
||||
}
|
||||
|
||||
void UChildHoodGameInstance::SetDoorOpen(FName DoorId, bool bIsOpen)
|
||||
{
|
||||
DoorStates.Add(DoorId, bIsOpen);
|
||||
}
|
||||
|
||||
void UChildHoodGameInstance::ResetAll()
|
||||
{
|
||||
CollectedItemIDs.Empty();
|
||||
DoorStates.Empty();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// ChildHood Project - 跨关卡持久数据持有者
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第12节(跨场景持久化设计)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "ChildHoodGameInstance.generated.h"
|
||||
|
||||
/**
|
||||
* UChildHoodGameInstance
|
||||
*
|
||||
* 跨关卡持久数据持有者。UE5 的 OpenLevel() 会销毁整个旧 World(包括
|
||||
* Character 及其所有 UActorComponent),因此需要将持久数据与运行时行为分离。
|
||||
*
|
||||
* v0.1 为单场景原型,此 GameInstance 以空数据初始化。
|
||||
* 后续多场景版本只需在 Project Settings 中将 GameInstance Class 设为此类即可。
|
||||
*/
|
||||
UCLASS()
|
||||
class UChildHoodGameInstance : public UGameInstance
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
// === 物品消耗状态 ===
|
||||
|
||||
/** 查询指定物品是否已被收集(跨场景持久) */
|
||||
bool IsItemCollected(FName ItemId) const;
|
||||
|
||||
/** 标记指定物品为已收集(写入持久层) */
|
||||
void MarkItemCollected(FName ItemId);
|
||||
|
||||
// === 门状态 ===
|
||||
|
||||
/** 查询指定门的开关状态(跨场景持久),未记录的门默认为关闭 */
|
||||
bool IsDoorOpen(FName DoorId) const;
|
||||
|
||||
/** 设置指定门的开关状态(写入持久层) */
|
||||
void SetDoorOpen(FName DoorId, bool bIsOpen);
|
||||
|
||||
// === 重置 ===
|
||||
|
||||
/** 重置所有持久数据(新游戏时调用) */
|
||||
void ResetAll();
|
||||
|
||||
private:
|
||||
|
||||
/** 已收集物品ID集合 */
|
||||
UPROPERTY()
|
||||
TSet<FName> CollectedItemIDs;
|
||||
|
||||
/** 门开关状态映射(true=打开,false=关闭) */
|
||||
UPROPERTY()
|
||||
TMap<FName, bool> DoorStates;
|
||||
};
|
||||
@@ -13,6 +13,19 @@ void AChildHoodPlayerController::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// C3: 设置摄像机俯仰角限制(垂直旋转 +45°/-30°)
|
||||
if (PlayerCameraManager)
|
||||
{
|
||||
PlayerCameraManager->ViewPitchMin = -30.0f; // 向下看最多 30°
|
||||
PlayerCameraManager->ViewPitchMax = 45.0f; // 向上看最多 45°
|
||||
}
|
||||
|
||||
// C1: 初始俯角 -15°(摄像机默认略向下看向角色)
|
||||
if (GetControlRotation().Pitch == 0.f)
|
||||
{
|
||||
SetControlRotation(FRotator(-15.0f, GetControlRotation().Yaw, GetControlRotation().Roll));
|
||||
}
|
||||
|
||||
// only spawn touch controls on local player controllers
|
||||
if (ShouldUseTouchControls() && IsLocalPlayerController())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// ChildHood Project - 通用交互物 Actor 基类 实现
|
||||
|
||||
#include "Interaction/InteractableActor.h"
|
||||
#include "Interaction/InteractableComponent.h"
|
||||
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
|
||||
// ============================================================================
|
||||
// 构造函数
|
||||
// ============================================================================
|
||||
|
||||
AInteractableActor::AInteractableActor()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// 创建 Mesh 为根组件
|
||||
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
|
||||
RootComponent = MeshComp;
|
||||
MeshComp->SetCollisionProfileName(TEXT("BlockAll"));
|
||||
|
||||
// 创建交互组件(UActorComponent 不需要 SetupAttachment,数据驱动型组件)
|
||||
InteractableComp = CreateDefaultSubobject<UInteractableComponent>(TEXT("InteractableComp"));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 交互回调
|
||||
// ============================================================================
|
||||
|
||||
void AInteractableActor::OnInteractStarted_Implementation(UInteractableComponent* Comp)
|
||||
{
|
||||
if (!Comp || !MeshComp) return;
|
||||
|
||||
const FInteractableData& Data = Comp->GetInteractableData();
|
||||
|
||||
// 门类型:根据开关状态旋转 Mesh
|
||||
if (Data.Type == EInteractType::Operate && Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
FRotator CurrentRot = MeshComp->GetRelativeRotation();
|
||||
float TargetYaw = Comp->IsDoorOpen() ? 90.0f : 0.0f;
|
||||
MeshComp->SetRelativeRotation(FRotator(CurrentRot.Pitch, TargetYaw, CurrentRot.Roll));
|
||||
}
|
||||
}
|
||||
|
||||
void AInteractableActor::OnInteractEnded_Implementation(UInteractableComponent* Comp)
|
||||
{
|
||||
// 默认空实现,子类可覆盖
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// ChildHood Project - 通用交互物 Actor 基类
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)
|
||||
// 职责:持有 Mesh + InteractableComponent,提供可被子类覆盖的交互回调
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "InteractableActor.generated.h"
|
||||
|
||||
class UInteractableComponent;
|
||||
|
||||
/**
|
||||
* AInteractableActor
|
||||
*
|
||||
* 通用交互物 Actor 基类。场景中的每个交互物(冰箱、门、NPC 等)
|
||||
* 均为该类的实例或其子类的实例。
|
||||
*
|
||||
* 组成:
|
||||
* - UStaticMeshComponent* MeshComp(根组件,承载可视模型)
|
||||
* - UInteractableComponent* InteractableComp(交互逻辑与数据)
|
||||
*
|
||||
* 子类可覆盖 OnInteractStarted / OnInteractEnded 以实现类型特定行为,
|
||||
* 如门开关时的 Mesh 旋转、拾取物的消失效果等。
|
||||
*/
|
||||
UCLASS()
|
||||
class AInteractableActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
AInteractableActor();
|
||||
|
||||
// === 组件访问 ===
|
||||
|
||||
/** 获取静态网格组件 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interact")
|
||||
UStaticMeshComponent* GetMeshComp() const { return MeshComp; }
|
||||
|
||||
/** 获取交互组件 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interact")
|
||||
UInteractableComponent* GetInteractableComp() const { return InteractableComp; }
|
||||
|
||||
// === 可被子类覆盖的交互回调 ===
|
||||
|
||||
/**
|
||||
* 交互开始时调用(门开关切换、状态恢复时也调用)。
|
||||
* 默认实现:门类型根据开关状态对 Mesh 做 Yaw 旋转(开门+90度/关门0度)。
|
||||
*/
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Interact")
|
||||
void OnInteractStarted(UInteractableComponent* Comp);
|
||||
virtual void OnInteractStarted_Implementation(UInteractableComponent* Comp);
|
||||
|
||||
/** 交互结束时调用。默认为空实现,子类可覆盖。 */
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Interact")
|
||||
void OnInteractEnded(UInteractableComponent* Comp);
|
||||
virtual void OnInteractEnded_Implementation(UInteractableComponent* Comp);
|
||||
|
||||
protected:
|
||||
|
||||
/** 交互物的可视模型 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UStaticMeshComponent* MeshComp;
|
||||
|
||||
/** 交互物的交互组件(数据 + 检测 + 状态) */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UInteractableComponent* InteractableComp;
|
||||
};
|
||||
@@ -0,0 +1,221 @@
|
||||
// ChildHood Project - 可交互物组件 实现
|
||||
|
||||
#include "Interaction/InteractableComponent.h"
|
||||
#include "Interaction/InteractableActor.h"
|
||||
#include "Interaction/InteractionManager.h"
|
||||
#include "ChildHoodGameInstance.h"
|
||||
#include "ChildHood.h"
|
||||
|
||||
#include "Components/SphereComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
// ============================================================================
|
||||
// 构造函数
|
||||
// ============================================================================
|
||||
|
||||
UInteractableComponent::UInteractableComponent()
|
||||
{
|
||||
// 不需要 Tick,检测由碰撞事件驱动
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期
|
||||
// ============================================================================
|
||||
|
||||
void UInteractableComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
AActor* Owner = GetOwner();
|
||||
if (!Owner)
|
||||
{
|
||||
UE_LOG(LogChildHood, Warning, TEXT("InteractableComponent: 无 Owner,跳过初始化"));
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 创建检测球 ---
|
||||
DetectionSphere = NewObject<USphereComponent>(this, USphereComponent::StaticClass(), TEXT("DetectionSphere"));
|
||||
if (DetectionSphere)
|
||||
{
|
||||
DetectionSphere->SetupAttachment(Owner->GetRootComponent());
|
||||
DetectionSphere->RegisterComponent();
|
||||
DetectionSphere->SetSphereRadius(Data.TriggerRadius);
|
||||
DetectionSphere->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
|
||||
// 关闭物理模拟,仅用于 Overlap 检测
|
||||
DetectionSphere->SetGenerateOverlapEvents(true);
|
||||
DetectionSphere->SetCanEverAffectNavigation(false);
|
||||
|
||||
// 绑定碰撞事件
|
||||
DetectionSphere->OnComponentBeginOverlap.AddDynamic(this, &UInteractableComponent::OnDetectionOverlapBegin);
|
||||
DetectionSphere->OnComponentEndOverlap.AddDynamic(this, &UInteractableComponent::OnDetectionOverlapEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogChildHood, Error, TEXT("InteractableComponent: DetectionSphere 创建失败"));
|
||||
}
|
||||
|
||||
// --- 恢复跨场景持久状态 ---
|
||||
if (UChildHoodGameInstance* GI = GetWorld()->GetGameInstance<UChildHoodGameInstance>())
|
||||
{
|
||||
RestorePersistentState(GI);
|
||||
}
|
||||
|
||||
UE_LOG(LogChildHood, Log, TEXT("InteractableComponent Init: %s (Type=%s, Radius=%f)"),
|
||||
Data.DisplayName.IsEmpty() ? TEXT("(unnamed)") : *Data.DisplayName,
|
||||
*UEnum::GetValueAsString(Data.Type),
|
||||
Data.TriggerRadius);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 提示文本
|
||||
// ============================================================================
|
||||
|
||||
FString UInteractableComponent::GetPromptText() const
|
||||
{
|
||||
FString Verb = Data.InteractVerb;
|
||||
// 门类型:根据当前开关状态选择动词
|
||||
if (Data.Type == EInteractType::Operate && Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
Verb = bDoorIsOpen ? Data.InteractVerbAlt : Data.InteractVerb;
|
||||
}
|
||||
return FString::Printf(TEXT("[E] %s %s"), *Verb, *Data.DisplayName);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 消耗管理
|
||||
// ============================================================================
|
||||
|
||||
void UInteractableComponent::Consume()
|
||||
{
|
||||
bIsConsumed = true;
|
||||
|
||||
// 禁用检测球,不再触发 Overlap
|
||||
if (DetectionSphere)
|
||||
{
|
||||
DetectionSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
|
||||
// 写入持久层
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
if (UChildHoodGameInstance* GI = World->GetGameInstance<UChildHoodGameInstance>())
|
||||
{
|
||||
GI->MarkItemCollected(Data.ItemId);
|
||||
}
|
||||
}
|
||||
|
||||
UE_LOG(LogChildHood, Log, TEXT("InteractableComponent 已消耗: %s"), *Data.ItemId.ToString());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 门状态管理
|
||||
// ============================================================================
|
||||
|
||||
void UInteractableComponent::ToggleDoor()
|
||||
{
|
||||
bDoorIsOpen = !bDoorIsOpen;
|
||||
UE_LOG(LogChildHood, Log, TEXT("InteractableComponent 门状态切换: %s → %s"),
|
||||
*Data.ItemId.ToString(),
|
||||
bDoorIsOpen ? TEXT("开") : TEXT("关"));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 位置查询
|
||||
// ============================================================================
|
||||
|
||||
FVector UInteractableComponent::GetWorldLocation() const
|
||||
{
|
||||
AActor* Owner = GetOwner();
|
||||
return Owner ? Owner->GetActorLocation() : FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 跨场景持久状态恢复
|
||||
// ============================================================================
|
||||
|
||||
void UInteractableComponent::RestorePersistentState(UChildHoodGameInstance* GI)
|
||||
{
|
||||
if (!GI) return;
|
||||
|
||||
// oneShot 物品:已消耗 → 隐藏 + 禁用检测
|
||||
if (Data.bOneShot && GI->IsItemCollected(Data.ItemId))
|
||||
{
|
||||
bIsConsumed = true;
|
||||
if (DetectionSphere)
|
||||
{
|
||||
DetectionSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
if (AInteractableActor* Owner = Cast<AInteractableActor>(GetOwner()))
|
||||
{
|
||||
Owner->SetActorHiddenInGame(true);
|
||||
}
|
||||
UE_LOG(LogChildHood, Log, TEXT("RestorePersistentState: 已消耗物品隐藏: %s"), *Data.ItemId.ToString());
|
||||
}
|
||||
|
||||
// 门:恢复开关状态
|
||||
if (Data.Type == EInteractType::Operate && Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
bDoorIsOpen = GI->IsDoorOpen(Data.ItemId);
|
||||
// 通知 Actor 应用视觉状态(Mesh 旋转)
|
||||
if (AInteractableActor* Owner = Cast<AInteractableActor>(GetOwner()))
|
||||
{
|
||||
Owner->OnInteractStarted(this);
|
||||
}
|
||||
UE_LOG(LogChildHood, Log, TEXT("RestorePersistentState: 门状态恢复: %s → %s"),
|
||||
*Data.ItemId.ToString(),
|
||||
bDoorIsOpen ? TEXT("开") : TEXT("关"));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 碰撞回调
|
||||
// ============================================================================
|
||||
|
||||
void UInteractableComponent::OnDetectionOverlapBegin(UPrimitiveComponent* OverlappedComponent,
|
||||
AActor* OtherActor,
|
||||
UPrimitiveComponent* OtherComp,
|
||||
int32 OtherBodyIndex,
|
||||
bool bFromSweep,
|
||||
const FHitResult& SweepResult)
|
||||
{
|
||||
if (!OtherActor) return;
|
||||
|
||||
// 只响应 Character(玩家)的进入
|
||||
ACharacter* Character = Cast<ACharacter>(OtherActor);
|
||||
if (!Character) return;
|
||||
|
||||
// 已消耗的交互物不再注册
|
||||
if (bIsConsumed) return;
|
||||
|
||||
UE_LOG(LogChildHood, Verbose, TEXT("检测到角色进入范围: %s ← %s"),
|
||||
*Data.DisplayName, *OtherActor->GetName());
|
||||
|
||||
// 获取角色的 InteractionManager 并注册自己
|
||||
if (UInteractionManager* IM = Character->FindComponentByClass<UInteractionManager>())
|
||||
{
|
||||
IM->RegisterInteractable(this);
|
||||
}
|
||||
}
|
||||
|
||||
void UInteractableComponent::OnDetectionOverlapEnd(UPrimitiveComponent* OverlappedComponent,
|
||||
AActor* OtherActor,
|
||||
UPrimitiveComponent* OtherComp,
|
||||
int32 OtherBodyIndex)
|
||||
{
|
||||
if (!OtherActor) return;
|
||||
|
||||
ACharacter* Character = Cast<ACharacter>(OtherActor);
|
||||
if (!Character) return;
|
||||
|
||||
UE_LOG(LogChildHood, Verbose, TEXT("角色离开范围: %s ← %s"),
|
||||
*Data.DisplayName, *OtherActor->GetName());
|
||||
|
||||
// 获取角色的 InteractionManager 并注销自己
|
||||
if (UInteractionManager* IM = Character->FindComponentByClass<UInteractionManager>())
|
||||
{
|
||||
IM->UnregisterInteractable(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// ChildHood Project - 可交互物组件
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)+ 第12节(跨场景持久化)
|
||||
// 职责:单个交互物配置数据、触发区域、运行时状态、跨场景持久状态恢复
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "InteractionTypes.h"
|
||||
#include "InteractableComponent.generated.h"
|
||||
|
||||
class UChildHoodGameInstance;
|
||||
class USphereComponent;
|
||||
|
||||
/**
|
||||
* UInteractableComponent
|
||||
*
|
||||
* 挂载在 AInteractableActor(或其子类)上的组件。
|
||||
* 持有该交互物的全部配置数据(FInteractableData)、运行时触发检测球、
|
||||
* 消耗/门状态管理,以及跨场景持久状态恢复。
|
||||
*/
|
||||
UCLASS(ClassGroup=(Interaction), meta=(BlueprintSpawnableComponent))
|
||||
class UInteractableComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UInteractableComponent();
|
||||
|
||||
// === 配置数据 ===
|
||||
|
||||
/** 该交互物的全部配置数据,编辑器中按实例独立配置 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact")
|
||||
FInteractableData Data;
|
||||
|
||||
// === 查询接口 ===
|
||||
|
||||
/** 获取配置数据引用(只读) */
|
||||
const FInteractableData& GetInteractableData() const { return Data; }
|
||||
|
||||
/**
|
||||
* 获取提示文本,格式:"[E] 动作词 名称"
|
||||
* 门类型根据当前开关状态选择动词
|
||||
*/
|
||||
FString GetPromptText() const;
|
||||
|
||||
/** 该交互物是否已被消耗(oneShot 模式) */
|
||||
bool IsConsumed() const { return bIsConsumed; }
|
||||
|
||||
/** 标记为已消耗,禁用检测球,写入持久层 */
|
||||
void Consume();
|
||||
|
||||
// === 门状态管理 ===
|
||||
|
||||
/** 切换门开关状态 */
|
||||
void ToggleDoor();
|
||||
|
||||
/** 门是否处于打开状态 */
|
||||
bool IsDoorOpen() const { return bDoorIsOpen; }
|
||||
|
||||
/** 获取交互物在世界空间的位置 */
|
||||
FVector GetWorldLocation() const;
|
||||
|
||||
/** 从 GameInstance 恢复跨场景持久状态(BeginPlay 中调用) */
|
||||
void RestorePersistentState(UChildHoodGameInstance* GI);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
private:
|
||||
|
||||
/** 运行时创建的检测球,用于触发玩家进入/离开交互范围 */
|
||||
UPROPERTY()
|
||||
USphereComponent* DetectionSphere;
|
||||
|
||||
/** oneShot 物品是否已被消耗 */
|
||||
bool bIsConsumed = false;
|
||||
|
||||
/** 门是否处于打开状态(仅 Operate+Door 类型使用) */
|
||||
bool bDoorIsOpen = false;
|
||||
|
||||
// === 碰撞回调 ===
|
||||
|
||||
/** 玩家进入检测范围 */
|
||||
UFUNCTION()
|
||||
void OnDetectionOverlapBegin(UPrimitiveComponent* OverlappedComponent,
|
||||
AActor* OtherActor,
|
||||
UPrimitiveComponent* OtherComp,
|
||||
int32 OtherBodyIndex,
|
||||
bool bFromSweep,
|
||||
const FHitResult& SweepResult);
|
||||
|
||||
/** 玩家离开检测范围 */
|
||||
UFUNCTION()
|
||||
void OnDetectionOverlapEnd(UPrimitiveComponent* OverlappedComponent,
|
||||
AActor* OtherActor,
|
||||
UPrimitiveComponent* OtherComp,
|
||||
int32 OtherBodyIndex);
|
||||
};
|
||||
@@ -0,0 +1,897 @@
|
||||
// ChildHood Project - 交互管理器核心组件 实现
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第6节(行为规则实现)
|
||||
|
||||
#include "Interaction/InteractionManager.h"
|
||||
#include "Interaction/InteractableComponent.h"
|
||||
#include "Interaction/InteractableActor.h"
|
||||
#include "Interaction/PushCameraActor.h"
|
||||
#include "Interaction/InteractionPromptWidget.h"
|
||||
#include "Interaction/NarrativeTextWidget.h"
|
||||
#include "ChildHoodCharacter.h"
|
||||
#include "ChildHoodGameInstance.h"
|
||||
#include "ChildHood.h"
|
||||
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/SphereComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "TimerManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Blueprint/WidgetBlueprintLibrary.h"
|
||||
|
||||
// 定义交互系统日志类别
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogInteraction, Log, All);
|
||||
DEFINE_LOG_CATEGORY(LogInteraction);
|
||||
|
||||
// ============================================================================
|
||||
// 构造函数
|
||||
// ============================================================================
|
||||
|
||||
UInteractionManager::UInteractionManager()
|
||||
{
|
||||
// 默认关闭 Tick,首个交互物注册时开启
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Spawn 推镜用临时摄像机 Actor(使用专用的 APushCameraActor)
|
||||
// 随 Character 生命周期,不反复创建/销毁
|
||||
FActorSpawnParameters SpawnParams;
|
||||
SpawnParams.Owner = GetOwner();
|
||||
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||
|
||||
APushCameraActor* SpawnedCamera = GetWorld()->SpawnActor<APushCameraActor>(APushCameraActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
|
||||
PushCameraActor = SpawnedCamera;
|
||||
if (PushCameraActor)
|
||||
{
|
||||
PushCameraActor->SetActorHiddenInGame(true);
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("InteractionManager: BeginPlay 完成, PushCameraActor=%s"),
|
||||
PushCameraActor ? *PushCameraActor->GetName() : TEXT("nullptr"));
|
||||
|
||||
// --- 创建 UI Widget ---
|
||||
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
||||
if (PC)
|
||||
{
|
||||
// 创建提示 UI
|
||||
if (PromptWidgetClass)
|
||||
{
|
||||
PromptWidget = CreateWidget<UInteractionPromptWidget>(PC, PromptWidgetClass);
|
||||
if (PromptWidget)
|
||||
{
|
||||
PromptWidget->AddToViewport(10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInteraction, Warning, TEXT("InteractionManager: PromptWidgetClass 未设置,提示 UI 不可用"));
|
||||
}
|
||||
|
||||
// 创建文本底框 UI
|
||||
if (NarrativeWidgetClass)
|
||||
{
|
||||
NarrativeWidget = CreateWidget<UNarrativeTextWidget>(PC, NarrativeWidgetClass);
|
||||
if (NarrativeWidget)
|
||||
{
|
||||
NarrativeWidget->AddToViewport(20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInteraction, Warning, TEXT("InteractionManager: NarrativeWidgetClass 未设置,文本 UI 不可用"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tick 驱动
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
if (State == EInteractionState::Free)
|
||||
{
|
||||
// Free 状态下更新提示 UI 的屏幕位置
|
||||
if (PromptWidget && PromptWidget->IsVisible() &&
|
||||
NearbyInteractables.Num() > 0 && NearbyInteractables.IsValidIndex(SelectedIndex))
|
||||
{
|
||||
UInteractableComponent* Selected = NearbyInteractables[SelectedIndex];
|
||||
if (Selected)
|
||||
{
|
||||
UpdatePromptScreenPosition(Selected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Phase)
|
||||
{
|
||||
case EInteractPhase::Enter:
|
||||
TickEnterPhase(DeltaTime);
|
||||
break;
|
||||
|
||||
case EInteractPhase::AnimLock:
|
||||
TickAnimLockPhase(DeltaTime);
|
||||
break;
|
||||
|
||||
case EInteractPhase::Active:
|
||||
// 等待玩家输入,无需 Tick 处理
|
||||
break;
|
||||
|
||||
case EInteractPhase::Exit:
|
||||
TickExitPhase(DeltaTime);
|
||||
break;
|
||||
|
||||
case EInteractPhase::None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 公开方法
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::BeginInteract()
|
||||
{
|
||||
// 前置检查:必须 Free 状态
|
||||
if (State != EInteractionState::Free)
|
||||
{
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("BeginInteract: 拒绝,当前状态不是 Free (State=%d)"),
|
||||
static_cast<int32>(State));
|
||||
return;
|
||||
}
|
||||
|
||||
// 前置检查:必须有选中的交互物
|
||||
if (NearbyInteractables.Num() == 0 || !NearbyInteractables.IsValidIndex(SelectedIndex))
|
||||
{
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("BeginInteract: 拒绝,没有选中的交互物"));
|
||||
return;
|
||||
}
|
||||
|
||||
UInteractableComponent* Target = NearbyInteractables[SelectedIndex];
|
||||
|
||||
// 前置检查:交互物不能已被消耗
|
||||
if (!Target || Target->IsConsumed())
|
||||
{
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("BeginInteract: 拒绝,交互物已被消耗"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 进入交互
|
||||
State = EInteractionState::Interacting;
|
||||
Phase = EInteractPhase::Enter;
|
||||
CurrentInteractable = Target;
|
||||
|
||||
// 通知 Character 进入交互状态(屏蔽移动)
|
||||
AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(GetOwner());
|
||||
if (Char)
|
||||
{
|
||||
Char->SetInteracting(true);
|
||||
}
|
||||
|
||||
// 隐藏提示 UI
|
||||
HidePrompt();
|
||||
|
||||
// 重置 Enter 阶段计时器
|
||||
TurnElapsed = 0.0f;
|
||||
WaitElapsed = 0.0f;
|
||||
bPushStarted = false;
|
||||
|
||||
const FInteractableData& Data = Target->GetInteractableData();
|
||||
UE_LOG(LogInteraction, Log, TEXT("BeginInteract: 开始交互 '%s' (Type=%d)"),
|
||||
*Data.DisplayName, static_cast<int32>(Data.Type));
|
||||
}
|
||||
|
||||
void UInteractionManager::CancelInteract()
|
||||
{
|
||||
// 前置检查:必须 Interacting 状态
|
||||
if (State != EInteractionState::Interacting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// AnimLock 期间不可取消
|
||||
if (Phase == EInteractPhase::AnimLock)
|
||||
{
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("CancelInteract: 拒绝,AnimLock 阶段不可取消"));
|
||||
return;
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("CancelInteract: 取消/结束交互"));
|
||||
|
||||
// 隐藏叙事文本
|
||||
HideNarrativeText();
|
||||
|
||||
// 进入 Exit 阶段
|
||||
Phase = EInteractPhase::Exit;
|
||||
|
||||
// 相机回位
|
||||
const FInteractableData* Data = CurrentInteractable ? &CurrentInteractable->GetInteractableData() : nullptr;
|
||||
float ReturnDuration = (Data && Data->bUseCameraPush) ? Data->CameraReturnDuration : 0.3f;
|
||||
ReturnCamera(ReturnDuration);
|
||||
|
||||
// 清除可能残留的计时器
|
||||
GetWorld()->GetTimerManager().ClearTimer(AnimEventTimerHandle);
|
||||
GetWorld()->GetTimerManager().ClearTimer(AnimEndTimerHandle);
|
||||
|
||||
// 设置退出定时器,回位动画播完后回到 Free
|
||||
GetWorld()->GetTimerManager().SetTimer(ExitTimerHandle, this, &UInteractionManager::OnExitTimerComplete, ReturnDuration, false);
|
||||
}
|
||||
|
||||
void UInteractionManager::SwitchTarget(int32 Direction)
|
||||
{
|
||||
int32 Num = NearbyInteractables.Num();
|
||||
if (Num == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Interacting 状态下忽略切换
|
||||
if (State != EInteractionState::Free)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedIndex = (SelectedIndex + Direction + Num) % Num;
|
||||
UpdatePromptUI();
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("SwitchTarget: 切换到 %d/%d"), SelectedIndex, Num);
|
||||
}
|
||||
|
||||
void UInteractionManager::RegisterInteractable(UInteractableComponent* Interactable)
|
||||
{
|
||||
if (!Interactable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 去重检查
|
||||
if (NearbyInteractables.Contains(Interactable))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NearbyInteractables.Add(Interactable);
|
||||
|
||||
// 按水平距离排序(DistSquared2D,避免 sqrt)
|
||||
AActor* Owner = GetOwner();
|
||||
if (Owner)
|
||||
{
|
||||
FVector OwnerLoc = Owner->GetActorLocation();
|
||||
NearbyInteractables.Sort([OwnerLoc](const UInteractableComponent& A, const UInteractableComponent& B)
|
||||
{
|
||||
float DistA = FVector::DistSquared2D(OwnerLoc, A.GetWorldLocation());
|
||||
float DistB = FVector::DistSquared2D(OwnerLoc, B.GetWorldLocation());
|
||||
return DistA < DistB;
|
||||
});
|
||||
}
|
||||
|
||||
UpdateSelection();
|
||||
UpdatePromptUI();
|
||||
|
||||
// 首个交互物注册时开启 Tick
|
||||
if (NearbyInteractables.Num() == 1)
|
||||
{
|
||||
SetComponentTickEnabled(true);
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("RegisterInteractable: 注册 '%s', 列表大小=%d"),
|
||||
*Interactable->GetInteractableData().DisplayName, NearbyInteractables.Num());
|
||||
}
|
||||
|
||||
void UInteractionManager::UnregisterInteractable(UInteractableComponent* Interactable)
|
||||
{
|
||||
if (!Interactable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool bRemoved = NearbyInteractables.Remove(Interactable) > 0;
|
||||
if (!bRemoved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果移除的是当前正在交互的交互物,清空引用
|
||||
if (CurrentInteractable == Interactable)
|
||||
{
|
||||
CurrentInteractable = nullptr;
|
||||
}
|
||||
|
||||
if (NearbyInteractables.Num() > 0)
|
||||
{
|
||||
UpdateSelection();
|
||||
UpdatePromptUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 列表为空,隐藏提示
|
||||
HidePrompt();
|
||||
// 最后一个注销时关闭 Tick
|
||||
SetComponentTickEnabled(false);
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("UnregisterInteractable: 注销 '%s', 列表大小=%d"),
|
||||
*Interactable->GetInteractableData().DisplayName, NearbyInteractables.Num());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Enter 阶段 Tick
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::TickEnterPhase(float DeltaTime)
|
||||
{
|
||||
if (!CurrentInteractable)
|
||||
{
|
||||
UE_LOG(LogInteraction, Warning, TEXT("TickEnterPhase: CurrentInteractable 为空,强制取消"));
|
||||
CancelInteract();
|
||||
return;
|
||||
}
|
||||
|
||||
ACharacter* Char = Cast<ACharacter>(GetOwner());
|
||||
if (!Char)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FInteractableData& Data = CurrentInteractable->GetInteractableData();
|
||||
|
||||
// --- 1. 转向插值 ---
|
||||
TurnElapsed += DeltaTime;
|
||||
|
||||
FVector CharLoc = Char->GetActorLocation();
|
||||
FVector TargetLoc = CurrentInteractable->GetWorldLocation();
|
||||
FVector DirToTarget = (TargetLoc - CharLoc);
|
||||
DirToTarget.Z = 0.0f;
|
||||
FRotator TargetRot = DirToTarget.Rotation();
|
||||
|
||||
// 使用 RInterpTo 进行平滑插值,InterpSpeed = 1/TurnDuration
|
||||
float InterpSpeed = (TurnDuration > 0.f) ? (1.f / TurnDuration) : 10.f;
|
||||
FRotator NewRot = FMath::RInterpTo(Char->GetActorRotation(), TargetRot, DeltaTime, InterpSpeed);
|
||||
Char->SetActorRotation(NewRot);
|
||||
|
||||
// --- 2. 推镜(一次性发起) ---
|
||||
if (Data.bUseCameraPush && !bPushStarted)
|
||||
{
|
||||
FVector PushPos = CalculatePushPosition(CurrentInteractable);
|
||||
PushCamera(PushPos, Data.CameraPushDuration);
|
||||
bPushStarted = true;
|
||||
}
|
||||
|
||||
// --- 3. 判断完成 ---
|
||||
bool bTurnComplete = TurnElapsed >= TurnDuration;
|
||||
bool bPushComplete = !Data.bUseCameraPush || bPushStarted;
|
||||
|
||||
if (bTurnComplete && bPushComplete)
|
||||
{
|
||||
// 推镜后需要额外等待 PushWaitDelay
|
||||
if (Data.bUseCameraPush && Data.PushWaitDelay > 0.f)
|
||||
{
|
||||
WaitElapsed += DeltaTime;
|
||||
if (WaitElapsed >= Data.PushWaitDelay)
|
||||
{
|
||||
TransitionFromEnter();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionFromEnter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// AnimLock 阶段 Tick(v0.1 由计时器驱动,此处为空)
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::TickAnimLockPhase(float DeltaTime)
|
||||
{
|
||||
// v0.1: AnimLock 由 AnimEventTimer 和 AnimEndTimer 驱动,无需 Tick 处理
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Exit 阶段 Tick(v0.1 由定时器驱动回 Free)
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::TickExitPhase(float DeltaTime)
|
||||
{
|
||||
// v0.1: Exit 阶段由 ExitTimerHandle 定时器驱动回到 Free
|
||||
// 此处可做相机回位进度检查等,简单方案留空
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Enter 完成后类型分发
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::TransitionFromEnter()
|
||||
{
|
||||
if (!CurrentInteractable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FInteractableData& Data = CurrentInteractable->GetInteractableData();
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("TransitionFromEnter: 类型=%d 分发"), static_cast<int32>(Data.Type));
|
||||
|
||||
switch (Data.Type)
|
||||
{
|
||||
case EInteractType::Examine:
|
||||
Phase = EInteractPhase::Active;
|
||||
ShowNarrativeText(PickRandomNarrative(Data.NarrativeTexts));
|
||||
break;
|
||||
|
||||
case EInteractType::Pickup:
|
||||
Phase = EInteractPhase::AnimLock;
|
||||
EnterAnimLockPhase();
|
||||
break;
|
||||
|
||||
case EInteractType::Operate:
|
||||
if (Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
Phase = EInteractPhase::AnimLock;
|
||||
EnterAnimLockPhase();
|
||||
}
|
||||
else if (Data.OperateSubType == EOperateSubType::Search)
|
||||
{
|
||||
Phase = EInteractPhase::AnimLock;
|
||||
EnterAnimLockPhase();
|
||||
}
|
||||
break;
|
||||
|
||||
case EInteractType::Talk:
|
||||
Phase = EInteractPhase::Active;
|
||||
ShowNarrativeText(PickRandomNarrative(Data.NarrativeTexts));
|
||||
break;
|
||||
|
||||
default:
|
||||
UE_LOG(LogInteraction, Warning, TEXT("TransitionFromEnter: 未知交互类型 %d"), static_cast<int32>(Data.Type));
|
||||
// 未知类型直接回 Free
|
||||
CancelInteract();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// AnimLock 阶段
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::EnterAnimLockPhase()
|
||||
{
|
||||
if (!CurrentInteractable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FInteractableData& Data = CurrentInteractable->GetInteractableData();
|
||||
|
||||
// 计算总动画时长:有蒙太奇用蒙太奇长度,否则用配置的 AnimDuration
|
||||
float TotalAnimTime = Data.AnimDuration;
|
||||
if (Data.InteractMontage)
|
||||
{
|
||||
TotalAnimTime = Data.InteractMontage->GetPlayLength();
|
||||
if (TotalAnimTime <= 0.f)
|
||||
{
|
||||
TotalAnimTime = Data.AnimDuration;
|
||||
}
|
||||
|
||||
// 播放蒙太奇
|
||||
ACharacter* Char = Cast<ACharacter>(GetOwner());
|
||||
if (Char && Char->GetMesh())
|
||||
{
|
||||
Char->GetMesh()->GetAnimInstance()->Montage_Play(Data.InteractMontage);
|
||||
UE_LOG(LogInteraction, Log, TEXT("EnterAnimLockPhase: 播放蒙太奇, 时长=%.2f"), TotalAnimTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInteraction, Log, TEXT("EnterAnimLockPhase: 无蒙太奇,使用计时器, 时长=%.2f"), TotalAnimTime);
|
||||
}
|
||||
|
||||
// 动画事件触发计时器(如 60% 时物品消失)
|
||||
float EventTime = TotalAnimTime * Data.AnimEventTimepoint;
|
||||
GetWorld()->GetTimerManager().SetTimer(AnimEventTimerHandle, this, &UInteractionManager::ExecuteAnimEvent, EventTime, false);
|
||||
|
||||
// 动画结束计时器
|
||||
GetWorld()->GetTimerManager().SetTimer(AnimEndTimerHandle, this, &UInteractionManager::OnAnimLockComplete, TotalAnimTime, false);
|
||||
|
||||
bAnimEventFired = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 动画事件触发回调
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::ExecuteAnimEvent()
|
||||
{
|
||||
if (!CurrentInteractable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bAnimEventFired = true;
|
||||
const FInteractableData& Data = CurrentInteractable->GetInteractableData();
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("ExecuteAnimEvent: 类型=%d, 名称='%s'"),
|
||||
static_cast<int32>(Data.Type), *Data.DisplayName);
|
||||
|
||||
switch (Data.Type)
|
||||
{
|
||||
case EInteractType::Pickup:
|
||||
{
|
||||
// 标记消耗 → 隐藏 Actor → 通知物品系统
|
||||
CurrentInteractable->Consume();
|
||||
|
||||
// 隐藏交互物 Actor
|
||||
if (AInteractableActor* OwnerActor = Cast<AInteractableActor>(CurrentInteractable->GetOwner()))
|
||||
{
|
||||
OwnerActor->SetActorHiddenInGame(true);
|
||||
}
|
||||
|
||||
// 广播拾取事件
|
||||
OnItemPickedUp.Broadcast(Data.ItemId, Data.DisplayName, FName(TEXT("杂物")));
|
||||
UE_LOG(LogInteraction, Log, TEXT("ExecuteAnimEvent: Pickup 拾取完成 '%s'"), *Data.DisplayName);
|
||||
}
|
||||
break;
|
||||
|
||||
case EInteractType::Operate:
|
||||
{
|
||||
if (Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
// 切换门状态
|
||||
CurrentInteractable->ToggleDoor();
|
||||
|
||||
// 持久化门状态到 GameInstance
|
||||
if (UChildHoodGameInstance* GI = GetWorld()->GetGameInstance<UChildHoodGameInstance>())
|
||||
{
|
||||
GI->SetDoorOpen(Data.ItemId, CurrentInteractable->IsDoorOpen());
|
||||
}
|
||||
|
||||
// 通知 Actor 处理 Mesh 旋转等视觉反馈
|
||||
if (AInteractableActor* OwnerActor = Cast<AInteractableActor>(CurrentInteractable->GetOwner()))
|
||||
{
|
||||
OwnerActor->OnInteractStarted(CurrentInteractable);
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("ExecuteAnimEvent: Door 门状态切换, 开=%s"),
|
||||
CurrentInteractable->IsDoorOpen() ? TEXT("true") : TEXT("false"));
|
||||
}
|
||||
// Search 类型的结果判定在 OnAnimLockComplete 中处理
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 动画结束回调
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::OnAnimLockComplete()
|
||||
{
|
||||
if (!CurrentInteractable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FInteractableData& Data = CurrentInteractable->GetInteractableData();
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("OnAnimLockComplete: 类型=%d, 名称='%s'"),
|
||||
static_cast<int32>(Data.Type), *Data.DisplayName);
|
||||
|
||||
switch (Data.Type)
|
||||
{
|
||||
case EInteractType::Pickup:
|
||||
{
|
||||
// 直接回到 Free(无 Active/Exit,无相机/UI 需清理)
|
||||
AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(GetOwner());
|
||||
if (Char)
|
||||
{
|
||||
Char->SetInteracting(false);
|
||||
}
|
||||
State = EInteractionState::Free;
|
||||
Phase = EInteractPhase::None;
|
||||
CurrentInteractable = nullptr;
|
||||
|
||||
// 从检测列表移除已消耗的交互物
|
||||
// Consume 已在 ExecuteAnimEvent 中调用,但 UnregisterInteractable 应由 DetectionSphere 禁用触发
|
||||
// 这里主动从列表移除,确保提示 UI 正确更新
|
||||
if (NearbyInteractables.Num() > 0)
|
||||
{
|
||||
UpdateSelection();
|
||||
UpdatePromptUI();
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("OnAnimLockComplete: Pickup 完成,回到 Free"));
|
||||
}
|
||||
break;
|
||||
|
||||
case EInteractType::Operate:
|
||||
{
|
||||
if (Data.OperateSubType == EOperateSubType::Door)
|
||||
{
|
||||
// 直接回到 Free
|
||||
AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(GetOwner());
|
||||
if (Char)
|
||||
{
|
||||
Char->SetInteracting(false);
|
||||
}
|
||||
State = EInteractionState::Free;
|
||||
Phase = EInteractPhase::None;
|
||||
CurrentInteractable = nullptr;
|
||||
|
||||
// 更新提示(门动词可能变化)
|
||||
UpdateSelection();
|
||||
UpdatePromptUI();
|
||||
|
||||
UE_LOG(LogInteraction, Log, TEXT("OnAnimLockComplete: Door 完成,回到 Free"));
|
||||
}
|
||||
else if (Data.OperateSubType == EOperateSubType::Search)
|
||||
{
|
||||
// 翻找结果判定:v0.1 必定有物品
|
||||
CurrentInteractable->Consume();
|
||||
OnItemFound.Broadcast(Data.ItemId, Data.DisplayName, FName(TEXT("杂物")));
|
||||
UE_LOG(LogInteraction, Log, TEXT("OnAnimLockComplete: Search 翻找完成,获得物品 '%s'"), *Data.DisplayName);
|
||||
|
||||
// 进入 Active 阶段等待玩家按 E/ESC 关闭
|
||||
Phase = EInteractPhase::Active;
|
||||
// 有物品时不显示文本底框(架构预留)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UI 方法(v0.1 用日志替代)
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::UpdateSelection()
|
||||
{
|
||||
// 排序后选中索引重置为 0(最近的)
|
||||
if (AActor* Owner = GetOwner())
|
||||
{
|
||||
FVector OwnerLoc = Owner->GetActorLocation();
|
||||
NearbyInteractables.Sort([OwnerLoc](const UInteractableComponent& A, const UInteractableComponent& B)
|
||||
{
|
||||
float DistA = FVector::DistSquared2D(OwnerLoc, A.GetWorldLocation());
|
||||
float DistB = FVector::DistSquared2D(OwnerLoc, B.GetWorldLocation());
|
||||
return DistA < DistB;
|
||||
});
|
||||
}
|
||||
SelectedIndex = 0;
|
||||
}
|
||||
|
||||
void UInteractionManager::UpdatePromptUI()
|
||||
{
|
||||
if (NearbyInteractables.Num() == 0 || !NearbyInteractables.IsValidIndex(SelectedIndex))
|
||||
{
|
||||
HidePrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
UInteractableComponent* Selected = NearbyInteractables[SelectedIndex];
|
||||
if (!Selected)
|
||||
{
|
||||
HidePrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
FString PromptText = Selected->GetPromptText();
|
||||
|
||||
if (PromptWidget)
|
||||
{
|
||||
PromptWidget->SetPromptText(PromptText);
|
||||
PromptWidget->Show();
|
||||
UpdatePromptScreenPosition(Selected);
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("UpdatePromptUI: %s"), *PromptText);
|
||||
}
|
||||
|
||||
void UInteractionManager::HidePrompt()
|
||||
{
|
||||
if (PromptWidget)
|
||||
{
|
||||
PromptWidget->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void UInteractionManager::ShowNarrativeText(const FString& Text)
|
||||
{
|
||||
if (Text.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogInteraction, Warning, TEXT("ShowNarrativeText: text is empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (NarrativeWidget)
|
||||
{
|
||||
NarrativeWidget->SetNarrativeText(Text);
|
||||
NarrativeWidget->Show();
|
||||
}
|
||||
|
||||
UE_LOG(LogInteraction, Verbose, TEXT("ShowNarrativeText: %s"), *Text);
|
||||
}
|
||||
|
||||
void UInteractionManager::HideNarrativeText()
|
||||
{
|
||||
if (NarrativeWidget)
|
||||
{
|
||||
NarrativeWidget->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 摄像机控制
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::PushCamera(FVector Target, float Duration)
|
||||
{
|
||||
if (!PushCameraActor)
|
||||
{
|
||||
UE_LOG(LogInteraction, Warning, TEXT("PushCamera: PushCameraActor 为空"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算朝向交互物的旋转
|
||||
FVector LookTarget = CurrentInteractable ? CurrentInteractable->GetWorldLocation() : Target;
|
||||
FRotator LookAtRot = (LookTarget - Target).Rotation();
|
||||
|
||||
PushCameraActor->SetActorHiddenInGame(false);
|
||||
PushCameraActor->SetActorLocationAndRotation(Target, LookAtRot);
|
||||
|
||||
// 切换 ViewTarget
|
||||
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
||||
if (PC)
|
||||
{
|
||||
PC->SetViewTargetWithBlend(PushCameraActor, Duration, VTBlend_EaseOut);
|
||||
UE_LOG(LogInteraction, Log, TEXT("PushCamera: 推镜到 %s, 时长=%.2f"), *Target.ToString(), Duration);
|
||||
}
|
||||
}
|
||||
|
||||
void UInteractionManager::ReturnCamera(float Duration)
|
||||
{
|
||||
AActor* Owner = GetOwner();
|
||||
if (!Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
||||
if (PC)
|
||||
{
|
||||
// 回位到 Character
|
||||
PC->SetViewTargetWithBlend(Owner, Duration, VTBlend_EaseIn);
|
||||
UE_LOG(LogInteraction, Log, TEXT("ReturnCamera: 相机回位, 时长=%.2f"), Duration);
|
||||
}
|
||||
|
||||
// 隐藏推镜 Actor
|
||||
if (PushCameraActor)
|
||||
{
|
||||
PushCameraActor->SetActorHiddenInGame(true);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 推镜位置计算
|
||||
// ============================================================================
|
||||
|
||||
FVector UInteractionManager::CalculatePushPosition(UInteractableComponent* Interactable)
|
||||
{
|
||||
if (!Interactable)
|
||||
{
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
const FInteractableData& Data = Interactable->GetInteractableData();
|
||||
FVector InteractPos = Interactable->GetWorldLocation();
|
||||
FVector CharPos = GetOwner() ? GetOwner()->GetActorLocation() : FVector::ZeroVector;
|
||||
|
||||
FVector Dir = (InteractPos - CharPos);
|
||||
Dir.Z = 0.0f;
|
||||
Dir.Normalize();
|
||||
|
||||
// 交互物前方(面向角色的一侧),推镜距离偏移
|
||||
FVector TargetPos = InteractPos - Dir * Data.CameraPushDistance;
|
||||
// 高度略低于交互物中心(微仰视)
|
||||
TargetPos.Z = InteractPos.Z * 0.8f;
|
||||
|
||||
return TargetPos;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 叙事文本随机选取
|
||||
// ============================================================================
|
||||
|
||||
FString UInteractionManager::PickRandomNarrative(const TArray<FString>& Texts)
|
||||
{
|
||||
if (Texts.Num() == 0)
|
||||
{
|
||||
return TEXT("");
|
||||
}
|
||||
|
||||
if (Texts.Num() == 1)
|
||||
{
|
||||
LastNarrativeText = Texts[0];
|
||||
return Texts[0];
|
||||
}
|
||||
|
||||
FString Candidate;
|
||||
int32 Attempts = 0;
|
||||
do
|
||||
{
|
||||
Candidate = Texts[FMath::RandRange(0, Texts.Num() - 1)];
|
||||
Attempts++;
|
||||
} while (Candidate == LastNarrativeText && Attempts < 10);
|
||||
|
||||
LastNarrativeText = Candidate;
|
||||
return Candidate;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Exit 阶段定时器回调
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::OnExitTimerComplete()
|
||||
{
|
||||
UE_LOG(LogInteraction, Log, TEXT("OnExitTimerComplete: Exit 阶段结束,回到 Free"));
|
||||
|
||||
// 通知 Character 解除交互状态
|
||||
AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(GetOwner());
|
||||
if (Char)
|
||||
{
|
||||
Char->SetInteracting(false);
|
||||
}
|
||||
|
||||
// 回到 Free 状态
|
||||
State = EInteractionState::Free;
|
||||
Phase = EInteractPhase::None;
|
||||
CurrentInteractable = nullptr;
|
||||
|
||||
// 如果仍在检测范围内,重新显示提示
|
||||
if (NearbyInteractables.Num() > 0)
|
||||
{
|
||||
UpdateSelection();
|
||||
UpdatePromptUI();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 提示 UI 屏幕位置更新
|
||||
// ============================================================================
|
||||
|
||||
void UInteractionManager::UpdatePromptScreenPosition(UInteractableComponent* Interactable)
|
||||
{
|
||||
if (!Interactable || !PromptWidget) return;
|
||||
|
||||
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
||||
if (!PC) return;
|
||||
|
||||
// 交互物世界位置 + 高度偏移 → 屏幕坐标
|
||||
FVector WorldLoc = Interactable->GetWorldLocation() + FVector(0.f, 0.f, PromptHeightOffset);
|
||||
FVector2D ScreenPos;
|
||||
if (UGameplayStatics::ProjectWorldToScreen(PC, WorldLoc, ScreenPos, true))
|
||||
{
|
||||
PromptWidget->SetScreenPosition(ScreenPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
// ChildHood Project - 交互管理器核心组件
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)+ 第6节(行为规则实现)
|
||||
// 职责:交互全流程状态机、检测选择、类型分发、摄像机/转向/UI 控制
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "InteractionTypes.h"
|
||||
#include "InteractionManager.generated.h"
|
||||
|
||||
class UInteractableComponent;
|
||||
class APushCameraActor;
|
||||
class AChildHoodCharacter;
|
||||
class UInteractionPromptWidget;
|
||||
class UNarrativeTextWidget;
|
||||
|
||||
/**
|
||||
* UInteractionManager
|
||||
*
|
||||
* 挂载在 AChildHoodCharacter 上的组件,负责交互全流程管理:
|
||||
* - 层级状态机驱动(Free / Interacting + 子阶段)
|
||||
* - 附近交互物检测列表排序与选中管理
|
||||
* - 四种交互类型分发(观察/拾取/操作/对话)
|
||||
* - 角色自动转向插值
|
||||
* - 摄像机推镜/回位控制
|
||||
* - UI 提示与文本显示控制(v0.1 先用日志)
|
||||
*/
|
||||
UCLASS(ClassGroup=(Interaction), meta=(BlueprintSpawnableComponent))
|
||||
class UInteractionManager : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UInteractionManager();
|
||||
|
||||
// === 公开方法 ===
|
||||
|
||||
/** 发起交互(E键触发),前置检查通过后进入 Enter 阶段 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void BeginInteract();
|
||||
|
||||
/** 取消/结束交互(ESC/E键在Active阶段触发),AnimLock期间不可取消 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void CancelInteract();
|
||||
|
||||
/** 切换选中交互物(Tab/滚轮),Direction: +1下一个 / -1上一个 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void SwitchTarget(int32 Direction);
|
||||
|
||||
/** 注册交互物到检测列表(由 InteractableComponent 的碰撞回调触发) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void RegisterInteractable(UInteractableComponent* Interactable);
|
||||
|
||||
/** 从检测列表注销交互物(离开范围或消耗时触发) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||||
void UnregisterInteractable(UInteractableComponent* Interactable);
|
||||
|
||||
// === 委托 ===
|
||||
|
||||
/** 物品拾取事件 — 通知物品系统(Pickup 类型 ExecuteAnimEvent 中广播) */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Interaction|Events")
|
||||
FMLocalItemEvent OnItemPickedUp;
|
||||
|
||||
/** 物品获得事件 — 通知收集系统(Search 类型 OnAnimLockComplete 中广播) */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Interaction|Events")
|
||||
FMLocalItemEvent OnItemFound;
|
||||
|
||||
// === 可调参数 ===
|
||||
|
||||
/** 角色转向时长(秒) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||||
float TurnDuration = 0.2f;
|
||||
|
||||
/** 提示 UI 淡入时长(秒) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||||
float PromptFadeInDuration = 0.2f;
|
||||
|
||||
/** 提示 UI 淡出时长(秒) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||||
float PromptFadeOutDuration = 0.2f;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
private:
|
||||
|
||||
// === 状态机 ===
|
||||
|
||||
/** 交互系统顶层状态 */
|
||||
EInteractionState State = EInteractionState::Free;
|
||||
|
||||
/** Interacting 子阶段 */
|
||||
EInteractPhase Phase = EInteractPhase::None;
|
||||
|
||||
// === 检测与选择 ===
|
||||
|
||||
/** 当前附近的交互物列表,按水平距离排序 */
|
||||
UPROPERTY()
|
||||
TArray<UInteractableComponent*> NearbyInteractables;
|
||||
|
||||
/** 当前选中的交互物索引 */
|
||||
int32 SelectedIndex = 0;
|
||||
|
||||
/** 当前正在交互的交互物(交互过程中锁定) */
|
||||
UPROPERTY()
|
||||
UInteractableComponent* CurrentInteractable = nullptr;
|
||||
|
||||
// === 摄像机控制 ===
|
||||
|
||||
/** 推镜用临时摄像机 Actor(BeginPlay 中 Spawn) */
|
||||
UPROPERTY()
|
||||
TObjectPtr<APushCameraActor> PushCameraActor;
|
||||
|
||||
/** 推镜是否已发起(Enter阶段一次性标志) */
|
||||
bool bPushStarted = false;
|
||||
|
||||
// === 计时器 ===
|
||||
|
||||
/** 转向已用时间 */
|
||||
float TurnElapsed = 0.0f;
|
||||
|
||||
/** 推镜后等待已用时间 */
|
||||
float WaitElapsed = 0.0f;
|
||||
|
||||
/** 动画事件计时器(如60%时物品消失) */
|
||||
FTimerHandle AnimEventTimerHandle;
|
||||
|
||||
/** 动画结束计时器 */
|
||||
FTimerHandle AnimEndTimerHandle;
|
||||
|
||||
/** 退出阶段回位计时器 */
|
||||
FTimerHandle ExitTimerHandle;
|
||||
|
||||
/** 动画事件是否已触发 */
|
||||
bool bAnimEventFired = false;
|
||||
|
||||
// === UI 配置 ===
|
||||
|
||||
/** 提示 UI 蓝图类(需在编辑器中指定为 WBP_InteractionPrompt) */
|
||||
UPROPERTY(EditAnywhere, Category = "Interaction|UI")
|
||||
TSubclassOf<UInteractionPromptWidget> PromptWidgetClass;
|
||||
|
||||
/** 文本底框 UI 蓝图类(需在编辑器中指定为 WBP_NarrativeText) */
|
||||
UPROPERTY(EditAnywhere, Category = "Interaction|UI")
|
||||
TSubclassOf<UNarrativeTextWidget> NarrativeWidgetClass;
|
||||
|
||||
/** 提示 UI 高度偏移(交互物上方的世界空间 Z 偏移,cm) */
|
||||
UPROPERTY(EditAnywhere, Category = "Interaction|UI")
|
||||
float PromptHeightOffset = 80.0f;
|
||||
|
||||
// === UI 实例 ===
|
||||
|
||||
/** 交互提示 Widget 实例 */
|
||||
UPROPERTY()
|
||||
TObjectPtr<UInteractionPromptWidget> PromptWidget;
|
||||
|
||||
/** 文本底框 Widget 实例 */
|
||||
UPROPERTY()
|
||||
TObjectPtr<UNarrativeTextWidget> NarrativeWidget;
|
||||
|
||||
// === 文本选择 ===
|
||||
|
||||
/** 上次显示的叙事文本(用于不重复选取) */
|
||||
FString LastNarrativeText;
|
||||
|
||||
// === 内部方法 ===
|
||||
|
||||
/** 更新选中交互物(排序后 SelectedIndex = 0) */
|
||||
void UpdateSelection();
|
||||
|
||||
/** 更新提示 UI 内容和位置 */
|
||||
void UpdatePromptUI();
|
||||
|
||||
/** 隐藏提示 UI */
|
||||
void HidePrompt();
|
||||
|
||||
/** 更新提示 UI 的屏幕空间位置(跟随交互物世界位置投影) */
|
||||
void UpdatePromptScreenPosition(UInteractableComponent* Interactable);
|
||||
|
||||
/** Enter 阶段 Tick:转向插值 + 推镜 + 等待 */
|
||||
void TickEnterPhase(float DeltaTime);
|
||||
|
||||
/** AnimLock 阶段 Tick(v0.1 由计时器驱动,此处可为空) */
|
||||
void TickAnimLockPhase(float DeltaTime);
|
||||
|
||||
/** Exit 阶段 Tick(v0.1 由定时器驱动回 Free) */
|
||||
void TickExitPhase(float DeltaTime);
|
||||
|
||||
/** Enter 阶段完成后,根据交互类型分发到下一阶段 */
|
||||
void TransitionFromEnter();
|
||||
|
||||
/** 进入 AnimLock 阶段:播放蒙太奇或启动计时器 */
|
||||
void EnterAnimLockPhase();
|
||||
|
||||
/** 动画事件触发点回调(如拾取物消失、门状态切换) */
|
||||
void ExecuteAnimEvent();
|
||||
|
||||
/** 动画结束回调 */
|
||||
void OnAnimLockComplete();
|
||||
|
||||
/** 显示叙事文本(v0.1 用日志输出) */
|
||||
void ShowNarrativeText(const FString& Text);
|
||||
|
||||
/** 隐藏叙事文本(v0.1 用日志输出) */
|
||||
void HideNarrativeText();
|
||||
|
||||
/** 推镜:移动 PushCameraActor 并切换 ViewTarget */
|
||||
void PushCamera(FVector Target, float Duration);
|
||||
|
||||
/** 相机回位:切换回 Character 的 FollowCamera */
|
||||
void ReturnCamera(float Duration);
|
||||
|
||||
/** 计算推镜目标位置 */
|
||||
FVector CalculatePushPosition(UInteractableComponent* Interactable);
|
||||
|
||||
/** 随机选取叙事文本,排除上次 */
|
||||
FString PickRandomNarrative(const TArray<FString>& Texts);
|
||||
|
||||
/** Exit 阶段定时器回调:回到 Free 状态 */
|
||||
void OnExitTimerComplete();
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
// ChildHood Project - 交互提示 UI 基类 实现
|
||||
|
||||
#include "Interaction/InteractionPromptWidget.h"
|
||||
#include "Components/TextBlock.h"
|
||||
|
||||
void UInteractionPromptWidget::NativeOnInitialized()
|
||||
{
|
||||
Super::NativeOnInitialized();
|
||||
|
||||
// 初始隐藏
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
|
||||
void UInteractionPromptWidget::SetPromptText(const FString& Text)
|
||||
{
|
||||
if (PromptTextBlock)
|
||||
{
|
||||
PromptTextBlock->SetText(FText::FromString(Text));
|
||||
}
|
||||
}
|
||||
|
||||
void UInteractionPromptWidget::SetScreenPosition(const FVector2D& Position)
|
||||
{
|
||||
// 使用 RenderTranslation 偏移 Widget 位置
|
||||
// 蓝图中 CanvasPanel 的 Anchors 应设置为屏幕左上角
|
||||
// 此处直接设置 RenderTranslation 来移动位置
|
||||
SetRenderTranslation(Position);
|
||||
}
|
||||
|
||||
void UInteractionPromptWidget::Show()
|
||||
{
|
||||
if (bIsVisible) return;
|
||||
bIsVisible = true;
|
||||
|
||||
SetVisibility(ESlateVisibility::HitTestInvisible);
|
||||
|
||||
if (FadeInAnim)
|
||||
{
|
||||
PlayAnimation(FadeInAnim, 0.0f, 1, EUMGSequencePlayMode::Forward, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void UInteractionPromptWidget::Hide()
|
||||
{
|
||||
if (!bIsVisible) return;
|
||||
|
||||
if (FadeOutAnim)
|
||||
{
|
||||
PlayAnimation(FadeOutAnim, 0.0f, 1, EUMGSequencePlayMode::Forward, 1.0f);
|
||||
// 动画播完后隐藏(简单方案:直接设置定时器隐藏)
|
||||
// 动画时长由蓝图中的 FadeOutAnim 决定,这里用固定 0.2s
|
||||
FTimerHandle TempHandle;
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
World->GetTimerManager().SetTimer(TempHandle, [this]()
|
||||
{
|
||||
bIsVisible = false;
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}, 0.2f, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bIsVisible = false;
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// ChildHood Project - 交互提示 UI 基类
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第6节(提示UI显示/隐藏)
|
||||
// 职责:屏幕空间悬浮提示 "[E] 动作词 名称",跟随交互物位置
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "InteractionPromptWidget.generated.h"
|
||||
|
||||
class UTextBlock;
|
||||
|
||||
/**
|
||||
* UInteractionPromptWidget
|
||||
*
|
||||
* 交互提示 UI 的 C++ 基类。蓝图子类(WBP_InteractionPrompt)继承此类,
|
||||
* 在 UMG 编辑器中布局可视组件,并确保组件名与 BindWidget 匹配。
|
||||
*
|
||||
* 绑定要求:
|
||||
* - TextBlock 名为 "PromptTextBlock" — 显示提示文字
|
||||
* - WidgetAnimation 名为 "FadeInAnim" — 淡入动画(0.2s)
|
||||
* - WidgetAnimation 名为 "FadeOutAnim" — 淡出动画(0.2s)
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable)
|
||||
class UInteractionPromptWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
/** 设置提示文字内容 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Prompt")
|
||||
void SetPromptText(const FString& Text);
|
||||
|
||||
/** 设置屏幕空间位置(由 InteractionManager 每帧调用) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Prompt")
|
||||
void SetScreenPosition(const FVector2D& Position);
|
||||
|
||||
/** 显示提示(播放淡入动画) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Prompt")
|
||||
void Show();
|
||||
|
||||
/** 隐藏提示(播放淡出动画) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Prompt")
|
||||
void Hide();
|
||||
|
||||
protected:
|
||||
|
||||
/** 提示文字 TextBlock,蓝图子类必须有一个同名 TextBlock */
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* PromptTextBlock;
|
||||
|
||||
/** 淡入动画(0.2s Opacity 0→1),蓝图子类必须有同名 WidgetAnimation */
|
||||
UPROPERTY(meta = (BindWidgetAnim), Transient)
|
||||
UWidgetAnimation* FadeInAnim;
|
||||
|
||||
/** 淡出动画(0.2s Opacity 1→0),蓝图子类必须有同名 WidgetAnimation */
|
||||
UPROPERTY(meta = (BindWidgetAnim), Transient)
|
||||
UWidgetAnimation* FadeOutAnim;
|
||||
|
||||
/** 是否正在显示中 */
|
||||
bool bIsVisible = false;
|
||||
|
||||
virtual void NativeOnInitialized() override;
|
||||
};
|
||||
@@ -0,0 +1,178 @@
|
||||
// ChildHood Project - 交互系统数据类型定义
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第5节(核心数据结构)+ 第12节(跨场景持久化)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "InteractionTypes.generated.h"
|
||||
|
||||
// ============================================================================
|
||||
// 枚举
|
||||
// ============================================================================
|
||||
|
||||
/** 交互类型 */
|
||||
UENUM(BlueprintType)
|
||||
enum class EInteractType : uint8
|
||||
{
|
||||
Examine UMETA(DisplayName = "观察"),
|
||||
Pickup UMETA(DisplayName = "拾取"),
|
||||
Operate UMETA(DisplayName = "操作"),
|
||||
Talk UMETA(DisplayName = "对话")
|
||||
};
|
||||
|
||||
/** 操作子类型(仅 Operate 类型有效) */
|
||||
UENUM(BlueprintType)
|
||||
enum class EOperateSubType : uint8
|
||||
{
|
||||
Door UMETA(DisplayName = "门(开关切换)"),
|
||||
Search UMETA(DisplayName = "翻找")
|
||||
};
|
||||
|
||||
/** 交互系统顶层状态 */
|
||||
UENUM(BlueprintType)
|
||||
enum class EInteractionState : uint8
|
||||
{
|
||||
Free UMETA(DisplayName = "自由状态"),
|
||||
Interacting UMETA(DisplayName = "交互中"),
|
||||
SubSystem UMETA(DisplayName = "子系统(v0.1预留)"),
|
||||
Cutscene UMETA(DisplayName = "过场(v0.1预留)")
|
||||
};
|
||||
|
||||
/** Interacting 子阶段 */
|
||||
UENUM(BlueprintType)
|
||||
enum class EInteractPhase : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "无"),
|
||||
Enter UMETA(DisplayName = "进入(转向+推镜)"),
|
||||
AnimLock UMETA(DisplayName = "动画锁定"),
|
||||
Active UMETA(DisplayName = "活跃(等待输入)"),
|
||||
Exit UMETA(DisplayName = "退出(回位)")
|
||||
};
|
||||
|
||||
/** 交互结束后动作 */
|
||||
UENUM(BlueprintType)
|
||||
enum class EPostAction : uint8
|
||||
{
|
||||
Return UMETA(DisplayName = "回到Free"),
|
||||
Minigame UMETA(DisplayName = "小游戏(v0.1预留)"),
|
||||
Dialogue UMETA(DisplayName = "对话(v0.1预留)"),
|
||||
SceneChange UMETA(DisplayName = "场景切换(v0.1预留)")
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 配置数据结构
|
||||
// ============================================================================
|
||||
|
||||
/** 可交互物配置数据 — 每个交互物实例独立配置 */
|
||||
USTRUCT(BlueprintType)
|
||||
struct FInteractableData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// === 基本信息 ===
|
||||
|
||||
/** 唯一ID(如 "fridge_home"),用于持久化存储和物品系统对接 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Basic")
|
||||
FName ItemId;
|
||||
|
||||
/** 显示名称(如 "旧冰箱"),用于提示UI */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Basic")
|
||||
FString DisplayName;
|
||||
|
||||
/** 交互类型 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Basic")
|
||||
EInteractType Type = EInteractType::Examine;
|
||||
|
||||
/** 操作子类型,仅 Type==Operate 时可见可编辑 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Basic",
|
||||
meta = (EditCondition = "Type == EInteractType::Operate", EditConditionHides))
|
||||
EOperateSubType OperateSubType = EOperateSubType::Door;
|
||||
|
||||
// === 触发 ===
|
||||
|
||||
/** 触发半径(cm),默认1.5m */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Trigger",
|
||||
meta = (ClampMin = "50.0", ClampMax = "500.0"))
|
||||
float TriggerRadius = 150.0f;
|
||||
|
||||
/** 是否一次性消耗(消耗后不再可交互) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Trigger")
|
||||
bool bOneShot = false;
|
||||
|
||||
// === 提示文本 ===
|
||||
|
||||
/** 动作词(如 "查看"、"拾取"、"打开") */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Prompt")
|
||||
FString InteractVerb;
|
||||
|
||||
/** 备选动词(如 "关上"),门打开时使用,仅 Operate+Door 时可见 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Prompt",
|
||||
meta = (EditCondition = "Type == EInteractType::Operate && OperateSubType == EOperateSubType::Door"))
|
||||
FString InteractVerbAlt;
|
||||
|
||||
// === 叙事/对话文本 ===
|
||||
|
||||
/** 文本列表,随机选取,不重复上次 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Text")
|
||||
TArray<FString> NarrativeTexts;
|
||||
|
||||
// === 摄像机推镜 ===
|
||||
|
||||
/** 是否使用摄像机推镜 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Camera")
|
||||
bool bUseCameraPush = false;
|
||||
|
||||
/** 推镜距离(cm),仅 bUseCameraPush 时可编辑 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Camera",
|
||||
meta = (EditCondition = "bUseCameraPush", ClampMin = "10.0", ClampMax = "300.0"))
|
||||
float CameraPushDistance = 80.0f;
|
||||
|
||||
/** 推镜过渡时长(秒),仅 bUseCameraPush 时可编辑 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Camera",
|
||||
meta = (EditCondition = "bUseCameraPush", ClampMin = "0.1", ClampMax = "2.0"))
|
||||
float CameraPushDuration = 0.5f;
|
||||
|
||||
/** 相机回位时长(秒),仅 bUseCameraPush 时可编辑 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Camera",
|
||||
meta = (EditCondition = "bUseCameraPush", ClampMin = "0.1", ClampMax = "2.0"))
|
||||
float CameraReturnDuration = 0.3f;
|
||||
|
||||
/** 推镜完成后到文本显示的等待时间(秒),仅 bUseCameraPush 时可编辑 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Camera",
|
||||
meta = (EditCondition = "bUseCameraPush", ClampMin = "0.0", ClampMax = "1.0"))
|
||||
float PushWaitDelay = 0.2f;
|
||||
|
||||
// === 动画 ===
|
||||
|
||||
/** 交互动画蒙太奇(可选,为空时用计时器模拟) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Anim")
|
||||
TObjectPtr<UAnimMontage> InteractMontage;
|
||||
|
||||
/** 无蒙太奇时的动画持续时间(秒) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Anim",
|
||||
meta = (ClampMin = "0.1", ClampMax = "5.0"))
|
||||
float AnimDuration = 1.0f;
|
||||
|
||||
/** 动画事件触发点(0-1比例),如0.6表示动画播放至60%时触发物品消失 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Anim",
|
||||
meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
float AnimEventTimepoint = 0.6f;
|
||||
|
||||
// === 结束动作 ===
|
||||
|
||||
/** 交互结束后的动作 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interact|Post")
|
||||
EPostAction PostAction = EPostAction::Return;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 委托
|
||||
// ============================================================================
|
||||
|
||||
/** 物品拾取/获得事件 — 通知物品系统和收集系统 */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
|
||||
FMLocalItemEvent,
|
||||
FName, ItemId,
|
||||
const FString&, DisplayName,
|
||||
const FName&, Category
|
||||
);
|
||||
@@ -0,0 +1,57 @@
|
||||
// ChildHood Project - 文本底框 UI 基类 实现
|
||||
|
||||
#include "Interaction/NarrativeTextWidget.h"
|
||||
#include "Components/TextBlock.h"
|
||||
|
||||
void UNarrativeTextWidget::NativeOnInitialized()
|
||||
{
|
||||
Super::NativeOnInitialized();
|
||||
|
||||
// 初始隐藏
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
|
||||
void UNarrativeTextWidget::SetNarrativeText(const FString& Text)
|
||||
{
|
||||
if (NarrativeTextBlock)
|
||||
{
|
||||
NarrativeTextBlock->SetText(FText::FromString(Text));
|
||||
}
|
||||
}
|
||||
|
||||
void UNarrativeTextWidget::Show()
|
||||
{
|
||||
if (bIsVisible) return;
|
||||
bIsVisible = true;
|
||||
|
||||
SetVisibility(ESlateVisibility::HitTestInvisible);
|
||||
|
||||
if (FadeInAnim)
|
||||
{
|
||||
PlayAnimation(FadeInAnim, 0.0f, 1, EUMGSequencePlayMode::Forward, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void UNarrativeTextWidget::Hide()
|
||||
{
|
||||
if (!bIsVisible) return;
|
||||
|
||||
if (FadeOutAnim)
|
||||
{
|
||||
PlayAnimation(FadeOutAnim, 0.0f, 1, EUMGSequencePlayMode::Forward, 1.0f);
|
||||
FTimerHandle TempHandle;
|
||||
if (UWorld* World = GetWorld())
|
||||
{
|
||||
World->GetTimerManager().SetTimer(TempHandle, [this]()
|
||||
{
|
||||
bIsVisible = false;
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}, 0.2f, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bIsVisible = false;
|
||||
SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// ChildHood Project - 文本底框 UI 基类
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第6节(通用文本显示UI)
|
||||
// 职责:半透明底框 + 一句话叙事/对话文本,带淡入淡出
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "NarrativeTextWidget.generated.h"
|
||||
|
||||
class UTextBlock;
|
||||
|
||||
/**
|
||||
* UNarrativeTextWidget
|
||||
*
|
||||
* 文本底框 UI 的 C++ 基类。蓝图子类(WBP_NarrativeText)继承此类,
|
||||
* 在 UMG 编辑器中布局可视组件,并确保组件名与 BindWidget 匹配。
|
||||
*
|
||||
* 绑定要求:
|
||||
* - TextBlock 名为 "NarrativeTextBlock" — 显示叙事/对话文字
|
||||
* - WidgetAnimation 名为 "FadeInAnim" — 淡入动画(0.2s)
|
||||
* - WidgetAnimation 名为 "FadeOutAnim" — 淡出动画(0.2s)
|
||||
*
|
||||
* 布局要求:
|
||||
* - Anchors: Horizontal Center, Vertical ~0.6(屏幕中心偏下)
|
||||
* - Border: 半透明黑色背景(~60%),圆角,SizeToContent
|
||||
* - TextBlock: 白色文字,居中,自动换行
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable)
|
||||
class UNarrativeTextWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
/** 设置叙事文本内容 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Narrative")
|
||||
void SetNarrativeText(const FString& Text);
|
||||
|
||||
/** 显示文本(播放淡入动画) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Narrative")
|
||||
void Show();
|
||||
|
||||
/** 隐藏文本(播放淡出动画) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Interaction|Narrative")
|
||||
void Hide();
|
||||
|
||||
protected:
|
||||
|
||||
/** 叙事文字 TextBlock,蓝图子类必须有一个同名 TextBlock */
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
UTextBlock* NarrativeTextBlock;
|
||||
|
||||
/** 淡入动画(0.2s),蓝图子类必须有同名 WidgetAnimation */
|
||||
UPROPERTY(meta = (BindWidgetAnim), Transient)
|
||||
UWidgetAnimation* FadeInAnim;
|
||||
|
||||
/** 淡出动画(0.2s),蓝图子类必须有同名 WidgetAnimation */
|
||||
UPROPERTY(meta = (BindWidgetAnim), Transient)
|
||||
UWidgetAnimation* FadeOutAnim;
|
||||
|
||||
/** 是否正在显示中 */
|
||||
bool bIsVisible = false;
|
||||
|
||||
virtual void NativeOnInitialized() override;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
// ChildHood Project - 推镜用临时摄像机 实现
|
||||
|
||||
#include "Interaction/PushCameraActor.h"
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
|
||||
// ============================================================================
|
||||
// 构造函数
|
||||
// ============================================================================
|
||||
|
||||
APushCameraActor::APushCameraActor()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// 创建摄像机组件
|
||||
CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
|
||||
// 不需要根组件的碰撞
|
||||
SetRootComponent(CameraComp);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// ChildHood Project - 推镜用临时摄像机
|
||||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)
|
||||
// 职责:极简 Actor,仅持有一个 UCameraComponent,供 SetViewTargetWithBlend 使用
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "PushCameraActor.generated.h"
|
||||
|
||||
class UCameraComponent;
|
||||
|
||||
/**
|
||||
* APushCameraActor
|
||||
*
|
||||
* 交互系统推镜时使用的临时摄像机 Actor。
|
||||
* 由 InteractionManager 在 BeginPlay 中 Spawn,随 Character 生命周期。
|
||||
* InteractionManager 在推镜时设置其 Location/Rotation,
|
||||
* 然后通过 PlayerController::SetViewTargetWithBlend 切换 ViewTarget。
|
||||
*/
|
||||
UCLASS()
|
||||
class APushCameraActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
APushCameraActor();
|
||||
|
||||
/** 推镜摄像机组件 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
|
||||
UCameraComponent* CameraComp;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
# API易 平台配置
|
||||
# 复制此文件为 .env 并填入你的 API Key
|
||||
# cp .env.example .env
|
||||
|
||||
# API 令牌(必填)— 在 https://api.apiyi.com/token 创建
|
||||
APIYI_API_KEY=sk-your-api-key-here
|
||||
|
||||
# API 地址(通常不需要修改)
|
||||
APIYI_BASE_URL=https://api.apiyi.com/v1
|
||||
|
||||
# 默认生图模型
|
||||
# 可选: gpt-image-2, gemini-3-1-flash-image-preview, dall-e-3, flux-pro-v1.1
|
||||
APIYI_MODEL=gpt-image-2
|
||||
@@ -0,0 +1,454 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
ChildHood AI Art Generation Tool
|
||||
通过 API易 平台调用 AI 生图模型
|
||||
|
||||
Usage:
|
||||
python image_gen.py --test # 测试 API 连通性
|
||||
python image_gen.py --generate "千禧年中国城郊的小卖部门口" # 文生图(自动加风格前缀)
|
||||
python image_gen.py --generate "a red apple" --no-style # 纯文生图(不加风格前缀)
|
||||
python image_gen.py --calibrate # 风格校准(5 个测试物体)
|
||||
python image_gen.py --fuse --style style.png --content photo.jpg # 双参考融合
|
||||
python image_gen.py --fuse --style style.png --content photo.jpg --prompt "自定义 prompt"
|
||||
|
||||
Requirements:
|
||||
pip install openai python-dotenv
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
# Windows 控制台 UTF-8 支持
|
||||
if sys.platform == "win32":
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 路径配置
|
||||
# ---------------------------------------------------------------------------
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent # ai-art-research/tools/
|
||||
RESEARCH_DIR = SCRIPT_DIR.parent # ai-art-research/
|
||||
DOTENV_PATH = RESEARCH_DIR / ".env"
|
||||
OUTPUT_BASE = RESEARCH_DIR / "生成结果"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 加载 .env
|
||||
# ---------------------------------------------------------------------------
|
||||
if DOTENV_PATH.exists():
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(DOTENV_PATH)
|
||||
|
||||
API_KEY = os.getenv("APIYI_API_KEY", "")
|
||||
BASE_URL = os.getenv("APIYI_BASE_URL", "https://api.apiyi.com/v1")
|
||||
DEFAULT_MODEL = os.getenv("APIYI_MODEL", "gpt-image-2")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 风格 Prompt 种子(来自工作流方案 v0.1)
|
||||
# ---------------------------------------------------------------------------
|
||||
STYLE_SEED_EN = (
|
||||
"3D low-poly game art, flat cel-shaded with solid color blocks, "
|
||||
"bright warm-cool balanced saturated palette, soft diffused lighting "
|
||||
"with subtle shadows, simplified geometric forms with clean edges, "
|
||||
"low-angle third-person perspective, nostalgic warm summer atmosphere"
|
||||
)
|
||||
|
||||
# 风格校准测试物体(中文名, 英文 prompt)
|
||||
CALIBRATION_OBJECTS = [
|
||||
("乌鸦", "a crow standing on the ground"),
|
||||
("茶杯", "a teacup on a wooden table"),
|
||||
("老人", "an old man standing in a village street"),
|
||||
("山湖", "a mountain lake with trees"),
|
||||
("苹果", "a red apple on the ground"),
|
||||
]
|
||||
|
||||
# 双参考融合默认 prompt
|
||||
DEFAULT_FUSION_PROMPT = """\
|
||||
图1 是我的风格参考(一张游戏截图)。图2 是我的内容参考(一张现实照片)。
|
||||
请生成一张新图片,用图1的美术风格来呈现图2中的场景内容。
|
||||
|
||||
风格要求:
|
||||
- 高度简化的低多边形几何形体,干净利落的边缘
|
||||
- 平面色块着色,不用渐变或写实纹理
|
||||
- 鲜艳明亮的暖冷平衡色调(暖黄、天蓝、翠绿为主)
|
||||
- 柔和散射光,阴影淡而柔和
|
||||
- 微低角度第三人称视角
|
||||
- 温暖怀旧的夏日午后氛围
|
||||
|
||||
内容要求:
|
||||
- 保留图2中的建筑类型、布局、空间关系
|
||||
- 但把所有建筑元素替换为千禧年中国城郊的风格
|
||||
- 色调保持温暖怀旧"""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 工具函数
|
||||
# ---------------------------------------------------------------------------
|
||||
def get_client() -> "OpenAI":
|
||||
"""创建 OpenAI 客户端"""
|
||||
if not API_KEY:
|
||||
print("❌ 未找到 API Key")
|
||||
print(f" 请在 {DOTENV_PATH} 中设置: APIYI_API_KEY=sk-xxx")
|
||||
sys.exit(1)
|
||||
from openai import OpenAI
|
||||
return OpenAI(api_key=API_KEY, base_url=BASE_URL)
|
||||
|
||||
|
||||
def _extract_image_bytes(img_obj) -> bytes:
|
||||
"""从 API 响应中提取图片字节数据"""
|
||||
# 优先 base64
|
||||
b64 = getattr(img_obj, "b64_json", None)
|
||||
if b64:
|
||||
return base64.b64decode(b64)
|
||||
# 其次 URL
|
||||
url = getattr(img_obj, "url", None)
|
||||
if url:
|
||||
print(" ⬇️ 正在下载图片...")
|
||||
return urllib.request.urlopen(url).read()
|
||||
raise ValueError("响应中未找到图片数据(无 b64_json 也无 url)")
|
||||
|
||||
|
||||
def _sanitize_filename(s: str, max_len: int = 40) -> str:
|
||||
"""清理文件名中的非法字符"""
|
||||
result = "".join(c if c.isalnum() or c in "._-" else "_" for c in s)
|
||||
return result[:max_len].rstrip("_")
|
||||
|
||||
|
||||
def save_result(image_bytes: bytes, metadata: dict, subdir: str = "") -> Path:
|
||||
"""保存图片和元数据,返回图片路径"""
|
||||
ts = datetime.now().strftime("%y%m%d-%H%M%S")
|
||||
model_slug = metadata.get("model", "unknown").replace("/", "-").replace(".", "-")
|
||||
|
||||
out_dir = OUTPUT_BASE / subdir if subdir else OUTPUT_BASE
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
prompt_tag = _sanitize_filename(metadata.get("prompt", "gen"))
|
||||
filename = f"{ts}_{model_slug}_{prompt_tag}.png"
|
||||
|
||||
img_path = out_dir / filename
|
||||
img_path.write_bytes(image_bytes)
|
||||
|
||||
meta_path = img_path.with_suffix(".meta.json")
|
||||
meta_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
|
||||
print(f"✅ 已保存: {img_path.name}")
|
||||
return img_path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 功能:测试连通性
|
||||
# ---------------------------------------------------------------------------
|
||||
def cmd_test(client):
|
||||
"""测试 API 易连通性,生成一张简单测试图"""
|
||||
print("🔗 测试 API易 连通性...")
|
||||
print(f" Base URL: {BASE_URL}")
|
||||
print(f" Model: {DEFAULT_MODEL}")
|
||||
print(f" API Key: {API_KEY[:8]}...{API_KEY[-4:]}")
|
||||
print()
|
||||
|
||||
prompt = f"{STYLE_SEED_EN}, a simple red cube on a white background, test image"
|
||||
print(f" Prompt: {prompt[:80]}...")
|
||||
|
||||
response = client.images.generate(
|
||||
model=DEFAULT_MODEL,
|
||||
prompt=prompt,
|
||||
size="1024x1024",
|
||||
quality="low",
|
||||
n=1,
|
||||
)
|
||||
|
||||
image_bytes = _extract_image_bytes(response.data[0])
|
||||
save_result(image_bytes, {
|
||||
"model": DEFAULT_MODEL,
|
||||
"prompt": prompt,
|
||||
"mode": "connection_test",
|
||||
"size": "1024x1024",
|
||||
"quality": "low",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}, subdir="测试")
|
||||
|
||||
print()
|
||||
print("✅ API 连通性测试通过!")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 功能:文生图
|
||||
# ---------------------------------------------------------------------------
|
||||
def cmd_generate(client, prompt: str, use_style: bool, size: str, quality: str,
|
||||
model: str, subdir: str):
|
||||
"""文生图"""
|
||||
model = model or DEFAULT_MODEL
|
||||
full_prompt = f"{STYLE_SEED_EN}, {prompt}" if use_style else prompt
|
||||
|
||||
print(f"🎨 文生图")
|
||||
print(f" 模型: {model}")
|
||||
print(f" 尺寸: {size} 质量: {quality}")
|
||||
print(f" 风格前缀: {'是' if use_style else '否'}")
|
||||
print(f" Prompt: {full_prompt[:100]}{'...' if len(full_prompt) > 100 else ''}")
|
||||
print()
|
||||
|
||||
response = client.images.generate(
|
||||
model=model,
|
||||
prompt=full_prompt,
|
||||
size=size,
|
||||
quality=quality,
|
||||
n=1,
|
||||
)
|
||||
|
||||
image_bytes = _extract_image_bytes(response.data[0])
|
||||
save_result(image_bytes, {
|
||||
"model": model,
|
||||
"prompt": full_prompt,
|
||||
"mode": "text_to_image",
|
||||
"style_prefix_used": use_style,
|
||||
"size": size,
|
||||
"quality": quality,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}, subdir=subdir)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 功能:风格校准
|
||||
# ---------------------------------------------------------------------------
|
||||
def cmd_calibrate(client, model: str):
|
||||
"""风格校准 — 5 个测试物体"""
|
||||
model = model or DEFAULT_MODEL
|
||||
subdir = "风格校准"
|
||||
|
||||
print("🎯 开始风格校准测试")
|
||||
print(f" 模型: {model}")
|
||||
print(f" 风格种子: {STYLE_SEED_EN[:60]}...")
|
||||
print(f" 测试物体: {', '.join(zh for zh, _ in CALIBRATION_OBJECTS)}")
|
||||
print()
|
||||
|
||||
success = 0
|
||||
for zh_name, en_prompt in CALIBRATION_OBJECTS:
|
||||
full_prompt = f"{STYLE_SEED_EN}, {en_prompt}"
|
||||
print(f" 🎨 生成: {zh_name} ...")
|
||||
|
||||
try:
|
||||
response = client.images.generate(
|
||||
model=model,
|
||||
prompt=full_prompt,
|
||||
size="1024x1024",
|
||||
quality="medium",
|
||||
n=1,
|
||||
response_format="b64_json",
|
||||
)
|
||||
image_bytes = _extract_image_bytes(response.data[0])
|
||||
save_result(image_bytes, {
|
||||
"model": model,
|
||||
"prompt": full_prompt,
|
||||
"mode": "style_calibration",
|
||||
"object_zh": zh_name,
|
||||
"object_en": en_prompt,
|
||||
"style_seed": STYLE_SEED_EN,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}, subdir=subdir)
|
||||
success += 1
|
||||
except Exception as e:
|
||||
print(f" ❌ 失败: {e}")
|
||||
print()
|
||||
|
||||
print(f"🎉 风格校准完成!成功 {success}/{len(CALIBRATION_OBJECTS)} 张")
|
||||
print(f" 输出目录: {OUTPUT_BASE / subdir}")
|
||||
print()
|
||||
print("📋 验证方法:打开上述目录,检查 5 张图是否视觉风格统一。")
|
||||
print(" 如果风格不一致,需要调整 STYLE_SEED_EN 后重新运行。")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 功能:双参考融合
|
||||
# ---------------------------------------------------------------------------
|
||||
def cmd_fuse(client, style_path: str, content_path: str, prompt: str,
|
||||
model: str, subdir: str):
|
||||
"""双参考图融合"""
|
||||
model = model or DEFAULT_MODEL
|
||||
fusion_prompt = prompt or DEFAULT_FUSION_PROMPT
|
||||
subdir = subdir or "双参考融合"
|
||||
|
||||
style_file = Path(style_path).resolve()
|
||||
content_file = Path(content_path).resolve()
|
||||
|
||||
if not style_file.exists():
|
||||
print(f"❌ 风格参考图不存在: {style_file}")
|
||||
sys.exit(1)
|
||||
if not content_file.exists():
|
||||
print(f"❌ 内容参考图不存在: {content_file}")
|
||||
sys.exit(1)
|
||||
|
||||
print("🔗 双参考融合")
|
||||
print(f" 模型: {model}")
|
||||
print(f" 风格参考: {style_file.name}")
|
||||
print(f" 内容参考: {content_file.name}")
|
||||
print(f" Prompt: {fusion_prompt[:80]}...")
|
||||
print()
|
||||
|
||||
# 编码图片为 base64
|
||||
style_b64 = base64.b64encode(style_file.read_bytes()).decode()
|
||||
content_b64 = base64.b64encode(content_file.read_bytes()).decode()
|
||||
|
||||
# 确定图片 MIME 类型
|
||||
ext_map = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
|
||||
".webp": "image/webp", ".gif": "image/gif"}
|
||||
style_mime = ext_map.get(style_file.suffix.lower(), "image/png")
|
||||
content_mime = ext_map.get(content_file.suffix.lower(), "image/png")
|
||||
|
||||
# 尝试方法 1: images.edit(带多图的编辑模式)
|
||||
image_bytes = None
|
||||
errors = []
|
||||
|
||||
# 方法 1: images.edit
|
||||
print(" 尝试方式 1: images.edit ...")
|
||||
try:
|
||||
response = client.images.edit(
|
||||
model=model,
|
||||
image=[
|
||||
{"type": "image_file", "image_file": {
|
||||
"file_data": f"data:{style_mime};base64,{style_b64}",
|
||||
"filename": style_file.name,
|
||||
}},
|
||||
{"type": "image_file", "image_file": {
|
||||
"file_data": f"data:{content_mime};base64,{content_b64}",
|
||||
"filename": content_file.name,
|
||||
}},
|
||||
],
|
||||
prompt=fusion_prompt,
|
||||
size="1024x1024",
|
||||
)
|
||||
image_bytes = _extract_image_bytes(response.data[0])
|
||||
print(" ✅ 方式 1 成功")
|
||||
except Exception as e:
|
||||
errors.append(f"images.edit: {e}")
|
||||
print(f" ⚠️ 方式 1 失败: {e}")
|
||||
|
||||
# 方法 2: images.generate with b64 image in prompt (chat-style)
|
||||
if image_bytes is None:
|
||||
print(" 尝试方式 2: images.generate with extra_body ...")
|
||||
try:
|
||||
response = client.images.generate(
|
||||
model=model,
|
||||
prompt=fusion_prompt,
|
||||
size="1024x1024",
|
||||
quality="medium",
|
||||
n=1,
|
||||
response_format="b64_json",
|
||||
extra_body={
|
||||
"image": [
|
||||
f"data:{style_mime};base64,{style_b64[:100]}...", # 截断防止请求过大
|
||||
],
|
||||
},
|
||||
)
|
||||
image_bytes = _extract_image_bytes(response.data[0])
|
||||
print(" ✅ 方式 2 成功")
|
||||
except Exception as e:
|
||||
errors.append(f"images.generate+extra_body: {e}")
|
||||
print(f" ⚠️ 方式 2 失败: {e}")
|
||||
|
||||
if image_bytes is None:
|
||||
print()
|
||||
print("❌ 双参考融合 API 调用失败。")
|
||||
print(" 这可能是因为 API易 不支持多图输入的 images.edit 端点。")
|
||||
print()
|
||||
print("💡 替代方案:")
|
||||
print(" 1. 使用 API易 网页界面上传多张参考图手动操作")
|
||||
print(" 2. 或将风格描述写入 prompt,仅上传内容参考图(单图模式)")
|
||||
print()
|
||||
print(" 所有错误:")
|
||||
for err in errors:
|
||||
print(f" - {err}")
|
||||
sys.exit(1)
|
||||
|
||||
save_result(image_bytes, {
|
||||
"model": model,
|
||||
"prompt": fusion_prompt,
|
||||
"mode": "dual_reference_fusion",
|
||||
"style_reference": str(style_file),
|
||||
"content_reference": str(content_file),
|
||||
"size": "1024x1024",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}, subdir=subdir)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CLI 入口
|
||||
# ---------------------------------------------------------------------------
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="ChildHood AI Art Generation Tool — 通过 API易 生图",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""\
|
||||
示例:
|
||||
python image_gen.py --test # 测试连通性
|
||||
python image_gen.py -g "千禧年中国城郊的小卖部门口" # 文生图
|
||||
python image_gen.py -g "a red apple" --no-style # 不加风格前缀
|
||||
python image_gen.py --calibrate # 风格校准
|
||||
python image_gen.py --fuse --style ref.png --content photo.jpg # 双参考融合
|
||||
python image_gen.py --fuse -s style.png -c photo.jpg -p "自定义" # 自定义 prompt
|
||||
|
||||
环境变量 (ai-art-research/.env):
|
||||
APIYI_API_KEY API易 令牌 (必填)
|
||||
APIYI_BASE_URL API 地址 (默认 https://api.apiyi.com/v1)
|
||||
APIYI_MODEL 默认模型 (默认 gpt-image-2)
|
||||
""",
|
||||
)
|
||||
|
||||
# 互斥的操作模式
|
||||
mode = parser.add_mutually_exclusive_group()
|
||||
mode.add_argument("--test", action="store_true", help="测试 API 连通性")
|
||||
mode.add_argument("-g", "--generate", type=str, metavar="PROMPT", help="文生图")
|
||||
mode.add_argument("--calibrate", action="store_true", help="风格校准(5 个测试物体)")
|
||||
mode.add_argument("--fuse", action="store_true", help="双参考图融合模式")
|
||||
|
||||
# 参数
|
||||
parser.add_argument("-s", "--style", type=str, help="风格参考图路径(配合 --fuse)")
|
||||
parser.add_argument("-c", "--content", type=str, help="内容参考图路径(配合 --fuse)")
|
||||
parser.add_argument("-p", "--prompt", type=str, help="自定义 prompt")
|
||||
parser.add_argument("-m", "--model", type=str, help=f"模型 (默认: {DEFAULT_MODEL})")
|
||||
parser.add_argument("--no-style", action="store_true", help="文生图不加风格前缀")
|
||||
parser.add_argument("--size", type=str, default="1024x1024", help="图片尺寸")
|
||||
parser.add_argument("--quality", type=str, default="medium",
|
||||
choices=["low", "medium", "high"], help="质量")
|
||||
parser.add_argument("--subdir", type=str, default="", help="输出子目录名")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 无参数时显示帮助
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
client = get_client()
|
||||
|
||||
if args.test:
|
||||
cmd_test(client)
|
||||
elif args.generate:
|
||||
cmd_generate(
|
||||
client, args.generate,
|
||||
use_style=not args.no_style,
|
||||
size=args.size, quality=args.quality,
|
||||
model=args.model, subdir=args.subdir or "文生图",
|
||||
)
|
||||
elif args.calibrate:
|
||||
cmd_calibrate(client, model=args.model)
|
||||
elif args.fuse:
|
||||
if not args.style or not args.content:
|
||||
parser.error("双参考融合需要 --style (-s) 和 --content (-c) 参数")
|
||||
cmd_fuse(
|
||||
client, args.style, args.content,
|
||||
prompt=args.prompt, model=args.model, subdir=args.subdir,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"model": "gpt-image-2",
|
||||
"prompt": "3D low-poly game art, flat cel-shaded with solid color blocks, bright warm-cool balanced saturated palette, soft diffused lighting with subtle shadows, simplified geometric forms with clean edges, low-angle third-person perspective, nostalgic warm summer atmosphere, a simple red cube on a white background, test image",
|
||||
"mode": "connection_test",
|
||||
"size": "1024x1024",
|
||||
"quality": "low",
|
||||
"timestamp": "2026-06-10T00:35:40.485529"
|
||||
}
|
||||
BIN
Binary file not shown.
+215
-24
@@ -2,7 +2,7 @@
|
||||
|
||||
> 完整游戏世界的空间、时代、氛围设计。
|
||||
> 覆盖城市主场景 + 乡下场景,以及场景与各系统的关联。
|
||||
> 最后更新:2026-06-01
|
||||
> 最后更新:2026-06-10
|
||||
|
||||
---
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
|------|------|--------|
|
||||
| 尺度 | ~80m × 60m | ~150m × 120m |
|
||||
| 区域数 | 6 个核心 + 1 背景 | 主街 + 生活区 + 边缘三大板块 |
|
||||
| 可进入室内 | 0-1 个 | 5-6 个(家 + 店铺 + 网吧) |
|
||||
| 店铺 | 仅小卖部 | 小卖部、书店、街机店、网吧、录像出租点 |
|
||||
| 可进入室内 | 0-1 个 | ~12 个(家 + 6 店铺 + 4 小伙伴家 + 网吧) |
|
||||
| 店铺 | 仅小卖部 | 小卖部、书店、粮油店、服装店、鞋店、街机店、网吧、录像出租点、储蓄所 |
|
||||
| 居住形态 | 平房带院子 | 事业单位楼房 + 小区 + 平房区 |
|
||||
|
||||
### 2.3 总体布局
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
## 三、商业主街
|
||||
|
||||
主街约 70m 长、5-6m 宽的水泥路,是整个场景最繁华的区域。以中间为界,**西侧是商业娱乐区**(街机、网吧、录像出租),**东侧是传统生活区**(小卖部、书店、学校)。街边散布着各类摊贩。
|
||||
主街约 70m 长、5-6m 宽的水泥路,是整个场景最繁华的区域。以中间为界,**西侧是商业娱乐区**(街机、网吧、录像出租、储蓄所、棋牌室),**东侧是传统生活区**(小卖部、书店、粮油店、服装店、鞋店、学校)。街边散布着各类摊贩和公交站牌。
|
||||
|
||||
### 3.1 东侧(传统生活)
|
||||
|
||||
@@ -201,7 +201,65 @@
|
||||
|
||||
---
|
||||
|
||||
#### 3.1.3 学校
|
||||
#### 3.1.3 粮油店
|
||||
|
||||
**位置**:主街东部,书店旁边
|
||||
**面积**:小型(~3m × 3m)
|
||||
**可进入**:简化(门口交互为主)
|
||||
|
||||
**外观**:
|
||||
- 窄门面,门口摆着几袋大米和油桶
|
||||
- 招牌手写"粮油"二字,简单直接
|
||||
- 门口有电子秤
|
||||
|
||||
**时代物件**:散装大米、5L 塑料油桶、酱油醋大缸(散装打)、挂面
|
||||
|
||||
**系统关联**:
|
||||
- 氛围营造(城郊生活必需品店铺)
|
||||
- 可能作为零花钱系统的消费点
|
||||
|
||||
---
|
||||
|
||||
#### 3.1.4 服装店/裁缝铺
|
||||
|
||||
**位置**:主街东部,粮油店旁边
|
||||
**面积**:小型(~3m × 3m)
|
||||
**可进入**:简化(门口交互为主)
|
||||
|
||||
**外观**:
|
||||
- 门口挂着几件成衣样品
|
||||
- 招牌写着"XX 服装"或"裁缝"
|
||||
- 老板娘坐在门口
|
||||
|
||||
**时代物件**:成衣、布匹、缝纫机、量衣尺
|
||||
|
||||
**系统关联**:
|
||||
- 氛围营造(裁缝铺是城郊标配)
|
||||
- 简化对话交互
|
||||
|
||||
---
|
||||
|
||||
#### 3.1.5 鞋店
|
||||
|
||||
**位置**:主街东部,服装店旁边
|
||||
**面积**:小型(~3m × 3m)
|
||||
**可进入**:简化(门口交互为主)
|
||||
|
||||
**外观**:
|
||||
- 门口摆着几排鞋(运动鞋为主)
|
||||
- 招牌写着"XX 鞋业"
|
||||
- 墙上挂着运动鞋海报(安踏/李宁风格)
|
||||
|
||||
**时代物件**:运动鞋(安踏/李宁早期款式)、塑料凉鞋、布鞋
|
||||
|
||||
**系统关联**:
|
||||
- 氛围营造(运动鞋是小孩的梦想)
|
||||
- 简化对话交互
|
||||
- 可能与"换装"概念联动
|
||||
|
||||
---
|
||||
|
||||
#### 3.1.6 学校
|
||||
|
||||
**位置**:主街最东端
|
||||
**朝向**:正门面向主街,侧门(小铁门)面向生活区巷子
|
||||
@@ -279,6 +337,7 @@
|
||||
- 经济系统(柜台换币消费)
|
||||
- 小霸王常驻于此(格斗高手)
|
||||
- 西侧的"磁石"——孩子们被声音和灯光吸引过来
|
||||
- **包机房后屋**:门帘隔开的内部空间,提供主机游戏(PS/SS 风格),比街机更沉浸但更贵
|
||||
|
||||
---
|
||||
|
||||
@@ -362,6 +421,58 @@
|
||||
|
||||
---
|
||||
|
||||
#### 3.2.4 储蓄所
|
||||
|
||||
**位置**:主街西部,录像出租点旁边
|
||||
**面积**:小型(~4m × 3m)
|
||||
**可进入**:简化(柜台交互)
|
||||
|
||||
**外观**:
|
||||
- 正式的门面,比周围店铺更"正经"
|
||||
- 招牌写着"XX 储蓄所"或"XX 信用社"
|
||||
- 门上有铁栅栏门(下班后拉上)
|
||||
|
||||
**时代物件**:存折、手写利率牌、算盘、老式点钞机
|
||||
|
||||
**系统关联**:
|
||||
- 零花钱系统(存取零花钱?待定)
|
||||
- 时代氛围(储蓄所是那个年代的金融地标)
|
||||
|
||||
---
|
||||
|
||||
#### 3.2.5 棋牌室
|
||||
|
||||
**位置**:主街西部
|
||||
**面积**:小型
|
||||
**可进入**:❌ 不可进入(大人的场所)
|
||||
|
||||
**外观**:
|
||||
- 半开的门,里面烟雾缭绕
|
||||
- 门口可能坐着抽烟的大人
|
||||
- 招牌写着"棋牌"或"茶室"
|
||||
- 能听到麻将牌碰撞的声音
|
||||
|
||||
**系统关联**:
|
||||
- 纯氛围营造(大人的世界,小孩好奇但不能进)
|
||||
- 声音景观(麻将声作为主街西侧的背景音)
|
||||
|
||||
---
|
||||
|
||||
#### 3.2.6 主街设施
|
||||
|
||||
**公交站牌**:
|
||||
- 主街中段的简易公交站牌(铁杆+铁皮站牌)
|
||||
- 公交车会经过但不可乘坐
|
||||
- 纯装饰,增强城郊出行氛围
|
||||
|
||||
**废品回收点**:
|
||||
- 主街路边固定摊位
|
||||
- 一把秤 + 几个编织袋 + 地上分类的废品
|
||||
- 老板娘坐镇,可交互卖废品
|
||||
- 与流动收废品车互补(固定点方便,流动车价格可能不同)
|
||||
|
||||
---
|
||||
|
||||
### 3.3 街边摊贩
|
||||
|
||||
**分布**:散布在主街各处 + 生活区巷子中
|
||||
@@ -372,6 +483,8 @@
|
||||
|----------|---------|---------|------|
|
||||
| 冰棍推车 | 主街阴凉处、学校门口 | 泡沫箱+棉被保温,绿豆冰/红豆冰/白糖冰棍 | 夏天标配 |
|
||||
| 烤肠机 | 小卖部门口、网吧门口 | 电烤机,1-2 元一根 | 简单经济触点 |
|
||||
| 烤鱿鱼 | 主街散布 | 铁板,酱料 | 城郊特色小吃 |
|
||||
| 烤里脊 | 主街散布 | 铁板串烤 | 城郊特色小吃 |
|
||||
| 糖葫芦 | 随机出现 | 插在草把子上,山楂/草莓/橘子 | 随机事件 |
|
||||
| 爆米花 | 偶尔出现在主街/空地附近 | 老式黑铁葫芦爆米花机,"嘭"一声 | 随机事件,声音记忆 |
|
||||
| 棉花糖 | 偶尔出现在空地/学校附近 | 手摇式棉花糖机 | 随机事件 |
|
||||
@@ -396,15 +509,28 @@
|
||||
|---|----------|------|--------|---------|
|
||||
| 1 | 合并小卖部 | 8m×5m | ✅ | 经济核心、收集入口、街坊聚集 |
|
||||
| 2 | 书店 | 5m×4m | ✅ | 漫画/书籍、叙事触点、时代氛围 |
|
||||
| 3 | 学校(仅操场) | 25m×18m | — | 肢体活动、剧情场景 |
|
||||
| 3 | 粮油店 | ~3m×3m | 简化 | 氛围营造、城郊生活必需品 |
|
||||
| 4 | 服装店/裁缝铺 | ~3m×3m | 简化 | 氛围营造、简化对话 |
|
||||
| 5 | 鞋店 | ~3m×3m | 简化 | 氛围营造、运动鞋梦想 |
|
||||
| 6 | 学校(仅操场) | 25m×18m | — | 肢体活动、剧情场景 |
|
||||
|
||||
**西侧(商业娱乐)**:
|
||||
|
||||
| # | 店铺/设施 | 面积 | 可进入 | 核心功能 |
|
||||
|---|----------|------|--------|---------|
|
||||
| 4 | 街机店 | 8m×6m | ✅ | 街机小游戏、社交核心 |
|
||||
| 5 | 网吧 | 6m×5m | ✅ | PC 小游戏、社交、时代氛围 |
|
||||
| 6 | 录像出租点 | 5m×4m | ✅ | 录像带/磁带、叙事触点、收集 |
|
||||
| 7 | 街机店(含包机房后屋) | 8m×6m | ✅ | 街机小游戏、社交核心、包机房 |
|
||||
| 8 | 网吧 | 6m×5m | ✅ | PC 小游戏、社交、时代氛围 |
|
||||
| 9 | 录像出租点 | 5m×4m | ✅ | 录像带/磁带、叙事触点、收集 |
|
||||
| 10 | 储蓄所 | ~4m×3m | 简化 | 存取零花钱?时代氛围 |
|
||||
| 11 | 棋牌室 | 小型 | ❌ | 纯氛围(大人的场所) |
|
||||
|
||||
**主街设施**:
|
||||
|
||||
| # | 设施 | 性质 |
|
||||
|---|------|------|
|
||||
| 12 | 公交站牌 | 纯装饰 |
|
||||
| 13 | 废品回收点 | 路边固定摊位,可交互卖废品 |
|
||||
| 14 | 街边摊贩 × N | 散布式(烤鱿鱼、烤里脊、冰棍推车、烤肠等) |
|
||||
|
||||
---
|
||||
|
||||
@@ -430,9 +556,15 @@
|
||||
- 楼道:水泥楼梯,声控灯,墙上贴着小广告和水电费通知
|
||||
|
||||
**死党 A 的家**:
|
||||
- 在某栋楼的某层(不可进入,但外观有标识——比如阳台上挂着四驱车赛道模型)
|
||||
- 在某栋楼的某层(简化室内,可进入)
|
||||
- 外观有标识——比如阳台上挂着四驱车赛道模型
|
||||
- 室内简化:小空间 + 对话为主,展示家境好的氛围(大电视、四驱车跑道、电脑)
|
||||
- 从楼下能看到他家阳台上摆着的东西
|
||||
|
||||
**小区设施**:
|
||||
- **自行车棚**:水泥柱 + 石棉瓦顶,停着几辆老式自行车(永久牌/凤凰牌)
|
||||
- 信报箱区(铁皮信报箱,嵌在楼道口墙上)
|
||||
|
||||
**系统关联**:
|
||||
- 四驱车系统(死党 A 在小区空地展示/比拼四驱车)
|
||||
- 社交场所(小区空地是另一个孩子聚集点)
|
||||
@@ -498,6 +630,15 @@
|
||||
- 墙上贴着水电费通知、小广告
|
||||
- 楼道里偶尔碰到邻居(背景 NPC)
|
||||
|
||||
**女班长家**:
|
||||
- 同栋楼不同层(简化室内,可进入)
|
||||
- 室内简化:小空间 + 对话为主
|
||||
- 女孩的房间视角,与主角家形成对照
|
||||
|
||||
**楼下设施**:
|
||||
- **信报箱**:铁皮信报箱嵌在楼道口,可能收到通知/信件
|
||||
- **自行车棚**:楼旁小型车棚(如有独立空间)
|
||||
|
||||
**系统关联**:
|
||||
- FC 家用机小游戏(坐在客厅电视前玩)
|
||||
- 暑假作业叙事线(书桌上的作业)
|
||||
@@ -535,11 +676,16 @@
|
||||
| 修车铺 | 修自行车的,门口散落零件 | 扳手、打气筒、旧轮胎 |
|
||||
| 小吃摊 | 下午出摊,卖凉皮、凉面 | 铁皮推车、调料瓶一字排开 |
|
||||
|
||||
这些小店大多不可进入(仅在门口交互),主要是氛围营造和日常事件触发。
|
||||
这些小店大多简化交互(门口对话为主),主要是氛围营造和日常事件触发。其中早餐店可交互买东西。
|
||||
|
||||
**平房区设施**:
|
||||
- **公共厕所**:平房区内的旱厕,城郊生活的标志性设施
|
||||
- **公共水龙头**:巷子角落
|
||||
|
||||
**死党 B 的家**:
|
||||
- 平房区某一间(外观有标识——门口可能放着弹珠罐子或自制玩具)
|
||||
- 不可进入,但门口有时可以和死党 B 互动
|
||||
- 平房区某一间(简化室内,可进入)
|
||||
- 外观有标识——门口可能放着弹珠罐子或自制玩具
|
||||
- 室内简化:小空间 + 对话为主,展示温馨但简朴的氛围
|
||||
|
||||
**系统关联**:
|
||||
- 对比叙事(小区 vs 平房区的物质差异)
|
||||
@@ -574,11 +720,16 @@
|
||||
|
||||
| # | 区域 | 位置 | 类型 | 核心功能 |
|
||||
|---|------|------|------|---------|
|
||||
| 1 | 小区 | 靠东侧 | 正经住宅(3-4 栋 6 层楼 + 中庭) | 死党 A 的家、四驱车场地、对比叙事 |
|
||||
| 1 | 小区 | 靠东侧 | 正经住宅(3-4 栋 6 层楼 + 中庭) | 死党 A 的家(简化室内)、四驱车场地、对比叙事 |
|
||||
| 2 | 主角家 | 中部 | 事业单位家属楼(独栋 6 层) | 起点/终点、FC 游戏、叙事 |
|
||||
| 3 | 平房区 | 靠西侧 | 自建平房群 + 生活小店 | 死党 B 的家、弹珠场地、对比叙事 |
|
||||
| 2b | 女班长家 | 同主角家楼 | 同栋不同层(简化室内) | 女班长家、社交 |
|
||||
| 3 | 平房区 | 靠西侧 | 自建平房群 + 生活小店 | 死党 B 的家(简化室内)、弹珠场地、对比叙事 |
|
||||
| 4 | 巷子通道 | 贯穿 | 2-3 个巷子口 + 内部连接路 | 穿行、日常事件、氛围 |
|
||||
|
||||
**小区设施**:自行车棚、信报箱
|
||||
**平房区设施**:公共厕所、公共水龙头
|
||||
**平房区小店**:早餐店(可交互)、理发店/修车铺/缝纫店(背景+对话)
|
||||
|
||||
---
|
||||
|
||||
## 五、边缘区域
|
||||
@@ -644,6 +795,24 @@
|
||||
|
||||
---
|
||||
|
||||
### 5.3 秘密基地(隐藏区域)
|
||||
|
||||
**设计理念**:散布在地图各处的小型隐藏空间,每个都有独特的"钻进去"方式。代表童年探索的乐趣——发现只有小孩才知道的秘密角落。
|
||||
|
||||
| # | 名称 | 位置 | 进入方式 | 氛围 |
|
||||
|---|------|------|---------|------|
|
||||
| H1 | 秘密基地 A | 工地蓝色围挡后面 | 围挡底部有个洞,蹲下钻进去 | 废弃建材、涂鸦、偷藏的零食 |
|
||||
| H2 | 秘密基地 B | 平房区深处的死角 | 穿过一条很窄的巷子 | 老式家具、墙角涂鸦、安静 |
|
||||
| H3 | 秘密基地 C | 待定 | 待定 | 待定 |
|
||||
|
||||
**系统关联**:
|
||||
- 探索奖励(发现秘密基地本身就是一个成就)
|
||||
- 收集品散落(秘密基地里有独特收集品)
|
||||
- 叙事触点(秘密基地里发现前人留下的东西、和朋友在这里约定)
|
||||
- 氛围营造("这是我们的秘密"的专属感)
|
||||
|
||||
---
|
||||
|
||||
## 六、乡下场景(奶奶家)
|
||||
|
||||
### 6.1 定位与尺度
|
||||
@@ -785,20 +954,29 @@
|
||||
```
|
||||
┌──────────────────────────────────┐
|
||||
│ 大型空地/工地 河边/河堤 │
|
||||
│ [秘密基地A] │
|
||||
└──────────┬───────────┬───────────┘
|
||||
│ │
|
||||
┌──────────┴───────────┴───────────┐
|
||||
│ 生活区巷子 │
|
||||
│ [平房区] ── [主角家] ── [小区] │
|
||||
│ [平房区] ── [主角家+女班长家] ── [小区] │
|
||||
│ [秘密基地B] │
|
||||
│ [早餐店·理发店·修车铺·缝纫店] │
|
||||
│ [公共厕所·自行车棚·信报箱] │
|
||||
└──┬──────────┬──────────┬─────────┘
|
||||
│巷子口① │巷子口② │巷子口③
|
||||
┌──┴──────────┴──────────┴──────────┐
|
||||
│ 商业主街 │
|
||||
│ │
|
||||
│ 西侧(娱乐) 东侧(生活) │
|
||||
│ [街机店] [小卖部] │
|
||||
│ [网吧] [书店] │
|
||||
│ [录像出租] [学校] │
|
||||
│ [棋牌室] [小卖部] │
|
||||
│ [储蓄所] [粮油店] │
|
||||
│ [录像出租] [书店] │
|
||||
│ [网吧] [服装店] │
|
||||
│ [街机店] [鞋店] │
|
||||
│ [学校] │
|
||||
│ │
|
||||
│ [公交站牌] [废品回收点] [摊贩×N] │
|
||||
└────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -858,7 +1036,7 @@
|
||||
| **女班长** | 学校操场(跳绳/跳皮筋) | 主街、小卖部门口 | 上午活跃 |
|
||||
| **转学生** | 小卖部门口(初来时) | 逐渐扩展到空地、街机店 | 中后期活动范围扩大 |
|
||||
| **残障儿童** | 平房区巷子口(家附近) | 小卖部门口(坐着看大家玩) | 下午出现 |
|
||||
| **小卖部老板儿子** | 合并小卖部 | 街机店(偷溜去玩) | 上午在店里、下午偷溜 |
|
||||
| **小卖部老板儿子** | 合并小卖部(后屋是家) | 街机店(偷溜去玩) | 上午在店里、下午偷溜 |
|
||||
| **小霸王** | 街机店(格斗高手) | 空地(找人挑衅) | 下午到傍晚 |
|
||||
|
||||
### 8.2 设计原则
|
||||
@@ -994,10 +1172,17 @@
|
||||
|------|------|------|
|
||||
| 合并小卖部 | 主街东侧 | 买零食、买文具、买四驱车配件、开卡片 |
|
||||
| 书店 | 主街东侧 | 租借漫画/书籍 |
|
||||
| 街机店 | 主街西侧 | 柜台换币、投币游戏 |
|
||||
| 粮油店 | 主街东侧 | 氛围 + 可能消费 |
|
||||
| 服装店/裁缝铺 | 主街东侧 | 氛围 + 简化对话 |
|
||||
| 鞋店 | 主街东侧 | 氛围 + 简化对话 |
|
||||
| 街机店 | 主街西侧 | 柜台换币、投币游戏、包机房 |
|
||||
| 网吧 | 主街西侧 | 上网收费 |
|
||||
| 录像出租点 | 主街西侧 | 租借录像带/磁带 |
|
||||
| 储蓄所 | 主街西侧 | 存取零花钱?待定 |
|
||||
| 废品回收点 | 主街路边 | 卖废品换钱 |
|
||||
| 早餐店 | 平房区 | 买早点(包子油条豆浆) |
|
||||
| 街边摊贩 | 主街 + 巷子 | 买冰棍、买小吃(比店铺便宜) |
|
||||
| 流动收废品车 | 巷子巡游 | 卖废品换钱(流动价格) |
|
||||
| 村口小卖部 | 乡下 | 乡下唯一消费点 |
|
||||
|
||||
### 10.4 叙事系统 × 场景触发
|
||||
@@ -1086,9 +1271,9 @@
|
||||
| **v0.2** | NPC 放置 + 弹珠场地标识 + NPC 常驻点标识 |
|
||||
| **v0.3** | 时段光影 + 天气初步 + 学校操场 |
|
||||
| **v0.4** | 街机店室内 + 录像出租点室内 + 叙事触发点布设 + 小区外观 |
|
||||
| **v0.5** | 网吧室内 + 书店室内 + 平房区 + 生活小店 + 工地围挡 + 摊贩体系 |
|
||||
| **v0.5** | 网吧室内 + 书店室内 + 粮油店/服装店/鞋店 + 储蓄所 + 平房区 + 生活小店 + 工地围挡 + 摊贩体系 + 废品回收点 |
|
||||
| **v0.6** | **乡下场景全部**(奶奶家、小溪、田间路、村口小卖部) |
|
||||
| **v0.7** | 全场景整合 + 城乡切换 + 细节打磨 |
|
||||
| **v0.7** | 全场景整合 + 城乡切换 + 4 家小伙伴家(简化室内)+ 秘密基地 + 棋牌室 + 公交站牌 + 细节打磨 |
|
||||
| **v1.0** | 氛围精修(声音景观、天气效果、光影优化) |
|
||||
|
||||
---
|
||||
@@ -1100,7 +1285,13 @@
|
||||
- [ ] 乡下阶段的 NPC 具体设计(村里有几个人?什么性格?)
|
||||
- [ ] 天气系统的详细设计(v0.3 前确定范围)
|
||||
- [ ] 室内场景的光照方案(自然光 vs 灯光)
|
||||
- [ ] 平房区生活小店哪些可以进入、哪些仅门口交互
|
||||
- [ ] 网吧的 PC 小游戏内容和家里 FC 的体验差异如何区分
|
||||
- [ ] 街边摊贩的出现逻辑(固定位置+固定时段?还是随机事件?)
|
||||
- [ ] 主街东西两侧是否有视觉上的渐变差异(东侧更传统朴素、西侧更鲜亮热闹?)
|
||||
- [x] ~~平房区生活小店哪些可以进入、哪些仅门口交互~~ → 早餐店可交互,其他简化对话
|
||||
- [x] ~~小伙伴家是否可进入~~ → 4 家可进入(全部简化室内):死党A家、死党B家、老板儿子家(小卖部后屋)、女班长家(主角家同楼)
|
||||
- [x] ~~包机房安排~~ → 合并进街机店后屋
|
||||
- [x] ~~废品回收点~~ → 主街固定摊位 + 流动收废品车
|
||||
- [ ] 秘密基地 C 的具体位置和进入方式
|
||||
- [ ] 储蓄所是否真正参与零花钱系统(还是纯氛围)
|
||||
- [ ] 服装店/鞋店是否有实际交互(买衣服/换装?还是纯氛围)
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
# 头脑风暴:灵感补充 + 城郊建筑与区域规划
|
||||
|
||||
**日期**:2026-06-10
|
||||
**参与**:starmen1265 × 策划 Agent
|
||||
**状态**:✅ 方向确认完毕
|
||||
|
||||
---
|
||||
|
||||
## 讨论一:灵感列表对比与新发现
|
||||
|
||||
用户提供了一份童年记忆灵感列表,对照已有三份头脑风暴记录进行逐一对比。
|
||||
|
||||
### 已有记录(不重复)
|
||||
|
||||
抓虫(乡下抓知了)、跳皮筋、呼啦圈、跳房子、石头剪刀布、警察抓小偷、一二三木头人、天线调台、日立电视、收音机、ADSL拨号上网、排球女将、大哥大、BP机、广播体操、广场舞、废旧报纸卖废品、少年包青天、菜地(迈皋桥地理元素)
|
||||
|
||||
### ⭐ 新发现元素
|
||||
|
||||
#### 乡下乡土活动(奶奶家阶段素材)
|
||||
|
||||
| # | 元素 | 灵感价值 |
|
||||
|---|------|---------|
|
||||
| 1 | 钓鱼(鱼竿,区别于"摸鱼") | ⭐⭐ 乡村独立小游戏潜力 |
|
||||
| 2 | 游泳(夏天河里/水塘) | ⭐⭐ 场景事件+氛围 |
|
||||
| 3 | 挤牛奶 | ⭐ 互动体验 |
|
||||
| 4 | 喂鸡、掏鸡蛋 | ⭐⭐⭐ 高辨识度、互动感强 |
|
||||
| 5 | 菜地浇水 | ⭐ 零花钱/好感度任务 |
|
||||
| 6 | 打水漂 | ⭐⭐ 简单小互动,有物理乐趣 |
|
||||
|
||||
#### 小孩日常小游戏
|
||||
|
||||
| # | 元素 | 灵感价值 |
|
||||
|---|------|---------|
|
||||
| 7 | 双人拍手小游戏(互推游戏) | ⭐⭐ 简单但互动感极强 |
|
||||
| 8 | 钻狗洞的秘密基地 | ⭐⭐⭐ **极佳的探索叙事素材** |
|
||||
| 9 | 猜在哪个手里 | ⭐ 最简单的NPC互动小游戏 |
|
||||
| 10 | 叠纸飞机(不同纸、不同技法) | ⭐⭐⭐ 收集+小游戏双潜力 |
|
||||
| 11 | 跑步比赛 | ⭐ 简单的NPC互动触发 |
|
||||
|
||||
#### 人物与社交
|
||||
|
||||
| # | 元素 | 灵感价值 |
|
||||
|---|------|---------|
|
||||
| 12 | 爷爷奶奶家的各种年龄段亲戚小孩 | ⭐⭐⭐ 乡下NPC角色体系 |
|
||||
| 13 | 北方来南方的同学 | ⭐⭐⭐ 与"转学生"角色互补 |
|
||||
| 14 | 等着去别人家(串门文化) | ⭐⭐ 日常叙事素材 |
|
||||
| 15 | 不知道名字的小哥哥跟你玩了一下午 | ⭐⭐⭐ **极高情感潜力的微型叙事线** |
|
||||
|
||||
#### 食物与零食
|
||||
|
||||
| # | 元素 | 灵感价值 |
|
||||
|---|------|---------|
|
||||
| 16 | 大大泡泡糖 | ⭐⭐ 品牌辨识度极高 |
|
||||
| 17 | 秀逗(超酸的糖) | ⭐⭐ 互动素材——表情反应 |
|
||||
| 18 | 无花果(丝) | ⭐ 零花钱消费场景填充 |
|
||||
| 19 | 老鼠屎(盐津葡萄/话梅粒) | ⭐⭐ 名字本身就是小孩文化缩影 |
|
||||
| 20 | 跳跳糖 | ⭐⭐ 视觉效果潜力 |
|
||||
| 21 | 烤鱿鱼 | ⭐ 街边饮食扩展 |
|
||||
| 22 | 烤里脊 | ⭐ 街边饮食扩展 |
|
||||
| 23 | 炒饭和速冻水饺 | ⭐⭐ 与体力系统直接联动 |
|
||||
|
||||
#### 日常生活与物品
|
||||
|
||||
| # | 元素 | 灵感价值 |
|
||||
|---|------|---------|
|
||||
| 24 | 每天都有吃饭聊天时间 | ⭐⭐ 氛围事件+叙事窗口 |
|
||||
| 25 | 小天鹅(洗衣机品牌) | ⭐ 时代品牌元素 |
|
||||
| 26 | MP3(2000年前后刚开始出现) | ⭐⭐ 时代物品——比随身听更"潮" |
|
||||
| 27 | 装修(邻居家在装修) | ⭐⭐ 场景细节(讨论后决定不做) |
|
||||
| 28 | 墙上涂鸦 | ⭐ 收集/互动素材 |
|
||||
| 29 | 十二生肖 | 待确认具体指什么 |
|
||||
| 30 | 吃遍附近的美食 | ⭐⭐ 探索型目标 |
|
||||
| 31 | 纸壳 | ⭐ 与叠纸飞机联动 |
|
||||
| 32 | 西游记后传(2000年播出) | ⭐⭐ 电视内容补充 |
|
||||
| 33 | 玉河摩托 | 待确认具体指什么 |
|
||||
| 34 | 公交 | ⭐ 场景/移动手段 |
|
||||
|
||||
#### 游戏机制灵感
|
||||
|
||||
**体力系统雏形**:
|
||||
> 吃饭补充体力,饭点之前体力无限。如果不吃饭,体力没跑几步就没了。
|
||||
|
||||
**动态家庭事件链**:
|
||||
> 爸爸妈妈早上会给留两顿炒饭 → 如果都不吃,连续三天,会换成速冻水饺 → 如果还不吃,每天会多给两顿饭钱。
|
||||
|
||||
这两个设计同时做到了:还原真实 × 驱动行为 × 叙事表达。
|
||||
|
||||
#### 重点标记 ⭐⭐⭐
|
||||
|
||||
1. **钻狗洞的秘密基地** — 探索叙事
|
||||
2. **叠纸飞机** — 收集+小游戏
|
||||
3. **爷爷奶奶家的亲戚小孩** — 乡下NPC体系
|
||||
4. **不知道名字的小哥哥** — 情感微型叙事
|
||||
5. **体力系统+家庭动态事件** — 核心玩法机制
|
||||
|
||||
---
|
||||
|
||||
## 讨论二:城郊区域建筑与区域规划
|
||||
|
||||
基于全部已记录的活动/事件,讨论城市主场景应有哪些建筑与区域(不含乡下)。
|
||||
|
||||
### 确认的变更(相比现有场景设计)
|
||||
|
||||
| # | 变更项 | 原设计 | 新决定 |
|
||||
|---|--------|--------|--------|
|
||||
| 1 | 小伙伴家 | 全部不可进入 | 4 家可进入(简化室内) |
|
||||
| 2 | 包机房 | 无 | 合并进街机店后屋 |
|
||||
| 3 | 废品回收 | 无 | 固定点 + 流动收废品车 |
|
||||
| 4 | 公交站 | 无 | 主街公交站牌(纯装饰) |
|
||||
| 5 | 秘密基地 | 无 | 多处散布 |
|
||||
| 6 | 棋牌室 | 无 | 新增 |
|
||||
| 7 | 储蓄所 | 无 | 新增 |
|
||||
| 8 | 菜地 | 无 | 不做(留乡下) |
|
||||
| 9 | 装修 | 无 | 不做 |
|
||||
| 10 | 游泳 | 无 | 河边不能下水 |
|
||||
|
||||
---
|
||||
|
||||
### 完整建筑与区域清单
|
||||
|
||||
#### 一、商业主街(东西走向,~70m x 5-6m)
|
||||
|
||||
**东侧(传统生活)**
|
||||
|
||||
| # | 名称 | 尺寸 | 可进入 | 核心功能 | 备注 |
|
||||
|---|------|------|--------|---------|------|
|
||||
| S1 | 合并小卖部 | 8m x 5m | ✅ | 零食/文具/四驱配件/经济核心 | 后半部分是老板儿子家(简化室内) |
|
||||
| S2 | 书店 | 5m x 4m | ✅ | 漫画/书籍租借 | |
|
||||
| S3 | 粮油店 | 小型 | ✅ | 米面油酱醋 | |
|
||||
| S4 | 服装店/裁缝铺 | 小型 | 简化 | 氛围 + 可能买衣服 | |
|
||||
| S5 | 鞋店 | 小型 | 简化 | 氛围 + 运动鞋梦想 | |
|
||||
|
||||
**西侧(娱乐商业)**
|
||||
|
||||
| # | 名称 | 尺寸 | 可进入 | 核心功能 | 备注 |
|
||||
|---|------|------|--------|---------|------|
|
||||
| S6 | 街机店 | 8m x 6m | ✅ | 街机小游戏 + 社交 | 含包机房后屋(门帘隔着) |
|
||||
| S7 | 网吧 | 6m x 5m | ✅ | PC 小游戏 + 社交 | |
|
||||
| S8 | 录像出租点 | 5m x 4m | ✅ | 录像带/磁带租借 | 只出租,无观影厅 |
|
||||
| S9 | 储蓄所 | 小型 | 简化 | 存取零花钱? | |
|
||||
| S10 | 棋牌室 | 小型 | ❌ | 纯氛围(大人的场所) | |
|
||||
|
||||
**主街设施(散布)**
|
||||
|
||||
| # | 名称 | 性质 |
|
||||
|---|------|------|
|
||||
| S11 | 公交站牌 | 纯装饰,公交经过不可乘坐 |
|
||||
| S12 | 废品回收点 | 路边固定摊位,可交互卖废品 |
|
||||
| S13 | 街边摊贩 × N | 散布式(烤鱿鱼、烤里脊、冰棍推车、烤肠等) |
|
||||
|
||||
**主街尽端**
|
||||
|
||||
| # | 名称 | 尺寸 | 可进入 |
|
||||
|---|------|------|--------|
|
||||
| S14 | 学校操场 | 25m x 18m | 仅室外 |
|
||||
|
||||
#### 二、生活区巷子(主街北侧,南北纵深)
|
||||
|
||||
**中部 — 事业单位家属楼**
|
||||
|
||||
| # | 名称 | 性质 | 备注 |
|
||||
|---|------|------|------|
|
||||
| R1 | 主角家 | 6 层家属楼,完整室内(两室一厅) | 起点终点、FC 游戏、电视、电话 |
|
||||
| R2 | 女班长家 | 同栋楼,简化室内 | 同楼不同层 |
|
||||
| R3 | 信报箱 | 楼下设施 | 氛围 + 可能收信/通知 |
|
||||
|
||||
**东侧 — 小区**
|
||||
|
||||
| # | 名称 | 性质 | 备注 |
|
||||
|---|------|------|------|
|
||||
| R4 | 小区 | 3-4 栋 6 层楼 + 中庭空地 | 死党 A 住这里 |
|
||||
| R5 | 死党 A 家 | 小区内某栋,简化室内 | 家境好,有四驱车跑道 |
|
||||
| R6 | 自行车棚 | 小区内设施 | 氛围 |
|
||||
|
||||
**西侧 — 平房区**
|
||||
|
||||
| # | 名称 | 性质 | 可交互 | 备注 |
|
||||
|---|------|------|--------|------|
|
||||
| R7 | 平房区 | 十几二十间平房 + 窄巷子 | — | 死党 B 住这里 |
|
||||
| R8 | 死党 B 家 | 平房区内某间,简化室内 | ✅ | 家境差,温馨 |
|
||||
| R9 | 早餐店 | 平房区沿街 | ✅ 买早点 | 包子油条豆浆 |
|
||||
| R10 | 理发店 | 平房区小店 | 简化对话 | 老式转椅+镜子 |
|
||||
| R11 | 修车铺 | 平房区小店 | 简化对话 | 门口堆轮胎零件 |
|
||||
| R12 | 缝纫店 | 平房区小店 | 简化对话 | 缝纫机响 |
|
||||
| R13 | 公共厕所 | 平房区内 | ❌ | 城郊生活标志 |
|
||||
|
||||
**巷子通道**
|
||||
|
||||
| # | 名称 | 备注 |
|
||||
|---|------|------|
|
||||
| R14 | 巷子口 × 2-3 | 主街与生活区的连接口 |
|
||||
|
||||
#### 三、边缘区域(北端)
|
||||
|
||||
| # | 名称 | 尺寸 | 备注 |
|
||||
|---|------|------|------|
|
||||
| E1 | 大型空地/工地 | ~40m x 30m | 一半空地(弹珠主战场),一半工地(围挡) |
|
||||
| E2 | 河边/河堤 | ~50m x 8m | 不能下水,氛围+打水漂 |
|
||||
|
||||
#### 四、隐藏区域
|
||||
|
||||
| # | 名称 | 位置 | 进入方式 |
|
||||
|---|------|------|---------|
|
||||
| H1 | 秘密基地 A | 工地围挡后面 | 钻洞 |
|
||||
| H2 | 秘密基地 B | 平房区死角 | 穿窄巷 |
|
||||
| H3 | 秘密基地 C | 待定 | 待定 |
|
||||
|
||||
#### 五、移动元素
|
||||
|
||||
| # | 名称 | 路线 | 功能 |
|
||||
|---|------|------|------|
|
||||
| M1 | 流动收废品车 | 巷子内巡游 | 卖废品 |
|
||||
| M2 | 街边摊贩 | 主街散布 | 零食/小吃 |
|
||||
|
||||
---
|
||||
|
||||
### 主街店铺分布(东西排列)
|
||||
|
||||
```
|
||||
← 东(生活) 西(娱乐)→
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ [学校操场] [小卖部] [粮油店] [书店] [服装店] [鞋店] · 公交站 · [棋牌室] [储蓄所] [录像出租] [网吧] [街机店] │
|
||||
│ ↑ 废品回收点(路边) ↑ 摊贩散布 │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 可进入室内完整清单
|
||||
|
||||
| # | 地点 | 规模 | 关联 NPC |
|
||||
|---|------|------|---------|
|
||||
| 1 | 主角家 | 完整(两室一厅) | — |
|
||||
| 2 | 合并小卖部 | 完整 | 老板儿子 |
|
||||
| 3 | 书店 | 中等 | — |
|
||||
| 4 | 街机店(含包机房后屋) | 中等 | 小霸王 |
|
||||
| 5 | 网吧 | 中等 | — |
|
||||
| 6 | 录像出租点 | 中等 | — |
|
||||
| 7 | 死党 A 家 | 简化(小空间+对话) | 死党 A |
|
||||
| 8 | 死党 B 家 | 简化 | 死党 B |
|
||||
| 9 | 老板儿子家 | 简化(小卖部后屋) | 老板儿子 |
|
||||
| 10 | 女班长家 | 简化(主角家同楼) | 女班长 |
|
||||
|
||||
---
|
||||
|
||||
### 讨论共识记录
|
||||
|
||||
1. **菜地**:城市场景不做,留给乡下阶段
|
||||
2. **秘密基地**:多处散布,小型空间(工地围挡后、平房区死角、至少 2-3 处)
|
||||
3. **小伙伴家**:4 家可进入,全部简化室内(小空间 + 对话为主)
|
||||
- 死党 A 家 → 小区内
|
||||
- 死党 B 家 → 平房区内
|
||||
- 老板儿子家 → 小卖部后屋
|
||||
- 女班长家 → 主角家同楼不同层
|
||||
4. **录像厅**:只做出租点,不做观影厅
|
||||
5. **包机房**:合并进街机店后屋
|
||||
6. **废品回收**:主街固定摊位 + 流动收废品车(巷子巡游)
|
||||
7. **装修**:不做
|
||||
8. **公交站**:纯装饰站牌
|
||||
9. **摊贩**:散布式
|
||||
10. **游泳**:河边不能下水
|
||||
11. **新增店铺**:粮油店、服装店/裁缝铺、鞋店 → 都放主街
|
||||
12. **新增设施**:棋牌室(大人场所/纯氛围)、储蓄所、公共厕所、自行车棚、信报箱
|
||||
13. **平房区小店**:早餐店(可交互)、理发店/修车铺/缝纫店(背景+对话)
|
||||
|
||||
---
|
||||
|
||||
### 统计
|
||||
|
||||
| 类别 | 数量 |
|
||||
|------|------|
|
||||
| 商业主街店铺/设施 | 14 个 |
|
||||
| 生活区建筑/设施 | 14 个 |
|
||||
| 边缘区域 | 2 个 |
|
||||
| 隐藏区域 | 多处 |
|
||||
| 移动元素 | 2 类 |
|
||||
| **可进入室内** | ~12 个 |
|
||||
|
||||
### 与概念草案的关系
|
||||
|
||||
概念草案定义「可进入室内:主角家 + 4 家店铺」。新设计变更为 6 家店铺 + 4 家小伙伴家(简化)+ 主角家 = ~12 个可进入室内。这是扩展,不与概念草案冲突。概念草案冻结,变更记录在系统设计案中。
|
||||
+767
-784
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
# 交互系统 · 拾取流程时序图(v1.0 Effect 驱动版)
|
||||
|
||||
## 场景
|
||||
|
||||
玩家进入地上某个交互物的交互范围,按 E 交互后,人物做动作,交互物消失,背包加一个新物品,UI 显示捡到一个物品。
|
||||
|
||||
## 架构层级
|
||||
|
||||
| 层级 | 实体 | 所在位置 |
|
||||
|------|------|---------|
|
||||
| **Logic** | `FInteractionManager` | ASystemDriver 持有 (普通C++, 纯事件驱动, 缓存 Presentation 数据) |
|
||||
| **Logic** | `FEffectManager` | ASystemDriver 持有 (普通C++, Driver 提供Tick) |
|
||||
| **World** | `ASystemDriver` | AInfo 全局唯一 (持有所有Manager, 显式控制创建/Tick顺序) |
|
||||
| **Data** | `UInteractableComponent` | 关卡实例 |
|
||||
| **Data** | `UPersistenceSubsystem` | GameInstanceSubsystem |
|
||||
| **Data** | `BackpackSystem` | GameInstance |
|
||||
| **Presentation** | `UInteractionPromptComponent` | Character |
|
||||
|
||||
## 数据流规则
|
||||
|
||||
- 表现层直接读数据层(Manager state / Component data / Backpack data)
|
||||
- 逻辑事件仅在 A 影响 B 时使用(如 Consume Action → Persistence 写入)
|
||||
- 两个表现实体之间不直接访问
|
||||
|
||||
---
|
||||
|
||||
## Effect 配置
|
||||
|
||||
```
|
||||
Effect: "拾取地面物品"
|
||||
TotalDuration: 1.5s, Cancellable: false
|
||||
|
||||
TriggerTime | Action | 说明
|
||||
----------- | --------------------- | ----
|
||||
0.0s | TurnToTarget | TurnDuration=0.2,转向交互物
|
||||
0.0s | PlayMontage | Montage=AM_Pickup,弯腰拾取动画
|
||||
0.6s | Consume | 标记消耗,禁用检测球
|
||||
0.6s | HideActor | 隐藏交互物 Actor
|
||||
0.6s | AddToBackpack | 物品进背包 + 持久化
|
||||
1.0s | ShowPickupNotification| 显示 "捡到了 [旧橡皮]!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 时序图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
|
||||
actor Player as 玩家
|
||||
participant Char as AChildHoodCharacter
|
||||
participant Mgr as FInteractionManager<br/>(普通C++ · ASystemDriver持有)
|
||||
participant Comp as UInteractableComponent<br/>(Data · 关卡实例)
|
||||
participant Actor as AInteractableActor
|
||||
participant EFM as FEffectManager<br/>(普通C++ · ASystemDriver持有)
|
||||
participant Persist as UPersistenceSubsystem<br/>(Data · GameInstance)
|
||||
participant Bag as BackpackSystem
|
||||
participant Pres as UInteractionPromptComponent<br/>(Presentation · Character)
|
||||
participant Driver as ASystemDriver<br/>(AInfo · 持有所有Manager)
|
||||
|
||||
rect rgb(230, 245, 255)
|
||||
Note over Player,Driver: ═══ Phase 0 · 进入检测范围 ═══
|
||||
Player->>Char: WASD 移动进入 TriggerRadius
|
||||
Comp->>Mgr: DetectionSphere OnOverlapBegin<br/>ASystemDriver::Get(World)->GetInteractionManager().RegisterInteractable(this)
|
||||
Mgr->>Mgr: NearbyInteractables.Add(Comp)<br/>Sort by Dist2D → SelectedIndex = 0
|
||||
Mgr->>Mgr: RefreshCachedSelection()<br/>缓存 PromptText + WorldPosition
|
||||
end
|
||||
|
||||
rect rgb(255, 250, 230)
|
||||
Note over Player,Driver: ═══ Phase 1 · Prompt 显示(Pres 每帧读 Manager 缓存)═══
|
||||
loop 每帧 Pres TickComponent
|
||||
Pres->>Mgr: GetState() → Free
|
||||
Pres->>Mgr: HasSelection() → true
|
||||
Pres->>Mgr: GetSelectedPromptText() → "[E] 拾取 旧橡皮"
|
||||
Pres->>Mgr: GetSelectedWorldPosition() → FVector
|
||||
Pres->>Pres: PromptWidget.SetText + SetScreenPosition
|
||||
end
|
||||
Note right of Pres: Pres 不碰 Component<br/>只读 Manager 缓存
|
||||
end
|
||||
|
||||
rect rgb(230, 255, 230)
|
||||
Note over Player,Driver: ═══ Phase 2 · 按 E,Character 通过 Driver 协调两个 Manager ═══
|
||||
Player->>Char: 按 E (IA_Interact)
|
||||
Char->>Mgr: Driver->GetInteractionManager().BeginInteract() → 返回 Comp
|
||||
Mgr->>Mgr: State = Executing, CurrentInteractable = Comp
|
||||
Char->>Char: SetInteracting(true) → 屏蔽移动
|
||||
|
||||
Char->>EFM: Driver->GetEffectManager().PlayEffect(Comp.Data.InteractEffect, Context)<br/>Context = {Char, Comp, Actor}
|
||||
Note right of EFM: Effect "拾取地面物品"<br/>T=0.0 TurnToTarget + PlayMontage<br/>T=0.6 Consume+Hide+Backpack<br/>T=1.0 PickupNotification<br/>Total=1.5s
|
||||
end
|
||||
|
||||
rect rgb(255, 240, 245)
|
||||
Note over Player,Driver: ═══ Phase 3 · Presentation 检测状态变化 ═══
|
||||
Pres->>Mgr: Tick: GetState() → Executing (变化!)
|
||||
Pres->>Pres: PromptWidget.Hide()
|
||||
end
|
||||
|
||||
rect rgb(240, 240, 255)
|
||||
Note over Player,Driver: ═══ Phase 4 · Effect 执行(ASystemDriver Tick → EffectManager)═══
|
||||
|
||||
Note over Driver: T=0.0: TurnToTarget + PlayMontage
|
||||
Driver->>EFM: Driver::Tick → EffectManager.Update(DeltaTime)
|
||||
EFM->>EFM: ElapsedTime=0.0 → 触发 TurnToTarget Action
|
||||
EFM->>Char: RInterpTo 转向 Comp(持续帧)
|
||||
EFM->>EFM: 触发 PlayMontage Action
|
||||
EFM->>Char: GetMesh()->GetAnimInstance()->Montage_Play(AM_Pickup)
|
||||
Note right of Char: 播放弯腰拾取动画
|
||||
|
||||
Note over Driver: T=0.0→0.6: 持续转向 + 动画播放
|
||||
loop 每帧 Driver Tick
|
||||
Driver->>EFM: Tick → Update(DeltaTime)
|
||||
EFM->>EFM: ElapsedTime += DeltaTime
|
||||
EFM->>Char: TurnToTarget: RInterpTo 插值
|
||||
end
|
||||
|
||||
Note over Driver: T=0.6: Consume + HideActor + AddToBackpack
|
||||
Driver->>EFM: Tick → Update → ElapsedTime=0.6 触发
|
||||
EFM->>Comp: Consume() — 数据变更
|
||||
Comp-->>Comp: bIsConsumed=true<br/>DetectionSphere → NoCollision
|
||||
Note right of Comp: 禁用碰撞同步触发 EndOverlap<br/>→ UnregisterInteractable<br/>Manager 标记延迟清理
|
||||
|
||||
EFM->>Persist: MarkItemCollected("rubber_01")
|
||||
Persist-->>Persist: CollectedItemIDs.Add("rubber_01")
|
||||
|
||||
EFM->>Actor: SetActorHiddenInGame(true)
|
||||
|
||||
EFM->>Bag: AddItem("rubber_01", "旧橡皮")
|
||||
Bag-->>Bag: Items.Add({Id:"rubber_01", Name:"旧橡皮"})
|
||||
|
||||
Pres->>Comp: Tick: IsConsumed() → true (变化!)
|
||||
Pres->>Actor: SetActorHiddenInGame(true)
|
||||
|
||||
Note over Driver: T=1.0: ShowPickupNotification
|
||||
Driver->>EFM: Tick → Update → ElapsedTime=1.0 触发
|
||||
EFM->>Pres: 显示拾取通知 "捡到了 [旧橡皮]!"
|
||||
end
|
||||
|
||||
rect rgb(230, 255, 255)
|
||||
Note over Player,Driver: ═══ Phase 5 · Effect 完成,回到 Free ═══
|
||||
Driver->>EFM: Tick → Update → ElapsedTime >= TotalDuration(1.5s)
|
||||
EFM->>EFM: FinishEffect()
|
||||
EFM->>Mgr: OnEffectComplete 回调
|
||||
Mgr->>Mgr: State = Free, CurrentInteractable = nullptr
|
||||
Mgr->>Char: SetInteracting(false) → 恢复移动
|
||||
|
||||
Pres->>Mgr: Tick: GetState() → Free (变化!)
|
||||
Pres->>Mgr: GetSelectedInteractable() → null (已注销)
|
||||
Note over Pres: 无其他交互物在范围,不显示 Prompt
|
||||
|
||||
Player->>Char: WASD 继续移动
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键数据流说明
|
||||
|
||||
### 表现层读数据(只读 Manager 缓存,不碰 Component)
|
||||
|
||||
| 读取时机 | PromptComponent 读谁 | 读什么 |
|
||||
|----------|---------------------|--------|
|
||||
| 每帧 Tick | Manager | `GetState()` |
|
||||
| Free 状态 | Manager | `HasSelection()` |
|
||||
| Free 状态 | Manager | `GetSelectedPromptText()` |
|
||||
| Free 状态 | Manager | `GetSelectedWorldPosition()` |
|
||||
|
||||
### Manager 缓存更新(选择变化时从 Component 读一次)
|
||||
|
||||
| 触发时机 | Manager 方法 | 缓存内容 |
|
||||
|----------|-------------|---------|
|
||||
| RegisterInteractable | RefreshCachedSelection() | PromptText + WorldPosition |
|
||||
| UnregisterInteractable | RefreshCachedSelection() | PromptText + WorldPosition |
|
||||
| SwitchTarget | RefreshCachedSelection() | PromptText + WorldPosition |
|
||||
|
||||
### Effect 内 Action 执行(直接操作)
|
||||
|
||||
| Action | 操作对象 | 说明 |
|
||||
|--------|---------|------|
|
||||
| TurnToTarget | Char->SetActorRotation | RInterpTo 跨帧插值 |
|
||||
| PlayMontage | Char->GetMesh()->GetAnimInstance() | 播放蒙太奇 |
|
||||
| Consume | Component->Consume() | 标记消耗+禁用检测 |
|
||||
| HideActor | Actor->SetActorHiddenInGame(true) | 隐藏 |
|
||||
| AddToBackpack | PersistenceSubsystem + BackpackSystem | 写入持久层+背包 |
|
||||
| ShowPickupNotification | PromptComponent / Widget | 显示通知 |
|
||||
|
||||
### 逻辑事件(仅 A 影响 B)
|
||||
|
||||
| 事件 | 触发者 | 订阅者 |
|
||||
|------|--------|--------|
|
||||
| OnItemConsumed | Manager(由 Consume Action 触发) | PersistenceSubsystem |
|
||||
| OnDoorToggled | Manager(由 ToggleDoor Action 触发) | PersistenceSubsystem + DoorComponent |
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
### EndOverlap 时序问题
|
||||
|
||||
Phase 4 中 `Consume()` 禁用 DetectionSphere 会**同步触发** `EndOverlap`,进而调用 `Manager->UnregisterInteractable()`。此时 Manager 处于 Executing 状态且 Effect 仍在使用 CurrentInteractable。
|
||||
|
||||
**解决方案**:Manager 的 `UnregisterInteractable` 中,当 `State == Executing` 且移除的正是 `CurrentInteractable` 时,仅从 NearbyInteractables 列表移除,**不清除 CurrentInteractable 引用**,等 Effect 完成回调中统一清理。
|
||||
|
||||
### ASystemDriver 生命周期
|
||||
|
||||
- `ASystemDriver` 是 AInfo 全局唯一,持有所有 World 级 Manager(普通 C++ 对象)
|
||||
- 关卡加载完成 → `GameInstance` Spawn `ASystemDriver`
|
||||
- `Driver::BeginPlay` 显式创建 `FInteractionManager` + `FEffectManager`,控制顺序
|
||||
- `Driver::BeginPlay` 中用 `TFunction` 连线 `EffectManager.OnEffectComplete → Manager.OnInteractionFinished`
|
||||
- `Driver::Tick` 显式调用 `EffectManager.Update(Delta)`,控制 Tick 顺序
|
||||
- 关卡卸载 → World 销毁 → Driver 自动销毁 → Manager 随 Driver 析构
|
||||
- 新关卡加载 → 重新 Spawn + 创建
|
||||
|
||||
### 系统协调关系
|
||||
|
||||
- `FInteractionManager` 和 `FEffectManager` 是普通 C++ 类,由 `ASystemDriver` 持有
|
||||
- `AChildHoodCharacter` 输入回调通过 `ASystemDriver::Get(World)` 访问两个 Manager
|
||||
- `Driver::BeginPlay` 中通过 `TFunction<void()>` 连接 EffectManager 完成回调到 Manager
|
||||
- `FInteractionManager` 纯事件驱动,无 Tick/Update
|
||||
- `UChildHoodGameInstance` 不持有任何交互系统对象,仅 `UPersistenceSubsystem` 跨 World 存活
|
||||
|
||||
### TurnToTarget 跨帧插值
|
||||
|
||||
TurnToTarget Action 不是瞬时完成的。EffectManager 在 Update 中维护 `FTurnState`(起始旋转、目标旋转、已用时间),每帧调用 `FMath::RInterpTo` 直到转向完成。多个 Action 可以并行执行。
|
||||
+162
-17
@@ -2,8 +2,8 @@
|
||||
|
||||
> 任务ID: P-009
|
||||
> 对应执行案: `docs/design/收集系统-执行案.md` (v0.1.1)
|
||||
> 关联系统: 物品系统(上游单向接收)、交互系统(间接,通过物品系统委托)
|
||||
> 日期: 2026-06-07
|
||||
> 关联系统: 物品系统(上游单向接收)、交互系统(间接,通过物品系统委托)、GameInstance 持久化层
|
||||
> 日期: 2026-06-07(2026-06-11 更新:加入多场景持久化架构)
|
||||
|
||||
---
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
**预估工期**:2-3 天
|
||||
**新增/修改代码量**:约 250-350 行 C++ + 3 个 UMG 蓝图
|
||||
|
||||
### 跨场景持久化架构
|
||||
|
||||
> 收集进度是玩家核心持久数据。当前设计中 `UCollectionManager` 将「行为控制」(UI、通知、动画)和「持久数据」(CollectedIDs、Progress)混在同一组件,随 Character 销毁而丢失。需要通过数据层分离解决:
|
||||
|
||||
- **持久数据层**:收集状态(CollectedIDs、Progress、bIsComplete)存储在 `UChildHoodGameInstance` 中(跨关卡存活)
|
||||
- **行为层**:`UCollectionManager` 仅负责运行时 UI 控制和委托监听,BeginPlay 时从 GameInstance 恢复状态
|
||||
- **交互物恢复**:场景中的已收集物品由交互系统通过 `InteractableComponent::RestorePersistentState()` 处理(见交互系统技术方案第 12 节)
|
||||
|
||||
v0.1 为单场景原型,此架构以接口预留形式存在,不影响当前功能。详见 [第 12 节:跨场景持久化设计](#12-跨场景持久化设计)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 需求功能点罗列
|
||||
@@ -123,6 +133,17 @@ classDiagram
|
||||
-CheckCompletion() void
|
||||
-ShowCompletionPrompt() void
|
||||
-UpdateProgressUI() void
|
||||
-LoadStateFromGameInstance() void
|
||||
-SaveStateToGameInstance() void
|
||||
}
|
||||
|
||||
class UChildHoodGameInstance {
|
||||
-TSet~FName~ CollectedItemIDs
|
||||
-int32 CollectionProgress
|
||||
-bool bCollectionComplete
|
||||
+GetCollectionState(TSet_FName_&, int32&, bool&) void
|
||||
+SetCollectionState(TSet_FName_&, int32, bool) void
|
||||
+ResetAll() void
|
||||
}
|
||||
|
||||
class UCollectionNotifWidget {
|
||||
@@ -175,6 +196,7 @@ classDiagram
|
||||
|
||||
AChildHoodCharacter *-- UCollectionManager : 组合
|
||||
UCollectionManager --> UInteractionManager : 关联(绑定委托)
|
||||
UCollectionManager ..> UChildHoodGameInstance : 读取/写入持久状态
|
||||
UCollectionManager o-- UCollectionNotifWidget : 聚合(管理生命周期)
|
||||
UCollectionManager o-- UCollectionProgressWidget : 聚合(管理生命周期)
|
||||
UCollectionManager ..> UCollectionCompleteWidget : 按需创建
|
||||
@@ -188,7 +210,7 @@ classDiagram
|
||||
| 组合 `*--` | 生命周期绑定 | Character 持有 CollectionManager;CollectionManager 内含 Config |
|
||||
| 聚合 `o--` | 引用但非拥有 | CollectionManager 管理通知/进度 Widget 的创建和销毁 |
|
||||
| 关联 `-->` | 持久引用 | CollectionManager 绑定 InteractionManager 的委托 |
|
||||
| 依赖 `..>` | 临时使用 | CollectionManager 按需创建完成提示 Widget |
|
||||
| 依赖 `..>` | 临时使用 | CollectionManager 从 GameInstance 读取/写入持久状态;按需创建完成提示 Widget |
|
||||
|
||||
### 新增类
|
||||
|
||||
@@ -489,6 +511,8 @@ void UCollectionManager::ProcessNewCollection(FName ItemId)
|
||||
// 步骤 3: 记录
|
||||
CollectedIDs.Add(ItemId);
|
||||
Progress = CollectedIDs.Num(); // 用 Set 大小作为权威进度值,避免状态不一致
|
||||
// 持久化到 GameInstance
|
||||
SaveStateToGameInstance();
|
||||
```
|
||||
|
||||
---
|
||||
@@ -519,6 +543,7 @@ void UCollectionManager::ProcessNewCollection(FName ItemId)
|
||||
if (Progress >= Config.TotalCount && !bIsComplete)
|
||||
{
|
||||
bIsComplete = true;
|
||||
SaveStateToGameInstance(); // 持久化完成状态
|
||||
CheckCompletion(); // 触发完成表现
|
||||
}
|
||||
}
|
||||
@@ -637,10 +662,8 @@ void UCollectionManager::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// 初始化状态
|
||||
Progress = 0;
|
||||
CollectedIDs.Empty();
|
||||
bIsComplete = false;
|
||||
// 从 GameInstance 恢复持久状态(v0.1 单场景等效于空数据初始化)
|
||||
LoadStateFromGameInstance();
|
||||
|
||||
// 创建进度 UI
|
||||
if (ProgressWidgetClass)
|
||||
@@ -652,7 +675,12 @@ void UCollectionManager::BeginPlay()
|
||||
if (ProgressWidget)
|
||||
{
|
||||
ProgressWidget->AddToViewport(5);
|
||||
ProgressWidget->UpdateProgress(0, Config.TotalCount);
|
||||
ProgressWidget->UpdateProgress(Progress, Config.TotalCount);
|
||||
// 已完成时恢复完成样式
|
||||
if (bIsComplete)
|
||||
{
|
||||
ProgressWidget->SetCompleteStyle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -772,20 +800,34 @@ void UCollectionManager::ShowCompletionPrompt()
|
||||
|
||||
#### 重启状态处理
|
||||
|
||||
**实现**:v0.1 无持久化。CollectionManager::BeginPlay() 中完全重置:
|
||||
**实现**:收集状态通过 `UChildHoodGameInstance` 跨场景持久化。CollectionManager::BeginPlay() 中从 GameInstance 恢复:
|
||||
|
||||
```cpp
|
||||
void UCollectionManager::BeginPlay()
|
||||
void UCollectionManager::LoadStateFromGameInstance()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
Progress = 0;
|
||||
CollectedIDs.Empty();
|
||||
bIsComplete = false;
|
||||
// ... 创建 UI、绑定委托
|
||||
if (UChildHoodGameInstance* GI = GetWorld()->GetGameInstance<UChildHoodGameInstance>())
|
||||
{
|
||||
GI->GetCollectionState(CollectedIDs, Progress, bIsComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 回退:无 GameInstance 时初始化为空(编辑器预览等场景)
|
||||
Progress = 0;
|
||||
CollectedIDs.Empty();
|
||||
bIsComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
void UCollectionManager::SaveStateToGameInstance()
|
||||
{
|
||||
if (UChildHoodGameInstance* GI = GetWorld()->GetGameInstance<UChildHoodGameInstance>())
|
||||
{
|
||||
GI->SetCollectionState(CollectedIDs, Progress, bIsComplete);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
重启后进度 UI 恢复显示 `📦 杂物 0/10`。
|
||||
v0.1 单场景下:GameInstance 以空数据初始化,等效于 `📦 杂物 0/10`。场景内正常收集后状态写入 GameInstance,若通过 Seamless Travel 切换关卡则自动恢复。非无缝跳转(OpenLevel)时 GameInstance 仍存活,新场景的 CollectionManager 可读取之前的数据。
|
||||
|
||||
#### 收集通知与拾取通知时序
|
||||
|
||||
@@ -819,6 +861,7 @@ void UCollectionManager::BeginPlay()
|
||||
### 注意事项
|
||||
|
||||
1. **委托绑定时机**:CollectionManager 在 BeginPlay() 中通过 `GetOwner()->GetComponentByClass<UInteractionManager>()` 获取引用并绑定。需确保 InteractionManager 已初始化。若为 nullptr 则在 Tick 中延迟绑定(最多重试 N 帧后报错)。
|
||||
2. **持久化读写时机**:`SaveStateToGameInstance()` 在每次 ProcessNewCollection 记录后和完成判定后调用,保证 GameInstance 中的数据始终最新。`LoadStateFromGameInstance()` 仅在 BeginPlay 中调用一次。
|
||||
2. **v0.1 无拾取通知 UI**:执行文档中拾取通知由物品系统负责,但 v0.1 物品系统仅为委托层(InteractionManager 上的委托)。收集通知的 0.3s 延迟仍按设计实现(为拾取通知预留时间窗口),即使拾取通知 UI 暂未实现。
|
||||
3. **通知移除回调**:UCollectionNotifWidget 淡出完成后需通知 CollectionManager 从 ActiveNotifications 中移除自身引用。使用委托或弱引用回调实现,避免循环引用。
|
||||
4. **FName 作为 ID**:收集系统使用 FName(ItemId)作为去重键,与 InteractionManager 委托广播的 ItemId 类型一致。
|
||||
@@ -847,14 +890,33 @@ InteractionManager (ExecuteAnimEvent)
|
||||
├─ 查品类 (Category == TrackedCategory?) → 不匹配则忽略
|
||||
├─ 查重复 (CollectedIDs.Contains?) → 已存在则忽略
|
||||
├─ 记录 (CollectedIDs.Add + Progress = Num())
|
||||
├─ SaveStateToGameInstance() → UChildHoodGameInstance (持久化)
|
||||
├─ UpdateProgressUI() → WBP_CollectionProgress (文本 + 弹性动画)
|
||||
├─ SetTimer(NotifDelay) → ShowCollectionNotification() → WBP_CollectionNotification
|
||||
└─ 完成判定 (Progress >= TotalCount)
|
||||
→ bIsComplete = true
|
||||
→ SaveStateToGameInstance() (持久化完成状态)
|
||||
→ SetCompleteStyle() → WBP_CollectionProgress (金色)
|
||||
→ SetTimer(TotalDelay) → ShowCompletionPrompt() → WBP_CollectionComplete
|
||||
```
|
||||
|
||||
### 跨场景恢复流
|
||||
|
||||
```
|
||||
场景切换 (OpenLevel / Seamless Travel)
|
||||
→ 新场景加载
|
||||
→ AChildHoodCharacter::BeginPlay()
|
||||
→ UCollectionManager::BeginPlay()
|
||||
→ LoadStateFromGameInstance()
|
||||
→ UChildHoodGameInstance::GetCollectionState(OutIDs, OutProgress, OutComplete)
|
||||
→ 恢复 CollectedIDs / Progress / bIsComplete
|
||||
→ 创建进度 UI(显示已恢复的进度值)
|
||||
→ 若 bIsComplete → 恢复完成样式
|
||||
→ 场景中 AInteractableActor::BeginPlay()
|
||||
→ UInteractableComponent::RestorePersistentState(GI)
|
||||
→ GI->IsItemCollected(ItemId) → 已收集则隐藏 + 禁用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 可调参数汇总
|
||||
@@ -886,10 +948,11 @@ InteractionManager (ExecuteAnimEvent)
|
||||
Source/ChildHood/
|
||||
├── Collection/
|
||||
│ ├── CollectionTypes.h # FCollectionConfig 结构体定义
|
||||
│ ├── CollectionManager.h/.cpp # 收集系统核心组件
|
||||
│ ├── CollectionManager.h/.cpp # 收集系统核心组件(含 GameInstance 读写)
|
||||
│ ├── CollectionNotifWidget.h/.cpp # 收集通知 UI 基类
|
||||
│ ├── CollectionProgressWidget.h/.cpp # 收集进度 UI 基类
|
||||
│ └── CollectionCompleteWidget.h/.cpp # 完成提示 UI 基类
|
||||
├── ChildHoodGameInstance.h/.cpp # 新增:跨关卡持久数据持有者(收集状态在此持久化)
|
||||
├── ChildHoodCharacter.h/.cpp # 修改:添加 CollectionManager 成员和访问器
|
||||
|
||||
Content/
|
||||
@@ -928,3 +991,85 @@ Content/
|
||||
|
||||
> **关键路径**:6b-1 → 6b-2 → 6b-4 → 6b-5 → 6b-6。6b-3(进度 UI)可在 6b-1 完成后并行。总关键路径约 3 天。
|
||||
> **前置依赖**:交互系统的 InteractionManager 组件需已完成(特别是 OnItemPickedUp/OnItemFound 委托),方可进行 6b-2 的委托绑定测试。
|
||||
|
||||
---
|
||||
|
||||
## 12. 跨场景持久化设计
|
||||
|
||||
> 收集进度是玩家的核心持久数据,必须在场景切换时保留。本节定义收集系统如何通过 `UChildHoodGameInstance` 实现跨场景数据持久化。
|
||||
|
||||
### 架构原则
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ UChildHoodGameInstance │ ← 跨关卡存活
|
||||
│ ├── CollectedItemIDs: TSet<FName> │ 所有场景共享
|
||||
│ ├── CollectionProgress: int32 │
|
||||
│ └── bCollectionComplete: bool │
|
||||
└──────────────────────────────────────────────────┘
|
||||
↕ BeginPlay 加载 / 收集时回写
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ UCollectionManager (每个场景重建) │ ← 行为层
|
||||
│ ├── 从 GameInstance 读取恢复进度 │ 不持有持久数据所有权
|
||||
│ ├── 收集时写入 GameInstance │
|
||||
│ └── 控制 UI / 通知 / 动画 │
|
||||
└──────────────────────────────────────────────────┘
|
||||
↕ 场景恢复
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ 场景中的 AInteractableActor │ ← 由交互系统负责恢复
|
||||
│ └── RestorePersistentState() │ (见交互系统技术方案第 12 节)
|
||||
└──────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### UChildHoodGameInstance 收集相关接口
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class UChildHoodGameInstance : public UGameInstance
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// === 收集状态 ===
|
||||
void GetCollectionState(TSet<FName>& OutIDs, int32& OutProgress, bool& OutComplete) const;
|
||||
void SetCollectionState(const TSet<FName>& IDs, int32 Progress, bool bComplete);
|
||||
|
||||
// === 物品消耗状态(交互系统也使用)===
|
||||
bool IsItemCollected(FName ItemId) const;
|
||||
void MarkItemCollected(FName ItemId);
|
||||
|
||||
// === 门状态(交互系统也使用)===
|
||||
bool IsDoorOpen(FName DoorId) const;
|
||||
void SetDoorOpen(FName DoorId, bool bIsOpen);
|
||||
|
||||
// === 重置 ===
|
||||
void ResetAll();
|
||||
|
||||
private:
|
||||
// 收集系统
|
||||
TSet<FName> CollectedItemIDs;
|
||||
int32 CollectionProgress = 0;
|
||||
bool bCollectionComplete = false;
|
||||
// 交互系统
|
||||
TMap<FName, bool> DoorStates;
|
||||
};
|
||||
```
|
||||
|
||||
> **注意**:`CollectedItemIDs` 同时被 `IsItemCollected()`(交互物恢复)和 `GetCollectionState()`(收集进度恢复)使用,确保两系统数据一致性。
|
||||
|
||||
### 读写时机
|
||||
|
||||
| 时机 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| CollectionManager::BeginPlay | `LoadStateFromGameInstance()` | 场景加载时恢复进度 |
|
||||
| ProcessNewCollection 记录后 | `SaveStateToGameInstance()` | 每次新收集时同步写入 |
|
||||
| 完成判定后 | `SaveStateToGameInstance()` | 完成状态立即持久化 |
|
||||
| InteractableComponent::Consume | `GI->MarkItemCollected()` | 交互物消耗状态写入(由交互系统调用) |
|
||||
|
||||
### v0.1 行为
|
||||
|
||||
- v0.1 为单场景原型,不存在跨场景切换
|
||||
- `UChildHoodGameInstance` 在 v0.1 中以空数据初始化,所有查询返回默认值
|
||||
- `LoadStateFromGameInstance()` 等效于初始化为 0
|
||||
- 后续多场景版本只需在 Project Settings 中将 GameInstance Class 设为 `UChildHoodGameInstance`,收集系统代码无需修改
|
||||
- 后续版本可通过 USaveGame 将 GameInstance 数据序列化到磁盘,实现跨会话持久化
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"subfolder": "AutomaticDoor",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/AutomaticDoor",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 6,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_AutoDoor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_AutoDoorDouble",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_AutoLateralDoor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_AutoLateralDoorDouble",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_BaseAutoDoor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DoorParts_Struct",
|
||||
"ue_class_type": "UserDefinedStruct",
|
||||
"note": [
|
||||
"非 Actor 类型: UserDefinedStruct"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"subfolder": "AutomaticDoor/Curves",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/AutomaticDoor/Curves",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 4,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "Curve_DoorBreakOpen",
|
||||
"ue_class_type": "CurveFloat",
|
||||
"note": [
|
||||
"非 Actor 类型: CurveFloat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Curve_DoorClose",
|
||||
"ue_class_type": "CurveFloat",
|
||||
"note": [
|
||||
"非 Actor 类型: CurveFloat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Curve_DoorOpen",
|
||||
"ue_class_type": "CurveFloat",
|
||||
"note": [
|
||||
"非 Actor 类型: CurveFloat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Curve_DoorRapidClose",
|
||||
"ue_class_type": "CurveFloat",
|
||||
"note": [
|
||||
"非 Actor 类型: CurveFloat"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"subfolder": "AutomaticDoor/Sounds",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/AutomaticDoor/Sounds",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 16,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "BigDoor_Closing01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_Closing02",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_Closing_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_Moving01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_Moving_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_StartOpening01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BigDoor_StartOpening01_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DoorSoundAttenuation",
|
||||
"ue_class_type": "SoundAttenuation",
|
||||
"note": [
|
||||
"非 Actor 蓝图: SoundAttenuation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_Closing01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_Closing_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StarClosing01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StarClosing01_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StarClosing02",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StartOpening01",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StartOpening02",
|
||||
"ue_class_type": "SoundWave",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundWave"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SimpleDoor_StartOpening_Cue",
|
||||
"ue_class_type": "SoundCue",
|
||||
"note": [
|
||||
"非 Actor 类型: SoundCue"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"subfolder": "Decals",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Decals",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 16,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_CircleZoneDecal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_OctagonZoneDecal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ShapeArrow_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ShapeCross_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ShapeLess_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ShapeSquare_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SquareZone_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SquareZoneBlue_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SquareZoneGreen_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SquareZoneRed_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SquareZoneYellow_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SripeZoneBlue_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SripeZoneGreen_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SripeZoneRed_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SripeZoneWhite_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SripeZoneYellow_Decal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"subfolder": "Decals/Class",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Decals/Class",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 6,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_BlockingDecal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SimpleBlockingDecal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ZoneDecal",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BlockingDecalData",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BlockingDecalMaterialParameters_Struct",
|
||||
"ue_class_type": "UserDefinedStruct",
|
||||
"note": [
|
||||
"非 Actor 类型: UserDefinedStruct"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DecalPivotPoint_Enum",
|
||||
"ue_class_type": "UserDefinedEnum",
|
||||
"note": [
|
||||
"非 Actor 类型: UserDefinedEnum"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"subfolder": "Interactions",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Interactions",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 3,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_FloorButton",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_PushButton",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_TriggerButton",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"subfolder": "Interactions/Curves",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Interactions/Curves",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 1,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "Curve_ButtonPress",
|
||||
"ue_class_type": "CurveFloat",
|
||||
"note": [
|
||||
"非 Actor 类型: CurveFloat"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"subfolder": "Interactions/Types",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Interactions/Types",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 1,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "ReplicatedPressedButton_Struct",
|
||||
"ue_class_type": "UserDefinedStruct",
|
||||
"note": [
|
||||
"非 Actor 类型: UserDefinedStruct"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"subfolder": "Lights",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Lights",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 10,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_BlockingLights",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLight01",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLight02a",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLight03a",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLight03b",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLightBulb",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_CeilingLightFlat02a",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_FlamingTorchWithSupport",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_RoadLamp_01",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_RoadLight",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"subfolder": "Others",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Others",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 5,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_DisplayPanel",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_HumanScaleReference",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SimpleCameraPreview",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_SplineArrow",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_TurnToCameraComponent",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"subfolder": "Others/BlockingTooltip",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Others/BlockingTooltip",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 2,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_BlockingTooltipActor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NS_BlockingTooltip",
|
||||
"ue_class_type": "NiagaraSystem",
|
||||
"note": [
|
||||
"非 Actor 类型: NiagaraSystem"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"subfolder": "Procedural",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/Procedural",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 6,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_BarrierWall",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_Ladder_01",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_Ladder_02",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_ProceduralBlockoutActor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_RoadSpeedBump",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_StairPlane",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"subfolder": "StaticDoor",
|
||||
"source_path": "/Game/BlockingStarterPack/Blueprints/StaticDoor",
|
||||
"actor_blueprint_count": 0,
|
||||
"non_actor_count": 2,
|
||||
"completed": true,
|
||||
"actor_blueprints": {},
|
||||
"skipped_non_actor": [
|
||||
{
|
||||
"name": "B_StaticDoor",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "B_StaticDoorDouble",
|
||||
"ue_class_type": "Blueprint",
|
||||
"note": [
|
||||
"非 Actor 蓝图: Blueprint"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"started_at": "2026-06-10T11:57:44.766012",
|
||||
"scan_root": "/Game/BlockingStarterPack",
|
||||
"output_dir": "C:\\MiceCola\\Indi\\ChildHood\\output\\asset-catalog",
|
||||
"steps": [
|
||||
{
|
||||
"name": "discover",
|
||||
"status": "ok",
|
||||
"total": 644,
|
||||
"meshes": 425,
|
||||
"materials": 86,
|
||||
"blueprints": 78,
|
||||
"others": 55,
|
||||
"mesh_subfolders": [
|
||||
"Architecture/Barriers",
|
||||
"Architecture/BayWindows",
|
||||
"Architecture/Beams",
|
||||
"Architecture/Doors",
|
||||
"Architecture/Floors",
|
||||
"Architecture/Stairs",
|
||||
"Architecture/Walls",
|
||||
"Architecture/WindowsSet",
|
||||
"Bathroom",
|
||||
"Bedroom",
|
||||
"BigBuildings",
|
||||
"Decorations",
|
||||
"DisplayPanels",
|
||||
"Extra/Camera",
|
||||
"Extra",
|
||||
"Furnitures",
|
||||
"Gears",
|
||||
"Industrials",
|
||||
"Interactions",
|
||||
"LandMesh",
|
||||
"Lights",
|
||||
"Pipes",
|
||||
"Primitives/Others",
|
||||
"Primitives",
|
||||
"Roads",
|
||||
"SmallBuildings",
|
||||
"Trashs",
|
||||
"Vegetations",
|
||||
"Vehicles",
|
||||
"Weapons"
|
||||
],
|
||||
"material_subfolders": [
|
||||
"Others/BlockingTooltip",
|
||||
"",
|
||||
"Blocking/Basics",
|
||||
"Blocking",
|
||||
"Blocking/TriPlanarLocalAligned",
|
||||
"Blocking/TriPlanarWorldAligned",
|
||||
"Decals",
|
||||
"Editor",
|
||||
"Glass",
|
||||
"Light"
|
||||
],
|
||||
"blueprint_subfolders": [
|
||||
"AutomaticDoor",
|
||||
"AutomaticDoor/Curves",
|
||||
"AutomaticDoor/Sounds",
|
||||
"Decals",
|
||||
"Decals/Class",
|
||||
"Interactions",
|
||||
"Interactions/Curves",
|
||||
"Interactions/Types",
|
||||
"Lights",
|
||||
"Others",
|
||||
"Others/BlockingTooltip",
|
||||
"Procedural",
|
||||
"StaticDoor"
|
||||
],
|
||||
"elapsed_sec": 4.2
|
||||
},
|
||||
{
|
||||
"name": "mesh",
|
||||
"status": "ok",
|
||||
"total": 425,
|
||||
"analyzed": 425,
|
||||
"failed": 0,
|
||||
"elapsed_sec": 1.5
|
||||
},
|
||||
{
|
||||
"name": "material",
|
||||
"status": "ok",
|
||||
"total": 86,
|
||||
"analyzed": 86,
|
||||
"failed": 0,
|
||||
"elapsed_sec": 0.5
|
||||
},
|
||||
{
|
||||
"name": "blueprint",
|
||||
"status": "ok",
|
||||
"total": 78,
|
||||
"actor_blueprints": 0,
|
||||
"skipped_non_actor": 78,
|
||||
"elapsed_sec": 0.6
|
||||
}
|
||||
],
|
||||
"completed_at": "2026-06-10T11:57:51.806102",
|
||||
"status": "ok"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"subfolder": "Blocking",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Blocking",
|
||||
"count": 2,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_BlockingMaterial": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
},
|
||||
"MI_DisplayPanelFace": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/MI_DisplayPanelFace.MI_DisplayPanelFace",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.3398,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 5.0
|
||||
},
|
||||
{
|
||||
"name": "UV Offset X",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "UV Offset Y",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "UV Scale X",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "UV Scale Y",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"display"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
{
|
||||
"subfolder": "Blocking/Basics",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics",
|
||||
"count": 14,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"MI_DevBlack": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlack.MI_DevBlack",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0104,
|
||||
"g": 0.0104,
|
||||
"b": 0.0104,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.1615,
|
||||
"g": 0.1615,
|
||||
"b": 0.1615,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#030303",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlue.MI_DevBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0000FF",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevBrown": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBrown.MI_DevBrown",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0729,
|
||||
"g": 0.031,
|
||||
"b": 0.0087,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#130802",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevFoliage": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevFoliage.MI_DevFoliage",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.151,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#002700",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevGray": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGray.MI_DevGray",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0885,
|
||||
"g": 0.0885,
|
||||
"b": 0.0885,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RoughnessMax",
|
||||
"value": 0.8
|
||||
},
|
||||
{
|
||||
"name": "RoughnessMin",
|
||||
"value": 0.6
|
||||
},
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 1.679003
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#171717",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGreen.MI_DevGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevOrange": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevOrange.MI_DevOrange",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.8308,
|
||||
"g": 0.3238,
|
||||
"b": 0.026,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Wire Roughness",
|
||||
"value": 0.6
|
||||
},
|
||||
{
|
||||
"name": "UV Offset X",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "UV Offset Y",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "UV Scale X",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "UV Scale Y",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#D45307",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevPink": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPink.MI_DevPink",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.3882,
|
||||
"b": 0.8682,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF63DD",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevPurple": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPurple.MI_DevPurple",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.6562,
|
||||
"g": 0.0355,
|
||||
"b": 0.413,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#A70969",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevRed": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevRed.MI_DevRed",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevSkyBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevSkyBlue.MI_DevSkyBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.4038,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0067FF",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevWhite": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevWhite.MI_DevWhite",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.3698,
|
||||
"g": 0.3698,
|
||||
"b": 0.3698,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Line Grow Distance",
|
||||
"value": 60000.0
|
||||
},
|
||||
{
|
||||
"name": "Line Weight Multiply On Distance",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Wire Weight (Small)",
|
||||
"value": 0.47
|
||||
},
|
||||
{
|
||||
"name": "Wire Weight (Medium)",
|
||||
"value": 0.465
|
||||
},
|
||||
{
|
||||
"name": "Wire Weight (Large)",
|
||||
"value": 0.475
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#5E5E5E",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_DevYellow": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevYellow.MI_DevYellow",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FFFF00",
|
||||
"style_tags": [
|
||||
"basic_color"
|
||||
]
|
||||
},
|
||||
"MI_LightGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_LightGreen.MI_LightGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.4798,
|
||||
"g": 1.0,
|
||||
"b": 0.3867,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#7AFF63",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
{
|
||||
"subfolder": "Blocking/TriPlanarLocalAligned",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned",
|
||||
"count": 14,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"MI_DevBlack_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevBlack_TPLA.MI_DevBlack_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlack.MI_DevBlack",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevBlue_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevBlue_TPLA.MI_DevBlue_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlue.MI_DevBlue",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevBrown_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevBrown_TPLA.MI_DevBrown_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBrown.MI_DevBrown",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevFoliage_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevFoliage_TPLA.MI_DevFoliage_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevFoliage.MI_DevFoliage",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevGray_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevGray_TPLA.MI_DevGray_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGray.MI_DevGray",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "TriplanardSmooth",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevGreen_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevGreen_TPLA.MI_DevGreen_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGreen.MI_DevGreen",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevOrange_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevOrange_TPLA.MI_DevOrange_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevOrange.MI_DevOrange",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevPink_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevPink_TPLA.MI_DevPink_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPink.MI_DevPink",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevPurple_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevPurple_TPLA.MI_DevPurple_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPurple.MI_DevPurple",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevRed_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevRed_TPLA.MI_DevRed_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevRed.MI_DevRed",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevSkyBlue_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevSkyBlue_TPLA.MI_DevSkyBlue_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevSkyBlue.MI_DevSkyBlue",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevWhite_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevWhite_TPLA.MI_DevWhite_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevWhite.MI_DevWhite",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevYellow_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_DevYellow_TPLA.MI_DevYellow_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevYellow.MI_DevYellow",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
},
|
||||
"MI_LightGreen_TPLA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarLocalAligned/MI_LightGreen_TPLA.MI_LightGreen_TPLA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_LightGreen.MI_LightGreen",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"local_aligned"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"subfolder": "Blocking/TriPlanarWorldAligned",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned",
|
||||
"count": 14,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"MI_DevBlack_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevBlack_TPWA.MI_DevBlack_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlack.MI_DevBlack",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevBlue_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevBlue_TPWA.MI_DevBlue_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBlue.MI_DevBlue",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevBrown_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevBrown_TPWA.MI_DevBrown_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevBrown.MI_DevBrown",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevFoliage_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevFoliage_TPWA.MI_DevFoliage_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevFoliage.MI_DevFoliage",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevGray_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevGray_TPWA.MI_DevGray_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGray.MI_DevGray",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "TriplanardSmooth",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevGreen_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevGreen_TPWA.MI_DevGreen_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevGreen.MI_DevGreen",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevOange_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevOange_TPWA.MI_DevOange_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevOrange.MI_DevOrange",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "TriplanardSmooth",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevPink_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevPink_TPWA.MI_DevPink_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPink.MI_DevPink",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevPurple_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevPurple_TPWA.MI_DevPurple_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevPurple.MI_DevPurple",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevRed_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevRed_TPWA.MI_DevRed_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevRed.MI_DevRed",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevSkyBlue_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevSkyBlue_TPWA.MI_DevSkyBlue_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevSkyBlue.MI_DevSkyBlue",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevWhite_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevWhite_TPWA.MI_DevWhite_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevWhite.MI_DevWhite",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_DevYellow_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_DevYellow_TPWA.MI_DevYellow_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_DevYellow.MI_DevYellow",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
},
|
||||
"MI_LightGreen_TPWA": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Blocking/TriPlanarWorldAligned/MI_LightGreen_TPWA.MI_LightGreen_TPWA",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/Basics/MI_LightGreen.MI_LightGreen",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"tri_planar",
|
||||
"world_aligned"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"subfolder": "Decals",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Decals",
|
||||
"count": 7,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_StainDecalColor": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorBlack": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorBlack.MI_StainDecalColorBlack",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorBlue.MI_StainDecalColorBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0000FF",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorGreen.MI_StainDecalColorGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorRed": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorRed.MI_StainDecalColorRed",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorSkyBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorSkyBlue.MI_StainDecalColorSkyBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.4038,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0067FF",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
},
|
||||
"MI_StainDecalColorYellow": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Decals/MI_StainDecalColorYellow.MI_StainDecalColorYellow",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Decals/M_StainDecalColor.M_StainDecalColor",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FFFF00",
|
||||
"style_tags": [
|
||||
"decal",
|
||||
"stain"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
{
|
||||
"subfolder": "Editor",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Editor",
|
||||
"count": 8,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_DevTriggerView": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevArrowMoving": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevArrowMoving.MI_DevArrowMoving",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorA",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 0.0571,
|
||||
"g": 0.3069,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "CoordX",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "CoordY",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "CustomPannerTime",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "SpeedY",
|
||||
"value": -1.0
|
||||
},
|
||||
{
|
||||
"name": "PulseMin",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "PulseSpeed",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevArrowMoving2": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevArrowMoving2.MI_DevArrowMoving2",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorA",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.4833,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "CoordX",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "CoordY",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "DepthFadeDistance",
|
||||
"value": 15.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "CustomPannerTime",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "SpeedX",
|
||||
"value": -4.0
|
||||
},
|
||||
{
|
||||
"name": "SpeedY",
|
||||
"value": 0.1
|
||||
},
|
||||
{
|
||||
"name": "PulseMin",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "PulseSpeed",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "CustomRotationTime",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevArrowMoving3": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevArrowMoving3.MI_DevArrowMoving3",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorA",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 0.338,
|
||||
"g": 0.0981,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "CoordX",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "CoordY",
|
||||
"value": 6.0
|
||||
},
|
||||
{
|
||||
"name": "CustomPannerTime",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "SpeedY",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "CustomRotationTime",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevTriggerViewBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevTriggerViewBlue.MI_DevTriggerViewBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.2832,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0048FF",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevTriggerViewGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevTriggerViewGreen.MI_DevTriggerViewGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevTriggerViewOrange": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevTriggerViewOrange.MI_DevTriggerViewOrange",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.5,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF8000",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
"MI_DevTriggerViewRed": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Editor/MI_DevTriggerViewRed.MI_DevTriggerViewRed",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Editor/M_DevTriggerView.M_DevTriggerView",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "ColorB",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"editor",
|
||||
"debug"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,665 @@
|
||||
{
|
||||
"subfolder": "Glass",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Glass",
|
||||
"count": 11,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_DevGlass": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassBlue.MI_DevGlassBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.6714,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.6714,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00ABFF",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassGreen.MI_DevGlassGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassMetalBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassMetalBlue.MI_DevGlassMetalBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.6714,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.6714,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00ABFF",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassMetalGreen": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassMetalGreen.MI_DevGlassMetalGreen",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassMetalRed": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassMetalRed.MI_DevGlassMetalRed",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassMetalWhite": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassMetalWhite.MI_DevGlassMetalWhite",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FFFFFF",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassMetalWhiteSoft": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassMetalWhiteSoft.MI_DevGlassMetalWhiteSoft",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.08
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.12
|
||||
},
|
||||
{
|
||||
"name": "OpacityMax",
|
||||
"value": 0.12
|
||||
},
|
||||
{
|
||||
"name": "OpacityMin",
|
||||
"value": 0.08
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FFFFFF",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassRed": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassRed.MI_DevGlassRed",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassWhite": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassWhite.MI_DevGlassWhite",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "GlassColor",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.4
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
},
|
||||
"MI_DevGlassWhiteSoft": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Glass/MI_DevGlassWhiteSoft.MI_DevGlassWhiteSoft",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Glass/M_DevGlass.M_DevGlass",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Specular",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Opacity",
|
||||
"value": 0.08
|
||||
},
|
||||
{
|
||||
"name": "Wire Opacity",
|
||||
"value": 0.12
|
||||
},
|
||||
{
|
||||
"name": "OpacityMax",
|
||||
"value": 0.12
|
||||
},
|
||||
{
|
||||
"name": "OpacityMin",
|
||||
"value": 0.08
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"glass",
|
||||
"transparent"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
{
|
||||
"subfolder": "Light",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Light",
|
||||
"count": 9,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_DevLight": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_Green": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_Green.MI_DevLight_Green",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 1.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#00FF00",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_NaturalBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_NaturalBlue.MI_DevLight_NaturalBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.4169,
|
||||
"g": 0.5275,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#6A87FF",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_NaturalOrange": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_NaturalOrange.MI_DevLight_NaturalOrange",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.5116,
|
||||
"b": 0.3404,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF8257",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_NaturalWhite": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_NaturalWhite.MI_DevLight_NaturalWhite",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_NaturalYellow": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_NaturalYellow.MI_DevLight_NaturalYellow",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.8803,
|
||||
"b": 0.2678,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FFE044",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_Off": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_Off.MI_DevLight_Off",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.2344,
|
||||
"g": 0.2344,
|
||||
"b": 0.2344,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "DirtScale",
|
||||
"value": 0.1
|
||||
},
|
||||
{
|
||||
"name": "Dirt Normal Scale",
|
||||
"value": 0.01
|
||||
},
|
||||
{
|
||||
"name": "Roughness",
|
||||
"value": 0.1
|
||||
},
|
||||
{
|
||||
"name": "Wire Roughness",
|
||||
"value": 0.5
|
||||
},
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 0.9
|
||||
},
|
||||
{
|
||||
"name": "Light Intensity",
|
||||
"value": 0.0
|
||||
},
|
||||
{
|
||||
"name": "WiresPower",
|
||||
"value": 2.0
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#3C3C3C",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_Red": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_Red.MI_DevLight_Red",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Light Intensity",
|
||||
"value": 2.2
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#FF0000",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
},
|
||||
"MI_DevLight_SkyBlue": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/Light/MI_DevLight_SkyBlue.MI_DevLight_SkyBlue",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Light/M_DevLight.M_DevLight",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.4038,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#0067FF",
|
||||
"style_tags": [
|
||||
"emissive",
|
||||
"light_color"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"subfolder": "Others/BlockingTooltip",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials/Others/BlockingTooltip",
|
||||
"count": 2,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_BlockingTooltipBase": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Blueprints/Others/BlockingTooltip/M_BlockingTooltipBase.M_BlockingTooltipBase",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Blueprints/Others/BlockingTooltip/M_BlockingTooltipBase.M_BlockingTooltipBase",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
},
|
||||
"M_BlockingTooltipText": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Blueprints/Others/BlockingTooltip/M_BlockingTooltipText.M_BlockingTooltipText",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Blueprints/Others/BlockingTooltip/M_BlockingTooltipText.M_BlockingTooltipText",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"subfolder": "",
|
||||
"source_path": "/Game/BlockingStarterPack/Materials",
|
||||
"count": 5,
|
||||
"completed": true,
|
||||
"materials": {
|
||||
"M_OverviewLevelFloor": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Maps/M_OverviewLevelFloor.M_OverviewLevelFloor",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Maps/M_OverviewLevelFloor.M_OverviewLevelFloor",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
},
|
||||
"M_OverviewLevelFloor2": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Maps/M_OverviewLevelFloor2.M_OverviewLevelFloor2",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Maps/M_OverviewLevelFloor2.M_OverviewLevelFloor2",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"unclassified"
|
||||
]
|
||||
},
|
||||
"M_DevMirror": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/M_DevMirror.M_DevMirror",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/M_DevMirror.M_DevMirror",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"mirror",
|
||||
"reflective"
|
||||
]
|
||||
},
|
||||
"M_FullyBlack": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/M_FullyBlack.M_FullyBlack",
|
||||
"ue_class_type": "Material",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/M_FullyBlack.M_FullyBlack",
|
||||
"parameters": {
|
||||
"vector": [],
|
||||
"scalar": []
|
||||
},
|
||||
"analysis_notes": [
|
||||
"基础 Material,参数需从实例推断"
|
||||
],
|
||||
"base_color_hex": "",
|
||||
"style_tags": [
|
||||
"special"
|
||||
]
|
||||
},
|
||||
"MI_DevGrid": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Materials/MI_DevGrid.MI_DevGrid",
|
||||
"ue_class_type": "MaterialInstanceConstant",
|
||||
"parent_material": "/Game/BlockingStarterPack/Materials/Blocking/M_BlockingMaterial.M_BlockingMaterial",
|
||||
"parameters": {
|
||||
"vector": [
|
||||
{
|
||||
"name": "Color",
|
||||
"value": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wire Color",
|
||||
"value": {
|
||||
"r": 1.0,
|
||||
"g": 1.0,
|
||||
"b": 1.0,
|
||||
"a": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"scalar": [
|
||||
{
|
||||
"name": "Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Roughness",
|
||||
"value": 0.55
|
||||
},
|
||||
{
|
||||
"name": "Roughness Checkers Multiply",
|
||||
"value": 0.9
|
||||
},
|
||||
{
|
||||
"name": "Wire Metallic",
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"name": "Wire Roughness",
|
||||
"value": 0.198
|
||||
},
|
||||
{
|
||||
"name": "RefractionDepthBias",
|
||||
"value": 0.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"analysis_notes": [],
|
||||
"base_color_hex": "#000000",
|
||||
"style_tags": [
|
||||
"grid",
|
||||
"debug"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,758 @@
|
||||
{
|
||||
"subfolder": "Architecture/BayWindows",
|
||||
"source_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows",
|
||||
"count": 12,
|
||||
"completed": true,
|
||||
"meshes": {
|
||||
"SM_BayWindow_100x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_100x300.SM_BayWindow_100x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
100.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
100.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
49.999805450454005,
|
||||
0.0015639066696166992
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindow_100x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_100x400.SM_BayWindow_100x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
100.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
100.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
49.999805450454005,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindow_200x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_200x300.SM_BayWindow_200x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99980926515127,
|
||||
0.0015639066696166992
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindow_200x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_200x400.SM_BayWindow_200x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99980926515127,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindow_400x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_400x300.SM_BayWindow_400x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.0015639066696166992
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindow_400x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindow_400x400.SM_BayWindow_400x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoor_200x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoor_200x300.SM_BayWindowDoor_200x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99980926515127,
|
||||
0.001558065414428711
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoor_200x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoor_200x400.SM_BayWindowDoor_200x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99980926515127,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoor_400x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoor_400x300.SM_BayWindowDoor_400x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.001558065414428711
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoor_400x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoor_400x400.SM_BayWindowDoor_400x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoorDouble_400x300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoorDouble_400x300.SM_BayWindowDoorDouble_400x300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.001558065414428711
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_BayWindowDoorDouble_400x400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/BayWindows/SM_BayWindowDoorDouble_400x400.SM_BayWindowDoorDouble_400x400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-0.0,
|
||||
-3.966,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
400.0,
|
||||
3.969,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
7.936,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
199.99980163575674,
|
||||
0.001555800437927246
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "Face",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "Join",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door",
|
||||
"window"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
{
|
||||
"subfolder": "Architecture/Beams",
|
||||
"source_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams",
|
||||
"count": 6,
|
||||
"completed": true,
|
||||
"meshes": {
|
||||
"SM_Beam_300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_Beam_300.SM_Beam_300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-20.0,
|
||||
-20.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
20.0,
|
||||
20.0,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
40.0,
|
||||
40.0,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-2.47955322265625e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_Beam_400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_Beam_400.SM_Beam_400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-20.0,
|
||||
-20.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
20.0,
|
||||
20.0,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
40.0,
|
||||
40.0,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-3.24249267578125e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_Beam_400_45d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_Beam_400_45d.SM_Beam_400_45d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-19.999,
|
||||
-419.999,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
20.001,
|
||||
-268.845,
|
||||
296.749
|
||||
],
|
||||
"size": [
|
||||
40.0,
|
||||
151.155,
|
||||
296.749
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
0.0007476806640625,
|
||||
-344.4219055175781
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RoundedBeam_300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_RoundedBeam_300.SM_RoundedBeam_300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-30.0,
|
||||
-30.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
30.0,
|
||||
30.0,
|
||||
300.0
|
||||
],
|
||||
"size": [
|
||||
60.0,
|
||||
60.0,
|
||||
300.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-2.47955322265625e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RoundedBeam_400": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_RoundedBeam_400.SM_RoundedBeam_400",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-30.0,
|
||||
-30.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
30.0,
|
||||
30.0,
|
||||
400.0
|
||||
],
|
||||
"size": [
|
||||
60.0,
|
||||
60.0,
|
||||
400.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-3.4332275390625e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RoundedBeam_400_45d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Beams/SM_RoundedBeam_400_45d.SM_RoundedBeam_400_45d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-30.0,
|
||||
-429.981,
|
||||
-0.291
|
||||
],
|
||||
"max": [
|
||||
30.0,
|
||||
-261.934,
|
||||
303.597
|
||||
],
|
||||
"size": [
|
||||
60.0,
|
||||
168.047,
|
||||
303.888
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-1.71661376953125e-05,
|
||||
-345.957763671875
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"structure"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,939 @@
|
||||
{
|
||||
"subfolder": "Architecture/Doors",
|
||||
"source_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors",
|
||||
"count": 16,
|
||||
"completed": true,
|
||||
"meshes": {
|
||||
"SM_DoorFrame": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_DoorFrame.SM_DoorFrame",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-66.0,
|
||||
-12.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
66.0,
|
||||
12.0,
|
||||
232.0
|
||||
],
|
||||
"size": [
|
||||
132.0,
|
||||
24.0,
|
||||
232.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-1.9073486328125e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 1
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_DoorFrameDouble": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_DoorFrameDouble.SM_DoorFrameDouble",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-116.0,
|
||||
-12.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
116.0,
|
||||
12.0,
|
||||
232.0
|
||||
],
|
||||
"size": [
|
||||
232.0,
|
||||
24.0,
|
||||
232.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-1.9073486328125e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 1
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_DoorFrameGarage": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_DoorFrameGarage.SM_DoorFrameGarage",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-166.0,
|
||||
-12.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
166.0,
|
||||
12.0,
|
||||
292.0
|
||||
],
|
||||
"size": [
|
||||
332.0,
|
||||
24.0,
|
||||
292.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-2.384185791015625e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 1
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_FakeDoor": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_FakeDoor.SM_FakeDoor",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-66.0,
|
||||
-0.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
66.0,
|
||||
12.0,
|
||||
232.0
|
||||
],
|
||||
"size": [
|
||||
132.0,
|
||||
12.0,
|
||||
232.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
5.999777317047119
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_FakeDoorDouble": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_FakeDoorDouble.SM_FakeDoorDouble",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-116.0,
|
||||
-0.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
116.0,
|
||||
12.0,
|
||||
232.0
|
||||
],
|
||||
"size": [
|
||||
232.0,
|
||||
12.0,
|
||||
232.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
7.62939453125e-06,
|
||||
5.999777317047119
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_FakeFrameGarage": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_FakeFrameGarage.SM_FakeFrameGarage",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-166.0,
|
||||
-0.002,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
166.0,
|
||||
12.0,
|
||||
292.0
|
||||
],
|
||||
"size": [
|
||||
332.0,
|
||||
12.002,
|
||||
292.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
5.998886585235596
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"unknown"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_GarageDoor_01": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_GarageDoor_01.SM_GarageDoor_01",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-150.0,
|
||||
-5.914,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
5.914,
|
||||
276.004
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
11.828,
|
||||
276.004
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-1.430511474609375e-06
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_GarageDoor_02": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_GarageDoor_02.SM_GarageDoor_02",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-150.0,
|
||||
-5.914,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
5.914,
|
||||
276.004
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
11.828,
|
||||
276.004
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-1.430511474609375e-06
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_GarageDoorOpen_01": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_GarageDoorOpen_01.SM_GarageDoorOpen_01",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-150.0,
|
||||
-224.485,
|
||||
219.986
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
5.914,
|
||||
296.388
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
230.398,
|
||||
76.401
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
-109.28529357910156
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_GarageDoorOpen_02": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_GarageDoorOpen_02.SM_GarageDoorOpen_02",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-150.0,
|
||||
-224.484,
|
||||
219.981
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
5.914,
|
||||
296.388
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
230.398,
|
||||
76.407
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-0.00019073486328125,
|
||||
-109.28524470329285
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_LateralDoor": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_LateralDoor.SM_LateralDoor",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-10.0,
|
||||
-8.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
8.0,
|
||||
250.0
|
||||
],
|
||||
"size": [
|
||||
160.0,
|
||||
16.0,
|
||||
250.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
70.00001525878906,
|
||||
-2.574920654296875e-05
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_LateralDoorFrame_150": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_LateralDoorFrame_150.SM_LateralDoorFrame_150",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-75.0,
|
||||
-55.236,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
75.0,
|
||||
55.236,
|
||||
250.0
|
||||
],
|
||||
"size": [
|
||||
150.0,
|
||||
110.473,
|
||||
250.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_LateralDoorFrame_300": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_LateralDoorFrame_300.SM_LateralDoorFrame_300",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-150.0,
|
||||
-55.236,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
150.0,
|
||||
55.236,
|
||||
250.0
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
110.473,
|
||||
250.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CENTER_BOTTOM",
|
||||
"offset_xy": [
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RotativeDoor_01": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_RotativeDoor_01.SM_RotativeDoor_01",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-100.0,
|
||||
-12.0,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
0.0,
|
||||
11.991,
|
||||
216.0
|
||||
],
|
||||
"size": [
|
||||
100.0,
|
||||
23.991,
|
||||
216.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-49.99995422363281,
|
||||
-0.004532814025878906
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevGlass",
|
||||
"material_name": "MI_DevGlassMetalWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RotativeDoor_02": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_RotativeDoor_02.SM_RotativeDoor_02",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-100.0,
|
||||
-12.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
0.0,
|
||||
11.991,
|
||||
216.0
|
||||
],
|
||||
"size": [
|
||||
100.0,
|
||||
23.991,
|
||||
216.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-49.99995422363281,
|
||||
-0.004460334777832031
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_RotativeDoor_03": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Doors/SM_RotativeDoor_03.SM_RotativeDoor_03",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-100.0,
|
||||
-12.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
0.0,
|
||||
11.991,
|
||||
216.0
|
||||
],
|
||||
"size": [
|
||||
100.0,
|
||||
23.991,
|
||||
216.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-49.99995422363281,
|
||||
-0.004532814025878906
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 3
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"slot_name": "M_DevWhite",
|
||||
"material_name": "MI_DevWhite"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"door"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
||||
{
|
||||
"subfolder": "Architecture/Stairs",
|
||||
"source_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs",
|
||||
"count": 10,
|
||||
"completed": true,
|
||||
"meshes": {
|
||||
"SM_Stair_100": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_Stair_100.SM_Stair_100",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
0.0,
|
||||
-0.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
150.0,
|
||||
102.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
150.0,
|
||||
102.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99999237056181,
|
||||
74.99992302650207
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_Stair_200": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_Stair_200.SM_Stair_200",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
0.0,
|
||||
-0.0,
|
||||
0.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
300.0,
|
||||
202.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
300.0,
|
||||
202.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "CORNER",
|
||||
"offset_xy": [
|
||||
99.99999237056181,
|
||||
149.99984621592557
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlane_100": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlane_100.SM_StairPlane_100",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
0.0,
|
||||
-0.0,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
150.0,
|
||||
102.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
150.0,
|
||||
122.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
99.99999237056181,
|
||||
74.99992302650207
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlane_200": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlane_200.SM_StairPlane_200",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
0.0,
|
||||
-0.0,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
200.0,
|
||||
300.0,
|
||||
202.0
|
||||
],
|
||||
"size": [
|
||||
200.0,
|
||||
300.0,
|
||||
222.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
99.99999237056181,
|
||||
149.99984621592557
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlaneRounded_300_45d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlaneRounded_300_45d.SM_StairPlaneRounded_300_45d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-300.0,
|
||||
-212.132,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
-70.71,
|
||||
-0.0,
|
||||
102.0
|
||||
],
|
||||
"size": [
|
||||
229.29,
|
||||
212.132,
|
||||
122.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-185.35503768920898,
|
||||
-106.06606129789725
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlaneRounded_300_90d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlaneRounded_300_90d.SM_StairPlaneRounded_300_90d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-300.0,
|
||||
-300.0,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
0.0,
|
||||
-0.0,
|
||||
202.0
|
||||
],
|
||||
"size": [
|
||||
300.0,
|
||||
300.0,
|
||||
222.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-149.9999389648583,
|
||||
-150.00014105534137
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlaneRounded_400_45d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlaneRounded_400_45d.SM_StairPlaneRounded_400_45d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-400.0,
|
||||
-282.842,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
-141.42,
|
||||
-0.0,
|
||||
102.0
|
||||
],
|
||||
"size": [
|
||||
258.58,
|
||||
282.842,
|
||||
122.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-270.71009063720703,
|
||||
-141.4214359519974
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairPlaneRounded_400_90d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairPlaneRounded_400_90d.SM_StairPlaneRounded_400_90d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-400.0,
|
||||
-400.0,
|
||||
-20.0
|
||||
],
|
||||
"max": [
|
||||
0.0,
|
||||
-0.0,
|
||||
202.0
|
||||
],
|
||||
"size": [
|
||||
400.0,
|
||||
400.0,
|
||||
222.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-199.9999023437631,
|
||||
-200.0001722176312
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair",
|
||||
"vehicle"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairRounded_300_45d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairRounded_300_45d.SM_StairRounded_300_45d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-300.0,
|
||||
-212.132,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
-70.711,
|
||||
-0.0,
|
||||
102.0
|
||||
],
|
||||
"size": [
|
||||
229.289,
|
||||
212.132,
|
||||
102.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-185.35552597045898,
|
||||
-106.066326141241
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
},
|
||||
"SM_StairRounded_300_90d": {
|
||||
"ue_path": "/Game/BlockingStarterPack/Meshes/Architecture/Stairs/SM_StairRounded_300_90d.SM_StairRounded_300_90d",
|
||||
"bounding_box": {
|
||||
"min": [
|
||||
-300.0,
|
||||
-300.001,
|
||||
-0.0
|
||||
],
|
||||
"max": [
|
||||
-0.001,
|
||||
-0.0,
|
||||
202.0
|
||||
],
|
||||
"size": [
|
||||
299.999,
|
||||
300.001,
|
||||
202.0
|
||||
]
|
||||
},
|
||||
"pivot": {
|
||||
"type": "OTHER",
|
||||
"offset_xy": [
|
||||
-150.00024414039217,
|
||||
-150.00042724603554
|
||||
]
|
||||
},
|
||||
"mesh_complexity": {
|
||||
"num_verts": null,
|
||||
"num_triangles": null,
|
||||
"num_lods": 1,
|
||||
"num_sections": 2
|
||||
},
|
||||
"sockets": [],
|
||||
"material_slots": [
|
||||
{
|
||||
"index": 0,
|
||||
"slot_name": "M_DevOrange",
|
||||
"material_name": "MI_DevOrange"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"slot_name": "M_DevBlack",
|
||||
"material_name": "MI_DevGray"
|
||||
}
|
||||
],
|
||||
"analysis_notes": [],
|
||||
"key_surfaces": [],
|
||||
"ground_sink_estimate": null,
|
||||
"style_tags": [
|
||||
"architecture",
|
||||
"stair"
|
||||
],
|
||||
"scene_tags": [
|
||||
"architecture",
|
||||
"construction"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user