Я создаю игру на C ++ и испытываю перетаскивание ввода, когда использую клавиатуру в качестве устройства ввода для управления плеером. В идеальных условиях ввод работает достаточно хорошо, но когда мой компьютер перегружен другими программами, производительность ухудшается, и проигрыватель постепенно теряет синхронизацию c при нажатии клавиш. Чем дольше я удерживаю клавишу направления, тем больше «ввода», похоже, сохраняется в компьютере.
Если я, например, удерживаю «S», чтобы двигаться вниз в течение нескольких секунд, а затем нажимаю клавишу go, игрок продолжает движение вниз через несколько секунд после отпускания, прежде чем остановиться. Если я удерживаю «S», а затем «D», игрок перемещается вниз на несколько секунд, а затем вправо на несколько секунд, отвечая увеличивающейся задержкой в зависимости от того, как долго удерживались клавиши. Дальнейший ввод правильно фиксируется, но все испытывают одно и то же перетаскивание: игрок движется, как ожидалось, , он делает это так долго после нажатия клавиши и гораздо дольше, чем удерживается клавиша.
Если я позволю воспроизвести все входные данные и игрок остановится, проблема возобновится - сначала игрок реагирует, но медленно теряет синхронизацию c с клавишами. Задержка увеличивается, чем дольше я удерживаю клавиши, и не появляется / становится заметным, если вместо этого нажимаю только клавиши, заставляя меня верить, что очередь заполняется событиями, которые не очищаются достаточно быстро, когда мой компьютер работает медленно. Я подозревал, что это может быть очередь событий SDL, но не смог ее обработать sh после прохождения основного l oop.
Интересно, что я кодировал игру, чтобы использовать контроллер в качестве дополнительного устройства ввода , Независимо от того, насколько плохо работает мой компьютер, проигрыватель всегда немедленно реагирует на ввод с контроллера и не страдает от перетаскивания ввода, как клавиатура. Если я перемещаю ручку вправо, игрок двигается вправо, и если я наклоняю или отпускаю ручку, игрок немедленно меняет направление или останавливается, как и ожидалось.
Я считаю, что управляемые событиями клавиши замедляются низкая производительность, в то время как управляемый опросом контроллер не страдает от того же самого эффекта. Я попытался очистить очередь событий SDL, обновить ее, очистить, вытащить все входы из нее, но пока мне не повезло.
Ниже мое событие l oop, с некоторыми разделы удалены. Удаленные части - это главным образом логи c рендеринга, рисования и обновления сущностей, которые выгружаются в другие классы; Логика c для прицеливания также опущена, так как в остальном она идентична движению (нажмите клавишу для наведения в этом направлении).
const Uint8* keystate = SDL_GetKeyboardState(NULL);
while(!quit) {
//==== PLAYER INPUT here ======================================================
//get the keystate
SDL_PumpEvents();
if(pause) { /*pause menu*/ }
else {
//-----------------------------------------------------------------------------
//this section does not protect against keybounce - ideally, it is checking at
//each frame, about every 20 ms (delta time is taken care of elsewhere).
//it feels like a "queue" is being built up of inputs that isn't emptied
//out in real time.
//no keybounce protection
//handle movement
if(keystate[SDL_SCANCODE_W])
{ e_handler::get().move_player(e_handler::UP); }
if(keystate[SDL_SCANCODE_A])
{ e_handler::get().move_player(e_handler::LF); }
if(keystate[SDL_SCANCODE_S])
{ e_handler::get().move_player(e_handler::DN); }
if(keystate[SDL_SCANCODE_D])
{ e_handler::get().move_player(e_handler::RT); }
if(keystate[SDL_SCANCODE_LSHIFT])
{ e_handler::get().boost_player(true); }
//(some other keystate sampling for aiming and shooting)
//-----------------------------------------------------------------------------
//this section is an optional alternative for when a controller is plugged in.
//even when my computer is running slowly, there's never any delay in input
//here - the program responds immediately to controller controls.
if(controller) {
//process controller input
vec2d lrud(
SDL_JoystickGetAxis(controller, LSTICK_LR),
SDL_JoystickGetAxis(controller, LSTICK_UD)
);
if(abs(lrud[0]) > CONTROLLER_DEADZONE) {
if(lrud[0] < 0) { e_handler::get().move_player(e_handler::LF); }
else { e_handler::get().move_player(e_handler::RT); }
}
if(abs(lrud[1]) > CONTROLLER_DEADZONE) {
if(lrud[1] < 0) { e_handler::get().move_player(e_handler::UP); }
else { e_handler::get().move_player(e_handler::DN); }
}
}
}
//-----------------------------------------------------------------------------
//this section has keybounce protection, to prevent the game from, for
//example, pausing and unpausing extremely quickly when "P" is pressed.
//supposedly, while(SDL_PollEvent(&e) != 0) is supposed to empty out the event
//queue, so i'm not sure if it really *is* the event queue that's causing the
//input dragging issue.
while(SDL_PollEvent(&e) != 0) {
//get an event: protect from keybounce
if(e.type == SDL_QUIT) { quit = true; }
else if(e.type == SDL_KEYDOWN) {
//pause unpause
if(keystate[SDL_SCANCODE_P]) { pause = !pause; }
if(pause || !pause) { //TODO: remove this / update it
//pause menu
if(keystate[SDL_SCANCODE_ESCAPE]) { quit = true; }
}
if(keystate[SDL_SCANCODE_O]) {
//TODO: make "tryjump" in map handler
if(map_h::get().debug_jump(e_handler::get().get_player_pos())) {
//jumped
e_handler::get().teleport_player_new_map();
}
}
//draw debug things
if(keystate[SDL_SCANCODE_PERIOD]) {
e_handler::get().set_draw_debug_info(
!e_handler::get().get_draw_debug_info()
);
}
}
}
//-----------------------------------------------------------------------------
//updating and drawing happens down here
}
Есть ли решение этой проблемы? Если нет, я планирую переключиться на опрос клавиатуры один раз в каждом кадре.