Skip to content

Add hand visualization and recording/playback system for single player mode - #2

Draft
wuzhi456 with Copilot wants to merge 11 commits into
mainfrom
copilot/visualize-hand-joint-data
Draft

Add hand visualization and recording/playback system for single player mode#2
wuzhi456 with Copilot wants to merge 11 commits into
mainfrom
copilot/visualize-hand-joint-data

Conversation

Copilot AI commented Dec 10, 2025

Copy link
Copy Markdown

Implements hand joint visualization (spheres for joints, cylinders for bones) with three game modes: normal play, recording mode (captures hand data), and playback mode (replays recorded hand data as a guide).

Changes

New Files

  • HandPoseData.swift: Data models for hand pose recording (HandJointPose, HandPoseFrame, HandPoseRecording) with bone connection definitions
  • HandCaptureManager.swift: Recording/playback manager with timestamped JSON persistence (saves as HandPose_YYYYMMDD_HHmmss.json)
  • HandVisualization.swift: RealityKit-based hand skeleton renderer using sphere meshes (joints) and cylinder meshes (bones)

Modified Files

  • GameModel.swift: Added SoloGameMode enum (.normal, .recording, .playback) and playbackRecording state
  • Start.swift: Mode selection UI with recordings list from app's Documents directory, including delete functionality with confirmation dialog
  • SoloPlay.swift: Recording/playback status indicator
  • HappyBeamSpace.swift: Integrated visualization and capture logic in RealityView update cycle

Features

  • Fixed "floating joints" issue: now properly hides all joint and bone entities when hands are not detected
  • Fixed recordings list buttons: changed to use standard .bordered buttonStyle for proper visionOS eye-tracking and hand interaction
  • Added renderOnTop mode for recording visualization: spheres/cylinders now render on top of user's hands for easier debugging
  • Added joint interpolation: uses last known positions for temporarily occluded joints to prevent partial hand model
  • Added delete functionality: each recording now has a trash button with confirmation dialog to remove unwanted recordings
Original prompt

当前的项目要求是:1.用户在游玩单人模式时手部关节信息可视化(用球代表关节,棍代表指节);2.用户可以选择记录一整局游戏中自己的手部动作数据;3.用户在游玩单人模式时可以选择已有的手部数据进入游戏,以这种方式进入游戏时,在新的一局游戏开始时,复现之前记录的手部数据,期望是用户在单人游戏的同时还可以看到可视化的手部数据(比如用球代表关节,棍代表指节的手)来指导用户进行游玩,球和棍的样式无需自定义,不需要区分不同手指;进入单人模式后应当有三种选项,第一种是正常游玩(已实现),第二种是记录模式,仅用显示用户自己的手部,第三种是回放模式,只显示回放数据的手部;球/棍无需可点击或高亮反馈;手部动作数据,按时间帧记录这个项目是一个在vision pro这种VR设备上以swiftui写的项目,只要是可兼容的手部动作数据记录的数据格式都可以;本地保存按日期时间作为名称保存;回放模式下严格按原时间轴复现;用户在回放模式下仍可以控制自己的手进行游玩,复现的数据将仅作为示范在游戏中播放,不影响游戏本身,也就是说回放模式和正常游玩模式完全一样,唯一的区别只有回放模式下用户游玩时会播放之前记录的手部数据,这些手部数据不影响游戏;以上是补充信息,帮我整理成更详细的prompt,如何实现。


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits December 10, 2025 03:35
…r mode

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
…tation

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
Copilot AI changed the title [WIP] Add hand joint information visualization in single player mode Add hand visualization and recording/playback system for single player mode Dec 10, 2025
Copilot AI requested a review from wuzhi456 December 10, 2025 03:40
@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 现在我想要知道为了测试你的改动是否有效,我需要用xcode运行哪一个项目文件

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 现在我想要知道为了测试你的改动是否有效,我需要用xcode运行哪一个项目文件

您需要用 Xcode 打开 HappyBeam.xcodeproj 项目来测试这些改动。所有的更改都在 HappyBeam 项目中,包括:

  • HappyBeam/GameModel.swift - 游戏模式枚举
  • HappyBeam/Views/Start.swift - 模式选择界面
  • HappyBeam/Views/SoloPlay.swift - 状态指示器
  • HappyBeam/HappyBeamSpace.swift - 手部可视化集成
  • HappyBeam/Gameplay/HandPoseData.swift - 数据模型
  • HappyBeam/Gameplay/HandCaptureManager.swift - 录制/回放管理
  • HappyBeam/Gameplay/HandVisualization.swift - 手部骨架渲染

运行后,在开始界面点击 "Play Solo" 会显示三个选项:Normal Play(正常游玩)、Recording Mode(录制模式)、Playback Mode(回放模式)。

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 手部数据会被存储什么格式的文件

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 手部数据会被存储什么格式的文件

