wiliwili游戏手柄振动波形:自定义模式
wiliwili作为专为手柄控制设计的跨平台B站客户端,不仅在视频播放体验上进行了优化,还通过手柄振动反馈增强了用户交互沉浸感。本文将深入解析其振动波形自定义系统的实现原理,帮助开发者创建个性化振动模式。
振动系统核心架构
振动功能主要由VibrationHelper单例类实现,通过C++标准线程库控制振动时序,支持多平台振动输出。核心代码位于:
该系统采用波形数据驱动架构,通过预定义振动序列实现不同场景的反馈效果,如硬币获取、加载等待等系统默认模式。
振动数据结构解析
振动数据使用VibrationData类型定义,本质是一个二维浮点数组:
typedef std::vector<std::vector<float>> VibrationData;
每个子数组包含四个参数,构成一个振动帧:
- 参数1:低频马达频率(Hz)
- 参数2:高频马达频率(Hz)
- 参数3:低频马达振幅(0.0-1.0)
- 参数4:高频马达振幅(0.0-1.0)
系统默认提供两种振动模式:
硬币获取振动
VibrationData VibrationHelper::coinVibrationData = {
{160, 1000, 0, 0.87}, {160, 1000, 0, 0.98}, {160, 1000, 0, 0.97},
// ... 共48帧振动数据
};
这段代码定义了类似"硬币碰撞"的振动效果,通过高频马达(1000Hz)的振幅变化模拟硬币滚落的层次感。完整波形数据可查看振动实现文件。
等待状态振动
VibrationData VibrationHelper::waitVibrationData = {
{140, 146.5, 0.14, 0.14},
{160, 320, 0, 0},
{160, 320, 0, 0},
{160, 320, 0, 0},
};
这是一种周期性振动模式,通过140Hz低频振动与静默帧交替,产生"呼吸感"的等待提示。
振动控制流程
振动播放通过startVibrate方法实现,核心流程如下:
- 检查振动总开关
GAMEPAD_VIBRATION状态 - 停止当前正在播放的振动序列
- 创建新线程处理振动帧播放
- 按顺序发送振动指令到硬件
关键实现代码:
void VibrationHelper::startVibrate(const VibrationData& data, bool loop) {
if (!GAMEPAD_VIBRATION) return;
this->stop();
this->playing = true;
#ifdef __SWITCH__
playThread = std::thread([&data, loop, this]() {
auto manager = (brls::SwitchInputManager*)brls::Application::getPlatform()->getInputManager();
do {
for (auto& i : data) {
if (!this->playing) break;
std::this_thread::sleep_for(std::chrono::milliseconds(16));
manager->sendRumbleRaw(i[0], i[1], i[2], i[3]);
}
} while (this->playing && loop);
manager->sendRumbleRaw(160, 320, 0, 0); // 停止振动
});
#endif
}
该方法支持两种播放模式:单次播放(默认)和循环播放(通过loop=true启用),振动线程会以16ms的固定间隔发送振动指令,确保波形平滑输出。
自定义振动模式开发指南
开发者可以通过以下步骤创建自定义振动模式:
1. 定义振动序列
创建新的VibrationData对象,按时间顺序排列振动帧:
// 示例:创建"心跳"振动模式
VibrationData heartbeatVibration = {
{160, 320, 0.8, 0.2}, // 强振动
{160, 320, 0, 0}, // 静默
{160, 320, 0, 0},
{160, 320, 0.8, 0.2}, // 强振动
{160, 320, 0, 0},
{160, 320, 0, 0},
{160, 320, 0, 0},
{160, 320, 0, 0},
};
2. 调用振动播放接口
通过VibrationHelper单例调用播放方法:
// 单次播放
VibrationHelper::getInstance()->startVibrate(heartbeatVibration);
// 循环播放(如加载中)
VibrationHelper::getInstance()->startVibrate(heartbeatVibration, true);
3. 停止振动
在不需要振动时及时停止,避免资源占用:
VibrationHelper::getInstance()->stop();
多平台振动支持现状
当前振动系统主要针对Nintendo Switch平台实现,代码中通过条件编译隔离平台相关代码:
#ifdef __SWITCH__
// Switch平台振动实现
auto manager = (brls::SwitchInputManager*)brls::Application::getPlatform()->getInputManager();
manager->sendRumbleRaw(i[0], i[1], i[2], i[3]);
#endif
其他平台(如PSVita、PS4)的振动支持可参考Switch实现,通过对应平台的输入管理器发送振动指令。平台相关代码组织在:
- Switch平台:wiliwili/source/utils/vibration_helper.cpp#L43-L55
- 通用接口:wiliwili/include/utils/vibration_helper.hpp
实践案例:弹幕互动振动
将弹幕飘过屏幕的事件与振动反馈结合,可创建沉浸式观看体验:
// 伪代码示例:弹幕振动反馈
void onDanmakuReceived(Danmaku danmaku) {
VibrationData vibration;
// 根据弹幕颜色确定振动强度
float intensity = danmaku.colorBrightness / 255.0f;
// 创建单帧振动
vibration.push_back({160, 800, 0, intensity});
// 播放振动
VibrationHelper::getInstance()->startVibrate(vibration);
}
这种动态生成振动数据的方式,可以让用户"感受"到弹幕互动,增强观看体验。
总结与扩展方向
wiliwili的振动系统通过灵活的数据驱动设计,为多平台手柄提供了统一的振动控制方案。未来可从以下方向扩展:
- 振动配置文件:支持从JSON文件加载自定义振动模式
- 波形编辑器:在设置界面添加可视化振动波形编辑工具
- 音频同步振动:分析音频波形生成同步振动效果
- 多设备同步:支持多手柄同时振动(如双人观看场景)
振动功能相关代码持续维护在utils模块中,欢迎开发者贡献更多创意振动模式和平台支持。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



