投掷物轮盘菜单是一个专门用于快速切换投掷物(手雷等)的径向菜单,可以让你在战斗中快速选择和装备投掷物。
- 按住 配置的热键(默认
G键,可在设置中修改)打开菜单 - 保持按住 热键的同时,移动鼠标选择投掷物
- 释放 热键,自动装备当前选中的投掷物
💡 提示:这是一个"按住-选择-释放"的操作流程,类似于 GTA5 的武器轮盘
- 按住热键后,移动鼠标指向你想要使用的投掷物
- 鼠标移出中心死区后,会高亮显示当前指向的投掷物扇区
- 高亮的扇区会放大并变亮,表示已选中
- 游戏暂停时会自动取消菜单
- 打开其他界面(背包、地图等)时会自动取消菜单
- 在死区内释放热键不会触发任何物品
投掷物轮盘菜单显示你背包中所有的投掷物(手雷等技能物品):
[手雷A]
[手雷B] [闪光弹]
●
[烟雾弹] [燃烧弹]
[...]
- 中心的 ● 是死区,鼠标在这里不会选中任何物品
- 每个扇区显示一种投掷物的图标
- 右下角显示该投掷物的总数量(叠加计算)
- 相同类型的投掷物会自动堆叠显示
✅ 实时同步:显示当前背包中实际的投掷物
✅ 视觉反馈:悬停时扇区高亮,清晰指示当前选择
✅ 智能关闭:打开背包、地图等界面时自动取消
✅ 快速操作:单手操作,无需离开游戏视角
✅ 输入隔离:菜单打开时自动屏蔽射击、移动、视角旋转等输入,防止误操作
✅ 可自定义:支持在设置中修改热键和菜单缩放
✅ 自动堆叠:相同类型的投掷物自动合并显示,显示总数量
-
投掷物类型检测:
- ✅ 检测所有技能类型物品(
IsSkill= true) - ✅ 必须是投掷技能(
Skill_Grenade类型) - ❌ 非投掷技能不会显示
- ✅ 检测所有技能类型物品(
-
死区设计:中心有一个小死区
- 鼠标在死区内不会选中任何物品
- 在死区内释放热键不会触发任何操作
- 可以安全地移动鼠标而不误触
-
输入屏蔽:菜单打开时会自动屏蔽以下操作
- ❌ 鼠标移动影响视角(镜头旋转)
- ❌ 射击/开火输入
- ✅ 键盘移动仍然可用(WASD)
-
与其他界面的交互:
- 如果有其他 UI 窗口打开(背包、地图、暂停菜单等),轮盘菜单无法打开
- 菜单打开时如果游戏暂停或打开其他界面,会自动取消菜单
-
物品堆叠:
- 相同 TypeID 的投掷物会自动堆叠
- 显示总数量(包括所有相同类型物品的 StackCount 总和)
- 使用时会优先使用列表中的第一个物品
可以在游戏设置界面中调整以下参数:
| 设置项 | 默认值 | 说明 |
|---|---|---|
| 投掷物轮盘启用 | ✓ 启用 | 是否启用投掷物轮盘菜单功能 |
| 投掷物轮盘热键 | G (KeyCode.G) |
打开轮盘菜单的快捷键,可自定义 |
| 轮盘缩放 | 1.0 | 菜单的整体大小,范围 0.5 - 2.0(与物品轮盘共用) |
PieMenuComponent(Utils/UI/Components/PieMenuComponent.cs) - 通用饼状菜单组件ThrowableWheelMenu(Features/ThrowableWheelMenu.cs) - 投掷物轮盘功能实现ThrowableWheelMenuPatch(Patches/ThrowableWheelMenuPatch.cs) - Harmony 补丁,处理输入和集成
- 用户按下配置的热键(默认 G 键)
ThrowableWheelMenuPatch检测按键事件,调用ThrowableWheelMenu.Show()ThrowableWheelMenu扫描角色背包获取所有投掷物数据- 使用
IsThrowableItem()检测投掷物(IsSkill+Skill_Grenade) - 按 TypeID 自动堆叠相同类型的投掷物
- 计算总数量(所有 StackCount 之和)
- 使用
PieMenuComponent渲染饼状菜单并处理鼠标悬停- 用户释放热键时,装备选中的投掷物(调用
Character.ChangeHoldItem()) - 补丁屏蔽游戏的射击、视角旋转输入,防止误操作
private bool IsThrowableItem(Item item)
{
// 1. 检查是否为技能物品
if (!item.GetBool("IsSkill")) return false;
// 2. 获取技能设置组件
ItemSetting_Skill skillSetting = item.GetComponent<ItemSetting_Skill>();
if (skillSetting == null) return false;
// 3. 检查是否为投掷技能
return skillSetting.Skill is Skill_Grenade;
}// 按 TypeID 分组堆叠
Dictionary<int, ThrowableStack> stacksByTypeID;
// ThrowableStack 结构
class ThrowableStack {
string TypeID; // 物品类型ID
List<Item> Items; // 该类型的所有物品实例
Sprite Icon; // 物品图标
string DisplayName; // 显示名称
int TotalCount; // 总数量(所有StackCount之和)
}补丁会拦截以下游戏输入方法:
CharacterInputControl.OnPlayerMouseDelta- 屏蔽视角旋转CharacterInputControl.OnPlayerMouseMove- 屏蔽瞄准移动CharacterInputControl.OnPlayerTriggerInputUsingMouseKeyboard- 屏蔽射击输入
通过事件监听自动取消菜单:
Duckov.UI.View.OnActiveViewChanged- 检测界面切换PauseMenu.Show- 检测游戏暂停GameManager.Paused- 轮询检测暂停状态
当菜单打开时,会清理积累的输入状态,防止鼠标移动影响镜头:
// 清理 mouseDelta 字段(防止镜头突然旋转)
mouseDeltaField.SetValue(inputControl, Vector2.zero);
// 重置 mousePos 字段到当前鼠标位置
mousePosField.SetValue(inputControl, currentMousePosition);| 特性 | 物品轮盘 | 投掷物轮盘 |
|---|---|---|
| 默认热键 | ~ (Backquote) |
G (KeyCode.G) |
| 物品来源 | 快捷栏物品(1-6键绑定) | 背包中所有投掷物 |
| 物品类型 | 消耗品、技能、手持物品 | 仅投掷物(Skill_Grenade) |
| 物品数量 | 固定6个位置 | 动态(有多少显示多少) |
| 堆叠行为 | 不堆叠 | 自动按TypeID堆叠 |
| 数量显示 | 单个物品StackCount | 总StackCount(所有同类型之和) |
| 使用行为 | 使用/装备物品 | 装备投掷物(ChangeHoldItem) |
| 菜单缩放 | 共用设置 | 共用设置 |
- 检查设置中"投掷物轮盘启用"是否开启
- 确认是否有其他 UI 界面已经打开(背包、地图等)
- 确认游戏没有暂停
- 检查热键是否被其他程序占用
- 查看日志文件:运行
scripts/rlog.sh或查看游戏日志
- 确认背包中确实有投掷物(手雷等技能物品)
- 检查物品是否为
Skill_Grenade类型 - 确认物品有
IsSkill属性且为 true - 查看日志了解具体检测结果
- 确保鼠标移出了中心死区(否则不会选中任何物品)
- 确认扇区已经高亮显示(表示已选中)
- 检查角色是否可以切换物品(可能在其他动作中)
- 查看日志了解具体错误信息
- 确认角色装备栏已经切换到投掷物
- 检查是否需要再次按使用键(游戏原生操作)
- 查看日志中的
ChangeHoldItem调用结果
如果你在使用过程中遇到问题,或有改进建议,可以:
- 查看模组日志了解详细错误信息
- 在项目 GitHub 页面提交 Issue
- 提供复现步骤和日志文件以便排查
祝游戏愉快! 🎮