Задать вопрос
Pakonigoosy
@Pakonigoosy
Разработчик ПО

Почему при одновременно нажатии двух клавиш программа на полсекунды замирает?

Я пытаюсь написать простую игру теннис.
Если нажимать на клавиши A/Z, OEM_2/OEM_7, то можно двигать первую и вторую ракетку соответственно вверх и вниз.
Проблема заключается в том, что если я с нажатой одной клавишей, нажимаю другую, то происходит небольшая задержка. Поясню на примере.
Допустим, я двигаю левую ракетку вверх. В какой-то момент я нажимаю кнопку, двигающую правую ракетку вниз. В этом случае все на полсекунды останавливается и потом продолжается также, как и должно. Как избавиться от этой полсекундной задержки?
#include <windows.h>
const double PI = 3.141592653;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char szClassName[] = "CG_WAPI_Template";
/////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmd
{
HWND hWnd;
MSG lpMsg;
WNDCLASS wc;
// Заполняем структуру класса окна
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)szClassName;
// Регистрируем класс окна
if (!RegisterClass(&wc))
{
MessageBox(NULL, (LPCWSTR)"Не могу зарегистрировать класс окна!", (LPCWSTR)"Ошибка", MB_O
return 0;
}
// Создаем основное окно приложения
hWnd = CreateWindow(
(LPCWSTR)szClassName, // Имя класса
L"Шаблон WinAPI приложения", // Текст заголовка
WS_OVERLAPPEDWINDOW, // Стиль окна
50, 50, // Позиция левого верхнего угла
600, 600, // Ширина и высота окна
(HWND) NULL, // Указатель на родительское окно NULL
(HMENU) NULL, // Используется меню класса окна
(HINSTANCE)hInstance, // Указатель на текущее приложение
NULL ); // Передается в качестве lParam в событие WM_CREATE
if (!hWnd)
{
MessageBox(NULL, (LPCWSTR)"Не удается создать главное окно!", (LPCWSTR)"Ошибка", MB_OK);
return 0;
}
// Показываем наше окно
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Выполняем цикл обработки сообщений до закрытия приложения
while (GetMessage(&lpMsg, NULL, 0, 0))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return (lpMsg.wParam);
}
/////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
RECT Rect;
Директива препроцессора #include <windows.h> открывает доступ к тысячам описаний констант,
структур, типов данных и функций Windows.
WinAPI приложение является в своей основе процедурным приложением и содержит два основных
модуля – функции WinMain и WndProc.
HDC hdc, hCmpDC;
HBITMAP hBmp;
switch (messg)
{
case WM_PAINT:
GetClientRect(hWnd, &Rect);
hdc = BeginPaint(hWnd, &ps);
// Создание теневого контекста для двойной буферизации
hCmpDC = CreateCompatibleDC(hdc);
hBmp = CreateCompatibleBitmap(hdc, Rect.right - Rect.left,
Rect.bottom - Rect.top);
SelectObject(hCmpDC, hBmp);
// Закраска фоновым цветом
LOGBRUSH br;
br.lbStyle = BS_SOLID;
br.lbColor = 0xEECCCC;
HBRUSH brush;
brush = CreateBrushIndirect(&br);
FillRect(hCmpDC, &Rect, brush);
DeleteObject(brush);
// Здесь рисуем на контексте hCmpDC
// Копируем изображение из теневого контекста на экран
SetStretchBltMode(hdc, COLORONCOLOR);
BitBlt(hdc, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top,
hCmpDC, 0, 0, SRCCOPY);
// Удаляем ненужные системные объекты
DeleteDC(hCmpDC);
DeleteObject(hBmp);
hCmpDC = NULL;
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN: 		
speed=10; 		
if (GetAsyncKeyState(0x41)){ 
pos1+=speed; 				
if (pos1>320){ 					
pos1=320; 				
} 		
} 		
if (GetAsyncKeyState(0x5A)){ 			
pos1-=speed; 				
if (pos1<0){ 					
pos1=0; 				
} 		
} 		
if (GetAsyncKeyState(VK_OEM_7)){ 

pos2+=speed; 				
if (pos2>320){ 					
pos2=320; 				
} 		
} 		
if (GetAsyncKeyState(VK_OEM_2)){ 			

pos2-=speed;	
if (pos2<0){ 					
pos2=0; 				
} 		
}	 		
InvalidateRect(hWnd,0,false); 		
UpdateWindow(hWnd); 		
break;
default:
return (DefWindowProc(hWnd, messg, wParam, lParam));
}

Примечания:
1. Шаблон не мой, я его скопировал. В оригинале он назывался "шаблон графического приложения на winapi"
2. Это моё первое приложение на winapi. Так что не судите строго
3. Функция draw просто рисует горизонтальную линию и вертикальную посередине, а также отрисовывает ракетки в зависимости от их позиции. Я думаю, что это не нужно сюда вставлять, но если надо, то я прикрепляю
Заранее спасибо
  • Вопрос задан
  • 117 просмотров
Подписаться 1 Простой 2 комментария
Решения вопроса 1
Pakonigoosy
@Pakonigoosy Автор вопроса
Разработчик ПО
Нашел решение проблемы. Суть в том, чтобы в блоке WM_KEYDOWN задавать значения булевых переменных is1up_pressed, is1down_pressed, is2up_pressed, is2down_pressed, каждая их которых отвечает за свою кнопку. Также я добавил блок WM_KEYUP, где я проверяю, отпущены ли клавиша.
Позицию ракетки я меняю по таймеру 25 раз в секунду
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы