ISSUE-008
Unity默认键位卡手问题
常见表现
游戏自带键位支持但存在一些问题,例如:WASD走不动路、按键无法长按、按键无法连点。
相关源码
Unity引擎 UnityView+Keyboard.mm
static const double kKeyTimeoutInSeconds = 0.5;
- (void)processKeyboard
{
KeyMap& map = GetKeyMap();
if (map.size() == 0)
return;
std::vector<int> keysToUnpress;
double nowTime = GetTimeInSeconds();
for (KeyMap::iterator item = map.begin();
item != map.end();
item++)
{
// Key has expired, register it for key up event
if (nowTime - item->second > kKeyTimeoutInSeconds)
keysToUnpress.push_back(item->first);
}
for (std::vector<int>::iterator item = keysToUnpress.begin();
item != keysToUnpress.end();
item++)
{
map.erase(*item);
UnitySetKeyboardKeyState(*item, false);
}
}
原因分析
在Unity引擎中可以通过两种方式去捕获键盘输入,一种是使用旧的API,即Input.GetKeyDown(),另一种是使用最新的Input System Package方式。如果游戏选择使用旧的API,就会出现键位卡手的问题。
iOS系统从14.0开始才有提供访问键盘设备的API,即GCKeyboard。而在此之前Unity就已经写好了UnityView+Keyboard.mm,只不过Unity是通过UIKeyCommand取巧的方式来实现的。
UIKeyCommand只支持监听按键按下事件,并不支持按键抬起事件。Unity则通过“0.5秒后自动松开”来模拟按键抬起,也就造成了游戏过程中按键卡手的情况。
解决方法
玩家方面:通过PlayCover的按键映射去覆盖默认键位。
开发者方面:使用GCKeyboard API重写UnityView+Keyboard.mm。
有一份现成的版本:gist,但这个版本不支持设备断开重连,通过GCKeyboardDidConnectNotification和GCKeyboardDidDisconnectNotification可以监听到设备断开重连。