?[導(dǎo)讀]本系列博文內(nèi)容鏈接如下:
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(一)——使用getch()函數(shù)獲得鍵盤(pán)碼值
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(二)——利用getch()函數(shù)實(shí)現(xiàn)鍵盤(pán)控制單個(gè)字符移動(dòng)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(三)——getch()函數(shù)控制任意造型飛機(jī)圖標(biāo)移動(dòng)【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(四)——給游戲添加背景音樂(lè)(多線程技巧應(yīng)用)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(五)——getch()控制兩個(gè)飛機(jī)圖標(biāo)移動(dòng)(控制光標(biāo)位置)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(六)——給兩架飛機(jī)設(shè)置不同顏色(cout輸出彩色字符、結(jié)構(gòu)體使用技巧)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(七)——兩組按鍵同時(shí)檢測(cè)平滑移動(dòng)(GetAsyncKeyState()函數(shù)應(yīng)用)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(八)——生成敵方炮彈(rand()函數(shù)應(yīng)用)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(九)——發(fā)射子彈的編程技巧
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(十)——子彈擊落炮彈、炮彈與飛機(jī)相撞?
一、GetAsyncKeyState()函數(shù)
在上一節(jié)
【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(六)——給兩架飛機(jī)設(shè)置不同顏色(cout輸出彩色字符、結(jié)構(gòu)體使用技巧)
中實(shí)現(xiàn)了利用鍵盤(pán)控制兩組方向鍵控制兩個(gè)不同顏色、造型的飛機(jī)移動(dòng),但是實(shí)際測(cè)試過(guò)程中發(fā)現(xiàn),兩組方向鍵盤(pán)會(huì)相互影響,不能實(shí)現(xiàn)兩組方向鍵長(zhǎng)按指令,而且移動(dòng)有卡頓,不平滑。經(jīng)過(guò)查詢資料,發(fā)現(xiàn)可以利用windows自帶的GetAsyncKeyState()函數(shù)實(shí)現(xiàn)可以同時(shí)檢測(cè)兩組按鍵,并且移動(dòng)比較平滑。
參考博文:20191223同時(shí)檢測(cè)多個(gè)按鍵和按鍵平滑處理_c++檢測(cè)用戶同時(shí)按下多個(gè)按鍵_lee李家軍的博客-CSDN博客
二、代碼優(yōu)化
(一)key()函數(shù)
//獲取鍵盤(pán)指令函數(shù)
void key(void)
{
direction_cmd c=none_cmd;
direction_cmd d=none_cmd;
if (GetAsyncKeyState(VK_UP) & 0x8000) c = up_cmd;
if (GetAsyncKeyState(VK_DOWN) & 0x8000) c = down_cmd;
if (GetAsyncKeyState(VK_LEFT) & 0x8000) c = left_cmd;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c = right_cmd;
if (GetAsyncKeyState('W') & 0x8000) d = up_cmd;
if (GetAsyncKeyState('S') & 0x8000) d = down_cmd;
if (GetAsyncKeyState('A') & 0x8000) d = left_cmd;
if (GetAsyncKeyState('D') & 0x8000) d = right_cmd;
plane[0].keycmd=c;
plane[1].keycmd=d;
}
(二)主函數(shù)
把位置更新的函數(shù),從主線程中移動(dòng)到按鍵檢測(cè)線程中。
(三)thread_key()
檢測(cè)按鍵線程內(nèi)加入飛機(jī)位置更新函數(shù)。注意,線程中要加一個(gè)延時(shí)函數(shù),延時(shí)的時(shí)間要進(jìn)行測(cè)試,以長(zhǎng)按時(shí)能顯示出每次移動(dòng)一個(gè)位置,而且移動(dòng)比較平滑為準(zhǔn)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-647838.html
void* thread_key(void* arg)
{
while(1)
{
Sleep(60); //獲取指令延時(shí)一定時(shí)間,起濾波作用,延緩獲取指令的響應(yīng)速度
key(); //獲取按鍵指令
plane_location_update() ;//獲取完指令馬上更新飛機(jī)坐標(biāo)
}
}
三、優(yōu)化后的代碼
(一)主函數(shù)
#include "control_plane.h"
using namespace std;
Plane plane[num_plane];
int main(int argc, char** argv) {
init(); //初始化
bgmusic();//播放背景音樂(lè)
getkey();
while(1) //循環(huán)等待鍵盤(pán)指令
{
if(plane[0].keycmd!=none_cmd ||plane[1].keycmd!=none_cmd)
{
system("cls");
for(int i=0;i<num_plane;i++)
{
show_plane(plane[i]); //刷新飛機(jī)圖標(biāo)
}
}
}
return 0;
}
(二)頭文件control_plane.h
#ifndef CONTROL_PLANE_H
#define CONTROL_PLANE
#include <iostream>
#include <string>
#include<stdlib.h>
#include<windows.h>
#include <pthread.h>//導(dǎo)入線程頭文件庫(kù)
#include <mmsystem.h> //導(dǎo)入聲音頭文件庫(kù)
#pragma comment(lib,"winmm.lib")//導(dǎo)入聲音的鏈接庫(kù)
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define t_b 0 //圖形顯示區(qū)域上側(cè)邊界
#define l_b 0 //圖形顯示區(qū)域左側(cè)邊界
#define r_b 100 //圖形顯示區(qū)域右側(cè)邊界
#define b_b 20 //圖形顯示區(qū)域下側(cè)邊界
#define num_plane 2 //飛機(jī)架數(shù)
//定義飛機(jī)造型
const string icon_plane1[]={" ■","■ ■ ■","■■■■■","■ ■ ■"," ■"," ■■■"};
const string icon_plane2[]={" ■","■ ■ ■","■■■■■"," ■"," ■■■","■■■■■"};
//定義坐標(biāo)結(jié)構(gòu)體
typedef struct{
int x;
int y;
} Location;
//定義移動(dòng)方向命令枚舉類型
typedef enum {none_cmd,up_cmd,down_cmd,left_cmd,right_cmd} direction_cmd;
//定義飛機(jī)結(jié)構(gòu)體
typedef struct{
Location location;
int color;
int icon;
direction_cmd keycmd;
}Plane;
extern Plane plane[num_plane];
//聲明刷新飛機(jī)位置函數(shù)
void show_plane(Plane plane);
//獲取鍵盤(pán)指令
void key(void);
//更新所有飛機(jī)坐標(biāo)
void plane_location_update(void);
//初始化函數(shù)
void init(void);
//播放背景音樂(lè)線程
void* thread_bgmusic(void* arg);
void play_bgmusic();
void bgmusic();
//獲取按鍵指令線程
void* thread_key(void* arg);
void getkey();
//輸出彩色字符函數(shù)
template<typename T> //T表示任何可以被cout輸出的類型
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0);
#endif
(三)庫(kù)函數(shù)control_plane.cpp
#include <iostream>
#include "conio.h"
#include <string>
#include "control_plane.h"
#include<windows.h>
using namespace std;
//彩色輸出函數(shù)
template<typename T> //T表示任何可以被cout輸出的類型
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0)
{
// 0 = 黑色 1 = 藍(lán)色 2 = 綠色 3 = 淺綠色 4 = 紅色 5 = 紫色 6 = 黃色 7 = 白色
// 8 = 灰色 9 = 淡藍(lán)色 10 = 淡綠色 11 = 淡淺綠色 12 = 淡紅色 13 = 淡紫色 14 = 淡黃色 15 = 亮白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForeColor + BackColor * 0x10);
cout << t;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
//隱藏光標(biāo)函數(shù)
HANDLE han = GetStdHandle(-11);
void hide(){
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = 0;
cursor.dwSize = 1;
SetConsoleCursorInfo(han,&cursor);
}
//初始化函數(shù)
void init(void)
{
plane[0].location={2*r_b/3,b_b};
plane[1].location={r_b/3,b_b};
plane[0].color=1;
plane[1].color=2;
plane[0].icon=1;
plane[1].icon=2;
system("cls");
for(int i=0;i<num_plane;i++)//刷新飛機(jī)圖標(biāo)
{
show_plane(plane[i]);
plane[i].keycmd=none_cmd;
}
hide();//隱藏光標(biāo)
}
//********************************************************************************
//以下三個(gè)函數(shù)為獲得按鍵指令線程函數(shù)
//********************************************************************************
void* thread_key(void* arg)
{
while(1)
{
Sleep(60); //獲取指令延時(shí)一定時(shí)間,起濾波作用,延緩獲取指令的響應(yīng)速度
key(); //獲取按鍵指令
plane_location_update() ;//獲取完指令馬上更新飛機(jī)坐標(biāo)
}
}
void getkey()
{
pthread_t tid;
pthread_create(&tid, NULL, thread_key, NULL);
}
//獲取鍵盤(pán)指令函數(shù)
void key(void)
{
direction_cmd c=none_cmd;
direction_cmd d=none_cmd;
if (GetAsyncKeyState(VK_UP) & 0x8000) c = up_cmd;
if (GetAsyncKeyState(VK_DOWN) & 0x8000) c = down_cmd;
if (GetAsyncKeyState(VK_LEFT) & 0x8000) c = left_cmd;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c = right_cmd;
if (GetAsyncKeyState('W') & 0x8000) d = up_cmd;
if (GetAsyncKeyState('S') & 0x8000) d = down_cmd;
if (GetAsyncKeyState('A') & 0x8000) d = left_cmd;
if (GetAsyncKeyState('D') & 0x8000) d = right_cmd;
plane[0].keycmd=c;
plane[1].keycmd=d;
}
//********************************************************************************
//以下三個(gè)函數(shù)為播放背景音樂(lè)功能
//********************************************************************************
//播放一遍背景音樂(lè)
void play_bgmusic() {
mciSendString(TEXT("open hero.mp3 alias s1"),NULL,0,NULL);
mciSendString(TEXT("play s1"),NULL,0,NULL);
Sleep(153*1000);//153*1000意思是153秒,是整首音樂(lè)的時(shí)長(zhǎng)
mciSendString(TEXT("close S1"),NULL,0,NULL);
}
//循環(huán)播放音樂(lè)線程函數(shù)
void* thread_bgmusic(void* arg) //
{
while(1)
{
play_bgmusic();
}
}
//創(chuàng)建音樂(lè)播放線程,開(kāi)始循環(huán)播放音樂(lè)
void bgmusic()
{
pthread_t tid;
pthread_create(&tid, NULL, thread_bgmusic, NULL);
}
void gotoxy(int x, int y) {
COORD pos = { x,y };
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//獲取標(biāo)準(zhǔn)輸出設(shè)備句柄
SetConsoleCursorPosition(hOut, pos);//兩個(gè)參數(shù)分別指定哪個(gè)窗口,具體位置
}
//飛機(jī)圖標(biāo)刷新函數(shù)
void show_plane(Plane plane) //預(yù)先定義字符定位顯示函數(shù),x是列坐標(biāo),y是行坐標(biāo),原點(diǎn)(x=0,y=0)位于屏幕左上角
{
int x,y;
int i,j;
int rows;
x=plane.location.x;
y=plane.location.y;
switch(plane.icon)
{
case 1://第一種造型
rows=sizeof(icon_plane1)/sizeof(icon_plane1[0]);
for(i=0;i<rows;i++)
{
gotoxy(x,y+i);
ColorCout(icon_plane1[i],plane.color);
}
break;
case 2://第二種造型
rows=sizeof(icon_plane2)/sizeof(icon_plane2[0]);
for(i=0;i<rows;i++)
{
gotoxy(x,y+i);
ColorCout(icon_plane2[i],plane.color);
}
break;
}
}
//更新兩個(gè)飛機(jī)的坐標(biāo)
void plane_location_update(void)
{
for(int i=0;i<2;i++)
{
if(plane[i].keycmd!=none_cmd)
{
int x,y;
x=plane[i].location.x;
y=plane[i].location.y;
switch(plane[i].keycmd)
{
case up_cmd:
y--; //字符上移一行,行值y減1
if(y<t_b) //限定y值最小值為0
{
y=t_b;
}
break;
case down_cmd:
y++; //字符下移一行,行值y加1
if(y>b_b) //限定y高度
{
y=b_b;
}
break;
case left_cmd:
x--; //字符左移一列,列值x減1
if(x<l_b)
{
x=l_b; //限定x最小值為0;
}
break;
case right_cmd:
x++; //字符右移一列,列值x加1
if(x>r_b)
{
x=r_b; //限定x寬度
}
break;
}
plane[i].location.x=x;
plane[i].location.y=y;
plane[i].keycmd=none_cmd;
}
}
}
(未完待續(xù))文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-647838.html
到了這里,關(guān)于【C++】做一個(gè)飛機(jī)空戰(zhàn)小游戲(七)——兩組按鍵同時(shí)檢測(cè)平滑移動(dòng)(GetAsyncKeyState()函數(shù)應(yīng)用)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!