虚拟键代码
虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn
在Windows操作系统中,虚拟键代码(Virtual-Key Codes)是一组用来表示键盘上按键的数值。这些代码通常用于Windows API函数,以便程序能够识别和处理键盘输入。
虚拟键代码是按键的物理位置定义的,而不是按字符本身定义的。这意味着,无论用户的键盘布局如何,同一物理按键的虚拟键代码都是相同的。例如,无论用户使用的是美式键盘、德式键盘还是日式键盘,字母 'A' 键的虚拟键代码都是 `VK_A`。
虚拟键代码通常以 `VK_` 开头,后面跟着一个或多个大写字母,表示特定的按键。例如:
- `VK_A` 表示 'A' 键。
- `VK_B` 表示 'B' 键。
- `VK_SPACE` 表示空格键。
- `VK_RETURN` 表示回车键。
- `VK_ESCAPE` 表示 ESC 键。
- `VK_UP` 表示向上箭头键。
- `VK_DOWN` 表示向下箭头键。
- `VK_LEFT` 表示向左箭头键。
- `VK_RIGHT` 表示向右箭头键。
- `VK_F1` 到 `VK_F12` 表示功能键 F1 到 F12。
在程序中,可以通过 `GetAsyncKeyState`、`GetKeyState` 或 `TranslateMessage` 等Windows API函数来检测虚拟键代码,从而判断用户是否按下了某个键。
if (KEY_PRESS(VK_UP) && ps->_SNAKE_DIR != DOWN) { ps->_SNAKE_DIR = UP; }
这里的 `KEY_PRESS(VK_UP)` 是一个宏或函数,用来检查用户是否按下了向上箭头键(`VK_UP`)。如果按下了,并且蛇当前的方向不是向下(`DOWN`),则将蛇的方向设置为向上(`UP`)。
这些虚拟键代码使得开发者能够以一种与键盘布局无关的方式处理键盘输入,从而编写出更加通用和易于移植的软件。
简单的说虚拟键代码的目的就是,进行识别是否按键封装一个宏
我们封装一个宏,进行虚拟键代码的判断
#define KEY_PRESS(vk) (GetAsyncKeyState(vk)&1?1:0)
宏 `KEY_PRESS(vk)` 是一个用于检测指定虚拟键 `vk` 是否被按下的辅助宏。它使用了 `GetAsyncKeyState` 函数,这是Windows API中的一个函数,用于检查异步键盘输入的状态。
下面是宏 `KEY_PRESS(vk)` 的详细解释:
- `GetAsyncKeyState(vk)`:这个函数接受一个虚拟键代码 `vk` 作为参数,并返回该键的异步键状态。返回值是一个16位的整数,其中第15位(从最低位开始的最高位)表示该键是否被按下。如果该位为1,则键被按下;如果为0,则键没有按下。
- `&1`:这是一个位运算符,用于对 `GetAsyncKeyState(vk)` 的返回值进行按位与操作。这里 `1` 表示二进制的最低位为1,其他位为0。因此,`&1` 操作实际上是在检查`GetAsyncKeyState(vk)` 返回值的第15位是否为1。
- `? :`:这是C语言中的三元条件运算符。如果 `GetAsyncKeyState(vk)&1` 的结果为真(非零),则表达式的值为 `1`,表示键被按下;如果为假(零),则表达式的值为 `0`,表示键没有被按下。
综上所述,`KEY_PRESS(vk)` 宏的目的是简化对 `GetAsyncKeyState` 函数的调用,并返回一个布尔值(0或1),指示指定的虚拟键 `vk` 是否被按下。在您的代码中,这个宏被用于检测用户的键盘输入,并根据这些输入来更新蛇的方向或游戏状态。
按键信息(贪吃蛇为例进行举例)
//蛇的运行逻辑 void Snake_RunGame(pSnake_State ps) { do { //打印分数 Snake_Cursor_Position(90, 20); wprintf(L"当前的得分是:%d", ps->_SNAKE_SCORE); Snake_Cursor_Position(90, 24); wprintf(L"一个食物的分数是:%d", ps->_SNAKE_ONE_FOOD); if (KEY_PRESS(VK_UP) && ps->_SNAKE_DIR != DOWN) { ps->_SNAKE_DIR = UP; } else if (KEY_PRESS(VK_DOWN) && ps->_SNAKE_DIR != UP) { ps->_SNAKE_DIR = DOWN; } else if (KEY_PRESS(VK_LEFT) && ps->_SNAKE_DIR != RIGHT) { ps->_SNAKE_DIR = LEFT; } else if (KEY_PRESS(VK_RIGHT) && ps->_SNAKE_DIR != LEFT) { ps->_SNAKE_DIR = RIGHT; } if (KEY_PRESS(VK_ESCAPE))//退出 { ps->_SNAKE_STATE = KILL_ESE; } if (KEY_PRESS(VK_F4))//减速 { if (ps->_SNAKE_ONE_FOOD > 10) { ps->_SNAKE_SLEEP_TIME += 30; ps->_SNAKE_ONE_FOOD = ps->_SNAKE_ONE_FOOD - 5; } } if (KEY_PRESS(VK_F3))//加速 { if (ps->_SNAKE_ONE_FOOD < 45) { ps->_SNAKE_SLEEP_TIME -= 30; ps->_SNAKE_ONE_FOOD = ps->_SNAKE_ONE_FOOD + 5; } } if (KEY_PRESS(VK_SPACE))//暂停 { SNAKEVK_SPACE(); } //蛇的移动 Snake_move(ps); //蛇的每次移动的休眠时间 Sleep(ps->_SNAKE_SLEEP_TIME); } while (ps->_SNAKE_STATE == OK); }
这段代码定义了一个函数 `Snake_RunGame`,它实现了蛇形游戏的主要运行逻辑。这个函数包含了蛇的移动、用户输入的检测、得分的更新以及游戏速度的控制。
下面是代码的解释:
1. `Snake_RunGame` 函数接受一个指向 `Snake_State` 结构的指针 `ps`,这个结构包含了蛇的状态信息,如头节点、状态、休息时间、得分等。
2. 函数使用一个 `do-while` 循环来持续运行游戏,直到蛇的状态不再是 `OK`(例如,蛇撞墙或吃到自己时)。
3. 在循环内部,首先使用 `Snake_Cursor_Position` 和 `wprintf` 函数打印当前得分和一个食物的分数。
4. 接下来,使用 `KEY_PRESS` 宏(或函数)来检测用户的键盘输入。根据用户按下的键(上、下、左、右箭头键),更新蛇的方向。如果蛇当前不是朝相反方向移动,蛇的方向会被更新。
5. 如果用户按下 `ESC` 键,游戏状态被设置为 `KILL_ESE`,表示游戏结束。
6. 如果用户按下 `F4` 键,游戏速度会减慢,蛇的休息时间增加,同时每个食物的分数减少。
7. 如果用户按下 `F3` 键,游戏速度会加快,蛇的休息时间减少,同时每个食物的分数增加。
8. 如果用户按下空格键,游戏会暂停。这可能是通过调用一个名为 `SNAKEVK_SPACE` 的函数实现的,但这个函数在提供的代码片段中没有定义。
9. `Snake_move` 函数被调用来处理蛇的移动逻辑。这个函数可能会更新蛇的位置,检查是否有食物被吃掉,以及蛇是否撞墙或吃到自己。
10. `Sleep` 函数用于控制游戏的更新速度,根据 `ps->_SNAKE_SLEEP_TIME` 的值来暂停一段时间。
11. `do-while` 循环的条件是蛇的状态为 `OK`,如果蛇的状态变为其他值(如 `KILL_ESE`),循环结束,游戏结束。
这个函数是蛇形游戏的核心部分,它负责处理游戏的主要逻辑和用户交互。在实际的游戏中,`Snake_move` 函数的实现细节对于游戏的行为至关重要。
这里代码有些函数是写完直接进行调用的,下面我会一一进行解释