Такая проблемка: В проге есть объект- игрок, он умеет двигаться. И вот, при зажатой клавише W,A,S,D он начинает двигаться с небольшой задержкой(как с backspace). Так же он не может двигаться по диагонали + Если была зажата какая-либо клавиша, и далее нажата другая, при том, что первая не отпускалась, он станет игнорировать последующие удержание первой клавиши. Как сделать так, чтобы можно было удерживать клавишу, даже если нажал другую? Эта функция вызывается, пока прога открыта.
void Game::handleEvents() {
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
isRunning = false;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_w:
player->Move(0, -5);
break;
case SDLK_a:
player->Move(-5, 0);
break;
case SDLK_s:
player->Move(0, 5);
break;
case SDLK_d:
player->Move(5, 0);
break;
case SDLK_ESCAPE:
isRunning = false;
break;
default:
break;
}
case SDL_KEYUP:
break;
default: break;
}
};
Во-первых, не используйте event.key.keysym.sym
для управления в играх!
Это значение зависит от текущей раскладки (QWERTY или AZERTY или что-то еще). Это удобно для ввода текста, но неудобно для игр. У какого-нибудь француза с раскладкой AZERTY клавиша W
окажется непонятно где (там, где обычно расположена Z
), и нажимать на нее станет сложно.
Используйте event.key.keysym.scancode
и константы SDL_SCANCODE_<буква>
, у них такого недостатка нет.
Scancode связаны с физическим расположением кнопок на клавиатуре. Например SDL_SCANCODE_W
соответствует W
на QWERTY и Z
на AZERTY.
Во-вторых, проверяйте значение event.key.repeat
:
Если 0
, то это обычное нажатие на клавишу.
Если не 0
, то это "фальшивое" нажатие, вызванное долгим удерживанием клавиши. Такие события вам не нужны, игнорируйте их.
В-третьих:
Заведите себе массив (размера SDL_NUM_SCANCODES
, например из bool
), и храните в нем состояние каждой кнопки: нажата или нет. В обработчиках событий меняйте содержимое массива, но не двигайте игрока.
Скажем,
bool buttons[SDL_NUM_SCANCODES] {};
// ...
case SDL_KEYDOWN:
if (event.key.repeat == 0)
buttons[event.key.keysym.scancode] = true;
break;
case SDL_KEYUP:
if (event.key.repeat == 0)
buttons[event.key.keysym.scancode] = false;
break;
Тогда, в основном цикле игры вы можете написать что-то вроде:
if (buttons[SDL_SCANCODE_W])
player->Move(0, -1);
Тогда игрок будет плавно двигаться, пока клавиша нажата.
В принципе, SDL сам уже хранит такой массив состояний кнопок.
К нему можно получить доступ вот так: if (SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_W])
.
Если вам достаточно знать, нажата кнопка или нет, можете использовать этот массив и вообще выбросить обработчики событий клавиатуры.
С другой стороны, обрабатывая события самостоятельно, вы можете получать больше информации: когда была нажата клавиша, и т.п.
По ответу с английского SO: лично я не знаком с SDL, но скорее всего вам будет приходить 2 типа уведомления - кнопка нажата/отжата. Следует хранить список текущих нажатых/отжатых кнопок и в нужный моменты сверяться с ним для дальнейшего принятия того или иного решения. Код приводить не стану, вся полная информация в вышеприведённой ссылке.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Подскажите зачем оператор new идет в объявления класс Bank(class Bank : IBank where T : Account, new())
Как запросить повышения прав пользователяНапример если это инсталятор службы, то функция установки даёт ошибку - не хватает прав