手部数据存储为 JSON 格式文件,文件名按日期时间命名,格式为:HandPose_YYYYMMDD_HHmmss.json

例如:HandPose_20251210_153042.json

文件存储在应用的 Documents 目录中。数据结构如下:

{
  "version": 1,
  "createdAt": "2025-12-10T15:30:42Z",
  "frames": [
    {
      "timestamp": 0.0,
      "leftJoints": [
        {"name": "wrist", "position": [x, y, z], "orientation": [x, y, z, w]},
        {"name": "thumbKnuckle", "position": [...], "orientation": [...]}
        // ... 其他关节
      ],
      "rightJoints": [...]
    }
  ]
}

每个 frame 包含时间戳和左右手所有关节的位置/旋转信息。

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 现在我在本地运行时报编译错误,gamemodel中找不到HandPoseRecording

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 现在我在本地运行时报编译错误,gamemodel中找不到HandPoseRecording

这个错误是因为新创建的 Swift 文件没有被自动添加到 Xcode 项目中。您需要手动将以下三个新文件添加到 HappyBeam 项目:

  1. 在 Xcode 中打开 HappyBeam.xcodeproj
  2. 在项目导航器中右键点击 HappyBeam/Gameplay 文件夹
  3. 选择 Add Files to "HappyBeam"...
  4. 选择以下三个文件:
    • HandPoseData.swift
    • HandCaptureManager.swift
    • HandVisualization.swift
  5. 确保勾选 "Copy items if needed""Add to targets: HappyBeam"
  6. 点击 Add

添加完成后重新编译项目即可解决这个错误。

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 现在handvisulization里有两处 let material = SimpleMaterial(color: SimpleMaterial.Color(Color(uiColor: jointColor)), roughness: 0.15, isMetallic: false)会报找不到'Color'

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 现在handvisulization里有两处 let material = SimpleMaterial(color: SimpleMaterial.Color(Color(uiColor: jointColor)), roughness: 0.15, isMetallic: false)会报找不到'Color'

已修复。问题是使用了 SwiftUI 的 Color 类型但没有导入 SwiftUI。现在直接使用 UIColor 传递给 SimpleMaterial,因为它本身就支持 UIColor

修复提交: 203384f

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 我现在不知道如果记录模式下成功记录下手部数据,对应的json文件存在哪里

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 我现在不知道如果记录模式下成功记录下手部数据,对应的json文件存在哪里

JSON 文件存储在应用的 Documents 目录中。具体路径取决于运行环境:

在 Vision Pro 真机上:

  • 路径类似:/var/mobile/Containers/Data/Application/<APP-UUID>/Documents/HandPose_YYYYMMDD_HHmmss.json
  • 可通过 Xcode → Window → Devices and Simulators → 选择设备 → 选择 HappyBeam 应用 → 下载 Container 来访问

在模拟器上:

  • 路径类似:~/Library/Developer/CoreSimulator/Devices/<DEVICE-UUID>/data/Containers/Data/Application/<APP-UUID>/Documents/

查看保存状态:
代码中有 print("Recording saved: \(url.path)") 语句,录制成功后会在 Xcode 控制台输出完整路径。

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 现在Select Recording" 标题
"Found 7 recordings" 计数"Import from Files" 按钮
"Back" 按钮这些都有,但是没有7个可点击的录制文件按钮(如 HandPose_20251211_142459)

