Всем привет!
У меня Ubuntu 22.04. В процессе прохождения уроков по языку С мне нужно было написать консольную игру платформер. Возникла проблема с реализацией управления, так как стандартными способами считывается только один символ, а мне нужно считывать нажатие нескольких клавиш одновременно. В Windows эту роль выполняла функция GetKeyState() из winuser.h.
Как я понял, в curses.h и termios.h такого нет, а подключать SFML, SDL и прочие библиотеки бессмысленно, так как они создают отдельное окно и я не смог воспользоваться их функционалом из консоли.
С помощью ИИ я решил проблему, но меня не устраивает:
1. игру нужно запускать от root
2. нажатия считываются даже тогда, когда окно консоли не активно
3. когда я делал управление с помощью SFML, изображение игры не съезжало вбок, а теперь съезжает
Подскажите пожалуйста, чем можно заменить мой код!
Файл key.h с костыльной реализацией управления:
#ifndef KEYS_H
#define KEYS_H
// перед закрытием игры
void BeforeCloseGame();
// одновременное нажатие клавиш
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <linux/kernel.h>
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
static inline int is_bit_set(unsigned long *array, int bit) {
return (array[bit / (sizeof(long) * 8)] & (1UL << (bit % (sizeof(long) * 8)))) != 0;
}
int fd, ret;
unsigned long key_state[BITS_TO_LONGS(KEY_CNT)];
// Методы для начала работы с библиотекой и завершением работы
void OpenKeysMode() {
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
if (fd == -1)
ErrorCloseGame("не получилось открыть устройство клавиатуры");
}
void CloseKeysMode() {
close(fd);
}
// Получаем состояние клавиатуры
void RefreshKeyboardStatus() {
ret = ioctl(fd, EVIOCGKEY(sizeof(key_state)), key_state);
if (ret < 0)
ErrorCloseGame("не получилось получить состояния клавиатуры");
}
int GetKeyState(int Key) {
return (is_bit_set(key_state, Key));
}
#endif // KEYS_H
Как это выглядит в игре:
#include "keys.h"
void GameControl(tObject *obj) {
RefreshKeyboardStatus();
if(menu == GAMEMODE_PLAY) {
float horizonSpeed = 1.0;
if(GetKeyState(KEY_A))
horizonMoveMap(horizonSpeed);
if(GetKeyState(KEY_D))
horizonMoveMap(-horizonSpeed);
if(GetKeyState(KEY_SPACE))
if ((*obj).isFly == 0)
(*obj).vertSpeed = -1;
if(GetKeyState(KEY_Q))
menu = GAMEMODE_MENU_PAUSE;
} else {
if(GetKeyState(KEY_ESC))
CloseGame();
if(GetKeyState(KEY_E))
menu = GAMEMODE_PLAY;
}
}
Игра на GitHub:
ссылка