自由学习记录(151)

https://github.com/Donchitos/Claude-Code-Game-Studios/?utm_source=chatgpt.com

你和一个主代理交互时,这个主代理会按这些角色分工去组织上下文、提示词和输出方式,让你感觉像在和一个小团队协作。

你可以把它理解成这样

这个仓库不会"自动魔法般控制我"。

它的工作原理其实很朴素:

在 Claude Code 里原本是这样工作的

  1. 用户打开项目
  2. Claude Code 读取 CLAUDE.md
  3. Claude 按需要读取 .claude/agents/*.md、.claude/skills/*.md
  4. Claude 按这些提示词规则来扮演角色和执行工作流

在 Codex 里现在是这样工作的

  1. 我读取你项目里的文档
  2. 我把这些文档当作项目规则和流程资产
  3. 我再按 Codex 的方式执行它们
  4. 其中 Claude 专属的运行时部分,我不直接继承,只把它们当参考

所以现在我的回答,不是"被 agent 自动接管",而是:

我主动读取并遵守了这个仓库里的规则文档和 skill 文档。

更复杂的 prompt orchestration。

PowerShell 把 codex.ps1 拦了。

绕过 .ps1,试可执行包装器。

在当前目录里先试:

overflow-visible! 复制代码

PowerShell
codex.cmd

  • Epic 的 `Enhanced Input` 和 `UInputMappingContext` 就是为"上下文切换输入"设计的,适合你这种 `普通第一人称` / `手操控模式` 两套映射切换。

  • Epic 的 `Live Link` 明确支持"外部源把数据流进 UE",而且支持 `Camera` / `Transform` 角色,也支持自定义 Source。

  • UE 5.7 文档里也能看到 `OpenCVHelper` 插件 API,说明官方引擎里确实有 OpenCV 相关基础模块可用,但这**不等于已经有现成的 webcam 头姿追踪玩法模块**。

  • 另外,官方现成的人脸追踪主路径其实更偏 `Live Link Face`(手机)而不是"PC 普通摄像头直接驱动玩家视角"。

**你这套方案里,最稳的部分**

  1. `F` 切模式

做两个 `Input Mapping Context`:

  • `IMC_DefaultFPS`

  • `IMC_HandMode`

按 `F`:

  • 移除默认 IMC

  • 添加手部 IMC

  • 锁定/隐藏普通视角输入

  • 启动头部追踪

  • 显示右手控制 UI 或状态

再按一次 `F` 反向切回。这个是标准 UE 路线。

  1. 鼠标映射成 多个 `Input Action`。

利爪模式下也只是切换这些 action 的解释方式,不需要改硬件输入层。

  1. `E` 切利爪状态

这个本质是一个状态机

  • `HandMode_Normal`

  • `HandMode_Claw`

切换后,从"收紧手指"变成"该指是否伸爪"。这在输入系统上很干净。

如果你坚持 PC 摄像头,这条路线是可行的,但它不是"蓝图拼一拼"级别,更像:

  • C++ 插件

  • 或外部程序 + Live Link Source

  • 或 OpenCV/MediaPipe 风格方案接 UE

先不要继续扩世界观,直接做一个技术 vertical slice,验证这 4 件事:

PC webcam 自定义插件

**官方资料**

不懂是最廉价的废话。

不想做那些"本来就该被自动化掉"的中间劳动?

如果你连这些也坚持不用蓝图:

  • 手模型挂载
  • Skeletal Mesh 指定
  • AnimBP/Control Rig 绑定
  • 输入资产配置
  • 参数调试
  • 相机位置细调
  • claw mesh/socket 调试

这些你也不是"不能做",只是会变得更慢、更硬。

所以我给你一个实用判断:

纯 C++ 可行的部分

  • PlayerCharacter
  • Components
  • 状态机
  • 输入绑定
  • 相机控制
  • 头追接口
  • 手指状态数据
  • 与动画系统通信的数据层

通常仍建议用编辑器资产承载的部分

  • Skeletal Mesh
  • Animation Blueprint
  • Control Rig
  • Input Mapping Context 资产
  • 手部 mesh / claw mesh / socket 配置
  • 场景交互对象配置

这不叫"依赖蓝图写逻辑",而是用 UE 正常的资产工作流

极端纯 C++,最大卡点在动画

不是做不到,而是你迟早会碰到这些:

  • 你要不要 AnimBP?
  • 你要不要 Control Rig?
  • 你要不要骨骼调试可视化?
  • 你要不要更快调每根手指的角度曲线?

这些在纯 C++ 下开发体验会差不少。

所以结论是:

  • 可以只写 C++ 逻辑,不靠蓝图写核心玩法
  • 但完全不碰蓝图/资产编辑器,不现实,也没必要
  • 最佳实践是:逻辑 C++,装配与动画资产用编辑器

在 UE 里,C++ 常常负责定义能力和边界,Blueprint/资产负责实例化、配置和组合。

也就是:

    • C++ 不是"换个形式写蓝图"

如果是 Unity,你很可能会想:

  • PlayerController.cs
  • HandController.cs
  • HeadTracking.cs
  • FingerState.cs
  • 然后把这些全挂在一个 prefab 上

这是非常 Unity 的思路。

如果是 UE,比较自然的思路会变成:

  • AMyPlayerCharacter
  • UHandControlComponent
  • UHeadTrackingComponent
  • UMyHandAnimInstance
  • IMC_HandMode 作为输入资产
  • 一个手部 Skeletal Mesh 资产
  • 一个 AnimBP 或 C++ AnimInstance 子类
  • 可能还有一个 BP_MyPlayerCharacter 只负责装这些东西

lueprint 本身是一个大类,不只 Actor Blueprint。基类是 AActor 的 Blueprint

Pawn / Character Blueprint

本质上也是 Actor Blueprint 的子类。

例如:

  • BP_Player
  • BP_NPCCharacter

它们也能放进场景,也很像 prefab,但更具体,是可控制角色模板。


3. ActorComponent Blueprint

这类不能单独放进场景

它们是组件蓝图,必须挂到 Actor 上用。

更像 Unity 里的自定义 MonoBehaviour 组件,而不是 prefab。

Widget Blueprint

例如 UI:

  • WBP_Inventory
  • WBP_Dialogue

它们也不是场景 Actor,不能像世界物体一样拖到关卡里当场景实体。

它们更像 Unity 里的 UI Prefab,但属于 UI 系统,不是世界 Actor。


5. Animation Blueprint

它是动画逻辑资产,不是场景对象。

不能直接放进场景。

更像:

  • Unity 的 Animator Controller + 动画图逻辑结合体

Blueprint Function Library

只是蓝图函数集合。

完全不是 prefab,也不是场景对象。


7. Interface Blueprint / Macro Library 等

这些都不是可放进场景的实体模板。

  • .uasset
  • .umap

也就是说,你在资源管理器里看到的文件后缀其实没那么多,真正多的是"编辑器里显示的资产种类"。

所以你可以这样记:

  • .uasset = 各种 UE 资产

  • .umap = 关卡地图

  • Blueprint

  • Widget Blueprint

  • Animation Blueprint

  • Material

  • Texture

  • Skeletal Mesh

  • Physics Asset

  • Input Action

  • Input Mapping Context

  • Data Asset

  • Niagara System

磁盘上大多本质都是 .uasset。

这点很重要,因为它能帮你降噪:

Unity 里的 ProjectSettings、package 配置、编辑器设置。

常见是:

  • .ini
  • .uproject
  • .uplugin

它们负责:

  • 项目配置
  • 插件声明
  • 引擎/编辑器设置
  • 默认类路径
  • 渲染/Input/平台配置

你可以这样理解:

  • .uproject = Unity 工程入口 + manifest 的混合体
  • .uplugin = 插件描述文件
  • .ini = 项目和引擎配置层

构建文件

这些是 Unity 里相对弱一点,但 UE 里更明显的一层。

常见:

  • .Build.cs
  • .Target.cs

它们负责:

  • 模块依赖
  • 编译目标
  • 链接哪些引擎模块
  • Editor/Game/Client/Server 构建配置

这部分你可以把它类比成:

  • Unity 里 asmdef + 一部分构建配置 + 模块声明

可以暂时只记这 6 类:

  1. .h

    定义类

  2. .cpp

    写逻辑

  3. .Build.cs

    声明这个模块依赖什么

  4. .uasset

    各种资产,别一开始细分过多

  5. .umap

    关卡

  6. .uproject

    项目入口

只靠这 6 个,你已经能大致理解一个 UE 项目。

  • Source/.../*.h
  • Source/.../*.cpp
  • *.Build.cs
  • BP_PlayerCharacter -> .uasset
  • IMC_DefaultFPS -> .uasset
  • IMC_HandMode -> .uasset
  • IA_Finger_Index 这类 Input Action -> .uasset
  • 手部 Skeletal Mesh -> .uasset
  • AnimBP -> .uasset
  • 测试地图 -> .umap

你看,实际也没那么散。

只分 4 层就够了:

  • 代码层:.h/.cpp
  • 资产层:.uasset
  • 地图层:.umap
  • 配置/构建层:.ini/.uproject/.Build.cs

这类危险不是崩溃级,而是项目会越来越脏

  • Blank C++ 项目
  • 只手动加你需要的系统

先看"项目设置是否被改"

每次导入模板后,第一时间检查这些:

  • Project Settings -> Maps & Modes
  • Project Settings -> Input
  • Project Settings -> Plugins
  • Default Pawn
  • Default GameMode
  • PlayerController
  • HUD

如果这些变了,就记录下来。

你担心"致命设置被改",真正高优先级看的就是这些。

只信引用图,不信直觉

UE 内置两个很重要的工具:

  • Reference Viewer
  • Size Map

你导入任何核心资产后,都去看:

  • 它依赖了什么
  • 谁在依赖它
  • 引用链有没有穿到你不想碰的地方

ctrl + L 改变光照方向

但它们仍然可以存在于很多别的游戏形式里。

剧情继续扩,只会让你更舍不得改核心交互。

假进展:内容越来越多,核心风险原地不动。

现在就把剧情写满,你会对现有形式产生情感绑定。

等交互出问题时,你会本能地想保住形式,而不是改对的地方。

把搜索结果改成了网格,但频道头像那一块仍然沿用 YouTube 搜索页原本的"大列表模式"尺寸,所以头像没有随卡片宽度一起收缩。

要的是"如果属于 short,就把里面每个 short 拆成普通 grid item",

这个单靠 CSS 做不到 ,因为 CSS 不能把父容器里的多个子项提升到外层 grid 参与同级排版。

这件事必须用 JS:

这件事必须用 JS:

  1. 找到 ytd-reel-shelf-renderer

  2. 取出里面的每个 ytd-reel-item-renderer

  3. 克隆/搬运成独立节点

  4. 插回外层 #contents

  5. 把原 shelf 隐掉

现在首次从首页进入搜索页时,问题恰恰是脚本根本没先注入,所以这个监听器也不存在。

所以最有效的修法,不是继续调 observer,而是先让脚本在 YouTube 整站都注入,再由代码自己判断"当前是不是搜索页"。

  • 脚本一开始就在 YouTube 全站注入

  • 你从首页搜到结果页时,yt-navigate-finish 触发

  • 脚本发现现在是 /results

  • 开始套 grid、shorts 处理、observer

  • 不再需要手动刷新

如果你想用你自己的图片,也可以把 @icon 换成你自己的图片 URL,比如
// @icon https://example.com/my-icon.png

要求通常是:

  • 最好是公网可访问的图片

  • png / ico / jpg 都可以,png 最稳

  • 小图标建议 32x32 或 64x64

如果你不想依赖外部网址,也可以直接用 base64 data URL,不过会比较长。例如:
// @icon data:image/png;base64,AAAA...

但这个不适合手写,通常是有现成图片再转。

一般不推荐,因为浏览器安全限制和不同设备路径差异,容易失效。比如这种理论上长这样:
// @icon file:///C:/Users/你的名字/Desktop/icon.png

Mimicry

UE 的 show fps / stat fps

更接近"每帧取一次真实经过时间,再做连续平滑"。

真正做性能判断时看毫秒而不是 FPS,因为 FPS 只是对帧时间的一个变换显示。

UE 的 Stats System 把多个线程和 GPU 的计时样本按"帧编号"归档

CPU 侧,UE 主循环每轮 Tick/Redraw 本身就是一个 engine frame;

stat unit 解释为显示 Frame / Game / Draw / GPU / RHIT / DynRes 这些线程或阶段的帧时间,用来判断瓶颈。

更具体一点,CPU 上至少有三种"帧时间来源"同时存在:

  1. Frame:整帧墙钟时间,等价于这次 frame loop 从上一帧到这一帧的跨度,通常接近你看到的 FPS 反算毫秒值。

  2. Game:游戏线程这一帧干活的时间。

  3. Draw / RHIT:渲染线程、RHI 线程在这一帧提交和驱动 GPU 的时间。

这些不是简单相加关系,因为线程之间大量重叠并行,真正的帧时长通常更接近"关键路径最大值 + 等待/同步"。Epic 的性能文档也直接说过,实际 frame time 通常受 GameDrawGPU 三者中最慢者限制。

https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/FGenericPlatformTime/GetSecondsPerCycle?utm_source=chatgpt.com

CPU 侧用平台高精度计时器不是靠 OS 普通毫秒计时。UE 的通用接口就是 FGenericPlatformTime::Cycles64() / Cycles(),官方 API 说明里明确说它返回平台相关的 CPU cycle 计数,Cycles64 推荐用于大多数用途,再用 GetSecondsPerCycle() 把 cycle 转成秒。UE 公开文档里 GetFrameCount 直接说明它返回 GFrameCounter,即"已经发生过多少帧"的运行计数。

  • 引擎主循环自己在推进一个 frame counter。Epic Games Developers

  • A glamorous life can make people forget all of this...

接着是"帧怎么定义"。

是引擎主循环天然就有的边界。UE 文档把 GFrameCounter 定义成"发生过的帧数",说明引擎在运行时一直维护全局 frame ordinal。

所以更底层的理解是:

  • 先有 engine frame:主循环进入新一轮,frame counter 推进。

  • 后有统计归属:这一轮内采到的 CPU scope、thread 时间、以及稍后回读到的 GPU 结果,被写到"frame N"的统计槽。

Frame ms 本身在底层更像什么?更像"相邻两次 frame 边界之间的墙钟跨度"。但显示层不一定直接把这个原始 delta 原封不动打出来。FStatUnitData 同时公开了 RawFrameTimeFrameTime,并且 RenderThreadTime 说明里明确写了"filtered with a simple running average";同类字段也有对应 raw 版。这说明显示值和原始值分离,至少有一层简单平滑/滤波。https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/FStatUnitData?utm_source=chatgpt.com

再说 Game / Draw / RHIT

这几列底层不是"帧头帧尾包住整个线程一刀切测出来"的唯一来源,

接近两类信息的结合:公开能确认的是 Stats System 就是 UE 的统一采集框架,而 FStatUnitData 里甚至有 GameThreadTimeCriticalPathRenderThreadTimeCriticalPath 这种字段。这个命名很关键:说明 stat unit 展示层并不只是累加 scope 时间,还区分了关键路径意义下的线程 frame time

这也解释了为什么 Frame != Game + Draw + GPU,甚至也不总等于 max(Game, Draw, GPU):因为还有线程间等待、同步、present、帧率限制、CPU/GPU pipeline depth、测量窗口错位这些因素。官方 profiling 文档把 frame performance 讲成"按 frame time 看",而不是让你去加总线程列;Frames Panel 也是分开显示 CPU/GPU frame。

CPU 可以立刻读 cycle counter。GPU 不行。GPU 时间通常来自 GPU timestamp query / elapsed query 一类硬件计时查询,命令被插到 GPU 命令流里,等 GPU 真执行到那些点时才会写回时间戳。因此 GPU frame time 的底层流程通常是:

  1. 在某个渲染帧开始/结束处插入 GPU timestamp。

  2. 这些 timestamp 所在命令被 render thread / RHI thread 提交给 GPU。

  3. GPU 在将来某个时刻执行到,产生 begin/end 时间。

  4. CPU 之后再去回读 query 结果。

  5. 把这个结果作为"last frame GPU cycles"写回统计系统。

Epic 的 RHI API 文档直接写了 RHIGetGPUFrameCycles()"Returns the total GPU time taken to render the last frame" ,并说明它和 FPlatformTime::Cycles() 使用同一量纲。这里"last frame"四个字非常关键,它明确表明 GPU 统计不是"当前 CPU 正在处理的 frame 的即时值",而是上一已完成 GPU frame 的回读结果。

你问"如何记录帧为单位的时间跨度",对 GPU 更精确的说法是:

  • 不是 CPU 当场量出来的。

  • 通过 GPU query 追踪一个渲染帧的起止,然后在结果可读时,把 elapsed cycles 归档到那个 frame 的统计槽

  • 因为 GPU 与 CPU 异步,且可能有 1--N 帧 in flight,所以你看到的 GPU ms 在时间线上天然可能比 Game/Draw 落后。

这点和并行渲染架构是连在一起的。Epic 的 Parallel Rendering Overview 明确说了 GameThread、RenderThread、RHI Thread、GPU 之间的同步很复杂,RHI command list 会在这些层之间翻译和提交。

把整条链写成更底层的伪流程,大概就是这样:

Engine frame N begins
GFrameCounter = N

cpu_frame_begin = FPlatformTime::Cycles64()

GameThread work...

many stat scopes record begin/end cycles

RenderThread / RHI work for frame N...

enqueue commands

insert GPU frame begin/end queries for frame N

Engine frame N ends

cpu_frame_end = FPlatformTime::Cycles64()

RawFrameTime[N] = cpu_frame_end - cpu_frame_begin

Later...

GPU finishes frame N query range

RHIGetGPUFrameCycles() / query readback returns elapsed cycles
RawGPUFrameTime[N] = gpu_end - gpu_begin

Display stage
write/update FStatUnitData arrays at CurrentIndex

smooth Raw* -> displayed FrameTime / GameThreadTime / ...

这时你应该能看出两个本质:

第一,"帧"首先是引擎调度概念,不是计时概念。

计时只是附着到这个调度概念上。

第二,CPU 帧时间和 GPU 帧时间的"归档时刻"不同。

CPU 的 raw frame 在 frame loop 结束时马上就能算。GPU 的 raw frame 要等 query 结果成熟后再补写。因此展示层看到的"当前一行 Frame/Game/Draw/GPU"其实是一个经过对齐、缓存、平滑后的逻辑视图,而不是所有数据都在同一个物理时刻瞬时生成。

隐含的那个问题:它为什么能"记录帧为单位的时间跨度",而不是被异步线程打乱?

GPU query延迟回填

底层存的本质不是"毫秒",而是**cycle 差值。**毫秒只是展示换算。

主循环相邻 frame boundary 之间的墙钟跨度,

i see it

enable arcball rotate,这个可以自由旋转

not all question should conclude with a answer,for your target, know something forcely will ruin your balance

稀缺效应

ue里想要两个物体同步变化,只要复制后就会自动同步,如果要断开联系,在transform里单独改就可以。

完全的单独个体单独个体的概念,不存在两个物体有共用的错误

,不对,可能不是自动变化,但是 单独个体的概念依然是存在的,是好事

个体的概念还是很显眼

An imposter (or impostor) is

a person who pretends to be someone else to deceive others, typically for fraudulent gain, attention, or to evade detection . It refers to a fraud, phony, or pretender who falsifies their identity, such as a "ringer" in a competition or a con artist.

Camouflage is the use of materials, coloration, or illumination to conceal or disguise, making animals or objects blend into their surroundings to avoid detection . It serves to hide, protect, or deceive, ranging from natural, cryptic coloration in animals to artificial, military-grade concealment of equipment.
Psychology is

the scientific study of the mind and behavior, exploring conscious and unconscious mental processes, thoughts, feelings, and motivations . It bridges natural and social sciences to understand individual and group actions, including human development, sports, health, and clinical treatment.

相关推荐
charlie1145141913 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(3)WSL2 USB 透传,让 ST-Link 穿越虚拟化边界
c++·stm32·单片机·学习·嵌入式
AI成长日志3 小时前
【datawhale】hello agents开源课程学习记录第6章:智能体框架开发实践
学习·开源
東雪木4 小时前
Java学习——重载 (Overload) 与重写 (Override) 的核心区别、底层实现规则
java·开发语言·jvm·学习·java面试
zl_dfq4 小时前
Python学习4 之 【函数】(函数的相关语法、下划线的使用、global与nonlocal关键字)
python·学习
承渊政道4 小时前
【优选算法】(实战剖析链表核心操作技巧)
开发语言·数据结构·c++·vscode·学习·算法·链表
li星野4 小时前
DeepSeek-V3介绍
学习
正经人_x5 小时前
学习日记36:TokenSeg
学习
VelinX5 小时前
【个人学习||spring boot】
spring boot·后端·学习
计算机安禾5 小时前
【数据结构与算法】第20篇:二叉树的链式存储与四种遍历(前序、中序、后序、层序)
c语言·开发语言·数据结构·c++·学习·算法·visual studio