…ing and debug logs

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 现在Select Recording" 标题
"Found 7 recordings" 计数"Import from Files" 按钮
"Back" 按钮这些都有,但是没有7个可点击的录制文件按钮(如 HandPose_20251211_142459�...

已修复。问题可能是 SwiftUI 的按钮在 VisionOS 上渲染问题。我做了以下更改:

  1. 改用 ForEach(Array(savedRecordings.enumerated()), id: \.offset) 确保正确遍历
  2. 为按钮添加了蓝色背景和圆角,使其更可见
  3. 使用 .buttonStyle(.plain) 避免样式冲突
  4. 增加了调试日志,选择录制时会输出 Selected recording: xxx

请重新测试,现在录制文件按钮应该有蓝色背景,更容易看到和点击。

修复提交: 0274a9f

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot if savedRecordings.isEmpty {
Text("No recordings found")
.foregroundColor(.secondary)
.padding()
} else {
// Show recording buttons directly without ScrollView to debug
VStack(spacing: 8) {
ForEach(Array(savedRecordings.enumerated()), id: .offset) { index, url in
Button {
print("Selected recording: (url.lastPathComponent)")
loadAndStartPlayback(from: url)
} label: {
Text(url.deletingPathExtension().lastPathComponent)
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
.background(Color.blue.opacity(0.2))
.cornerRadius(8)
}
.buttonStyle(.plain)
}
}
.frame(maxHeight: 200)
}经过你的修改,的确可以看到之前这些按钮,尽管他们全堆在一起了,但是这些按钮按后并没有反应

…nOS interaction

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot if savedRecordings.isEmpty {
Text("No recordings found")
.foregroundColor(.secondary)...

已修复两个问题:

1. 按钮堆叠问题

  • 增加了按钮间距 (spacing: 12)
  • 使用 ScrollView 并设置动态高度

2. 按钮无响应问题

  • 问题是 .buttonStyle(.plain) 在 visionOS 上不支持眼动追踪交互
  • 改为使用 .buttonStyle(.bordered),这是 visionOS 标准按钮样式,支持眼动追踪 + 手势确认

请重新测试,按钮现在应该:

  • 有适当的间距
  • 使用标准 visionOS 按钮外观
  • 可以正常点击并加载录制文件

点击按钮时控制台应输出 Button tapped for: xxx

修复提交: 66cf934

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 我觉得你可以把手部数据json文件存储位置改成该项目文件夹下一个专门用来存手部数据的文件夹

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 我觉得你可以把手部数据json文件存储位置改成该项目文件夹下一个专门用来存手部数据的文件夹

关于存储位置的说明:

在 iOS/visionOS 上,应用只能写入自己的沙盒目录(如 Documents),无法写入项目文件夹(项目文件夹在您的 Mac 上,而应用运行在 Vision Pro 设备上)。

当前方案:文件存储在应用的 Documents/ 目录,这是标准做法。

可以改进的方案

  1. 在 Documents 下创建专门的子文件夹,如 Documents/HandPoseRecordings/
  2. 或者使用 App Group 共享目录,使文件可被其他应用访问

您是希望我创建一个专门的子文件夹来组织这些录制文件吗?例如:

  • Documents/HandPoseRecordings/HandPose_20251211_142459.json

这样可以让录制文件更有组织,也更容易管理。

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 现在playback成功了但是发现之前记录的手部数据中一旦某些关节被遮挡,手部模型会部分缺失,有没有什么办法,可以预测或者补全被遮挡关节;除此之外,我希望在recording mode下,球棍模型不应该被用户的手挡住,不然调试的时候看不到关节是否都绑对了

…ion for missing joints

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 现在playback成功了但是发现之前记录的手部数据中一旦某些关节被遮挡,手部模型会部分缺失,有没有什么办法,可以预测或者补全被遮挡关节;...

已修复两个问题:

1. 遮挡关节补全

  • 添加了 interpolateMissing 参数,当关节被遮挡时,使用上一帧的已知位置来补全
  • 在录制和回放模式下都启用了插值功能
  • 注意:录制时仍保存实际检测到的关节,插值仅用于可视化

2. Recording 模式下可视化不被手遮挡

  • 为录制模式的可视化添加了 renderOnTop: true 参数
  • 使用 UnlitMaterialModelSortGroupComponent 使球棍始终渲染在最前面
  • 这样您可以清楚看到关节是否正确绑定

修复提交: 7228132

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 我现在需要增加一个删除之前的记录的手部数据json文件的功能

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 我现在需要增加一个删除之前的记录的手部数据json文件的功能

已添加删除功能。现在每个录制文件旁边都有一个红色垃圾桶按钮:

  1. 点击垃圾桶按钮会弹出确认对话框
  2. 确认后文件会被永久删除
  3. 列表会自动刷新

修复提交: 9832e91

@wuzhi456

Copy link
Copy Markdown
Owner

@copilot 我现在想修改一下UI,告诉我每个界面的ui对应的控制代码在哪里就行

Copilot AI commented Dec 11, 2025

Copy link
Copy Markdown
Author

@copilot 我现在想修改一下UI,告诉我每个界面的ui对应的控制代码在哪里就行

UI 控制代码位置如下:

主要界面文件:

  • HappyBeam/Views/Start.swift - 开始界面(包含 Play Solo 按钮、三种模式选择、录制文件列表选择界面)
    • soloModeSelectionView - 三种模式选择按钮
    • recordingsListView - 回放模式的文件选择列表
  • HappyBeam/Views/SoloPlay.swift - 单人游戏界面(包含录制/回放状态指示器)
  • HappyBeam/HappyBeamSpace.swift - 3D 空间界面(手部可视化的 RealityView)

手部可视化相关:

  • HappyBeam/Gameplay/HandVisualization.swift - 球棍模型的创建和更新

状态管理:

  • HappyBeam/GameModel.swift - soloGameModeplaybackRecording 状态变量

wuzhi456 pushed a commit that referenced this pull request Dec 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants