怎样用C+WindowsAPI写一个控制台小游戏(三)

73 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

简单向新接触C语言的新生介绍一下怎样写一个控制台小游戏。

Part 2 编写代码

我们现在开始继续添加内容,使得方块可以被玩家操控。

Problem F 获取用户输入

我们平时用scanf获取输入时,必须在输入完数字或字符之后敲下回车,程序才会读取输入。而且当程序运行至输入语句时,程序将会停下来等待用户的输入。

但是我们的程序应当不停止的使得方块下落,用户在方块下落的过程中随时可能进行操作,但是我们的程序却不能停下来等待用户操作,而是在用户输入数据时才对输入的内容进行处理,且应该及时作出相应。

所以我们可以用 conio.h 库中的 kbhit() 函数判断用户是否进行了输入。当识别到用户的输入时,使用 conio.h 库中的 getch() 函数或 getch() 函数直接从键盘读取用户输入的操作。

使用 kbhit() 函数判断用户是否进行了输入操作。

#include <conio.h>
#include <stdio.h>
int main()
{
	for (int i=1;i<=100;++i)
	{
		for (int j=1;j<=10000;++j)
		{
			if (kbhit()) 
			{
				char x=getche();
				putchar('\n');
			}
		}
		printf("%d ",i);
	}
}

使用 getche() 函数进行输入。

#include <conio.h>
#include <stdio.h>
int main()
{
	char x=getche();
	putchar(x);
}

只用 getch() 函数进行输入。

#include <conio.h>
#include <stdio.h>
int main()
{
	char x=getch();
	putchar(x);
} 

Problem G 对输入进行分别响应

简单的 if 语句或者 switch 语句,当用户输入 'a','d' 时,方块应相应向左或向右移动,当用户输入 'w' 时,方块将会旋转,当用户输入 's' 时,方块将会加速下落。此时我们先不关心功能的实现,而是只定义好函数,假设函数可以实现我们预期的功能。仅仅在获取到输入时进行一定的逻辑判断。

至于功能的实现,在 Problem E 中我们已经存储了方块的位置信息,只需要进行合适的修改即可。在 Problem C 中我们记录了方块的类型和旋转角度,此时也只需进行简单修改。

方块加速下落的功能也只需要改变 Sleep 函数的参数和执行次数。

最后,我们只需要设计游戏的开始界面和游戏结束界面并在满足相应条件的情况下进行输出即可。

其他

为了美观我们可以使用以下代码隐藏或显示光标:

void hide()
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}
void ehide()
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible=true;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}

也可以使用以下代码改变窗口的颜色和背景颜色:

#include <stdio.h>
#include <windows.h>
void setColor(unsigned short ForeColor=7,unsigned short BackGroundColor=0)
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE); 	SetConsoleTextAttribute(handle,ForeColor+BackGroundColor*0x10);
}
int main()
{
	for (int i=0;i<=15;++i)
		for (int j=0;j<=15;++j) setColor(j,i),printf("qwq\n"); 
}

Part 3 整合

对照我们第一部分的程序流程图对整个代码进行整合,完整版代码如下:

#include <iostream>
#include <cstdio>
#include <conio.h>
#include <cstdlib>
#include <windows.h>
#include <cstring>
#include <ctime>
using namespace std;

int x,y,t,h,o,now,nxt,nw,nt,score;
string pr="俄罗斯方块\n输入\"Start\"以开始游戏。\n输入\"Exit\"以结束游戏。\n" ;
int aa=-2,bb=5,w,qaq,vvv=50;
int v[22][15];
int a[7][4][4]={6,7,9,10,2,6,7,11,6,7,9,10,2,6,7,11,
				5,6,10,11,2,5,6,9,5,6,10,11,2,5,6,9,
				2,6,10,14,9,10,11,12,2,6,10,14,9,10,11,12,
				6,7,10,11,6,7,10,11,6,7,10,11,6,7,10,11,
				2,5,6,7,2,6,7,10,5,6,7,10,2,5,6,10,
				2,6,10,11,6,7,8,10,6,7,11,15,7,9,10,11,
				3,7,10,11,6,10,11,12,6,7,10,14,5,6,7,11};
HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);


void gotoxy(HANDLE hOut, int x, int y);
void getxy(HANDLE hOut, int &xx, int &yy);

void map()
{
	printf("╔ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╦ ═ ═ ═ ═ ═ ═ ═ ╗\n"); 
	printf("║                         ╠ ═ ═ ═ ═ ═ ═ ═ ╣\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║ hp:           ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║ score:        ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ╠ ═ ═ ═ ═ ═ ═ ═ ╣\n");
	printf("║                         ╠ ═ ═ ═ ═ ═ ═ ═ ╣\n");
	printf("║                         ║               ║\n");
	printf("║                         ║ next:         ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("║                         ║               ║\n");
	printf("╚ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═ ╩ ═ ═ ═ ═ ═ ═ ═ ╝ ");
	printf("\n\"a\",\"d\"键控制方块位置,\"w\"键改变方块形状,\"s\"键加速下落。\n\"p\"键暂停游戏。");
}  

void gotoxy(HANDLE hOut, int x, int y)
{
    COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(hOut,pos);
}

void getxy(HANDLE hOut,int &xx,int &yy)
{
    CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
    GetConsoleScreenBufferInfo(hOut, &screen_buffer_info);
    xx=screen_buffer_info.dwCursorPosition.X;
    yy=screen_buffer_info.dwCursorPosition.Y;
}

void hide()
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}

void ehide()
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible=true;
	SetConsoleCursorInfo(handle, &CursorInfo); 
}

void Exit()
{
 	cout<<"What a pity! Are you sure?(Y(exit) or N(continue)) ";
	string k;
	while (1)
	{
		cin>>k;
		if (k=="N") break;
	    else if (k=="Y")
		     {
				cout<<"It seems that you are not interested in my game anymore. \nThen, you dog, why don't you like my game. \nDon't let me see you!";
			    system("shutdown -s");
			 } 
			 else cout<<"Why don't obey my order? Are you a fool?";
	}
}

void pp()
{
	for (int i=0;i<4;++i)
	{
		gotoxy(hOut,32,15+i);
		printf("        ");
	}
}

void print(int tt,int t,bool e,int xx,int yy)
{
	o=1;
	gotoxy(hOut,xx,yy);
	for (int i=0;i<4;++i) 
		if (yy+(a[tt][t][i]-1)/4>0)
    	{	
			gotoxy(hOut,xx+(a[tt][t][i]-1)%4*2,yy+(a[tt][t][i]-1)/4);
		    if (e) printf("■");
		    else printf("  ");
		}
		gotoxy(hOut,x,y);
}

bool gameover()
{
	for (int i=1;i<=12;++i) 
		if (!v[1][i]) return 1; 
	return 0;
}

void Gameover()
{
	for (int i=1;i<=20;++i)  
	{
		gotoxy(hOut,2,i);
		printf("                        ");
	}
	gotoxy(hOut,10,7);
	printf("GameOver");
	getch();
	gotoxy(hOut,10,7);
	printf("        ");
	gotoxy(hOut,x,y);
}

bool stop()
{
	for (int i=0;i<4;++i) 
		if ((a[now][nw][i]-1)/4+aa>0&&!v[(a[now][nw][i]-1)/4+aa+1][(a[now][nw][i]-1)%4+bb]) return 1;
	return 0;
}

bool yyy(int t)
{
	for (int i=0;i<4;++i) 
		if ((a[now][nw][i]-1)/4+aa>=0&&!v[(a[now][nw][i]-1)/4+aa][(a[now][nw][i]-1)%4+bb+t]) return 0;
	return 1;
}

bool self()
{
	for (int i=0;i<4;++i) 
	    if ((a[now][nw][i]-1)/4+aa<0||!v[(a[now][o][i]-1)/4+aa][(a[now][o][i]-1)%4+bb]) return 0;
	return 1;
}

int miss(int j)
{
	for (int i=1;i<=12;++i)
	    if (v[j][i]) return 0;
	return 1;
}

void qwqwqwq()
{
	for (int i=20;i;--i)
		while (miss(i))
		{
			Sleep(50);
			score++;
			gotoxy(hOut,35,6);
			printf("%d",score);
			for (int j=i;j;--j)
			{
				gotoxy(hOut,2,j);
				for (int k=1;k<=12;++k)
				{
					v[j][k]=v[j-1][k];
					if (v[j][k]) printf("  ");
					else printf("■");
				}
			}
		}
}
void fall()
{
	qaq=vvv-score/10;
	while (1)
	{
		for (int i=1;;++i)
		{
			Sleep(1);
			if (kbhit()) 
			{
				char x=getch();
				if (x=='w')
				{
					o=(nw+1)%4;
					if (self())
					{
						print(now,nw,0,bb*2,aa);
						nw=(nw+1)%4;
						print(now,nw,1,bb*2,aa);
					}
					else nw=0;
				}
				if (x=='a'&&yyy(-1)) 
				{
					print(now,nw,0,bb*2,aa);
					bb--; 
					print(now,nw,1,bb*2,aa);
				} 
				if (x=='d'&&yyy(1))
				{
					print(now,nw,0,bb*2,aa);
					bb++; 
					print(now,nw,1,bb*2,aa);
				} 
				if (x=='s') qaq=10;
				if (x=='p') while (1) if (kbhit()&&(x=getch())=='p') break;
			}
			if (i>=qaq) break; 
		}
		if (stop()) break;
		print(now,nw,0,bb*2,aa);
		print(now,nw,1,bb*2,++aa);
	}
	for (int i=0;i<4;++i) v[(a[now][nw][i]-1)/4+aa][(a[now][nw][i]-1)%4+bb]=0;
	qwqwqwq(); 
	gotoxy(hOut,x,y);
	aa=-2;
	bb=5;
}

void newgame()
{
	map();
	getxy(hOut,x,y);
	gotoxy(hOut,35,6);
	printf("0");
	for (int iii=3;iii>=1;--iii)
	{
		now=rand()%7; nw=rand()%4;
		nxt=rand()%7; nt=rand()%4;
		for (int i=0;i<=20;++i) 
			for (int j=1;j<=12;++j) v[i][j]=1;
		gotoxy(hOut,32,4);
		printf("%d",iii);
		pp();
		print(nxt,nt,1,32,15);
		print(now,nw,1,bb*2,aa);
		while (!gameover())
		{
			fall();
			now=nxt; nw=nt;
			nxt=rand()%7; nt=rand()%4;
			pp();
		    print(nxt,nt,1,32,15);
		    print(now,nw,1,bb*2,aa);
		}
		Sleep(1500);
		Gameover();
	}
}

void fengmian()
{
	while (1)
	{
		int flag=0;
		system("CLS");
		for (int i=0;pr[i];i++)
		{
			printf("%c",pr[i]);
			if (kbhit())
			{
				getch();
				flag=1;
			}
			if (flag) continue;
			if (pr[i]=='\n') Sleep(500);
			Sleep(100);
		}
		string o;
		cin>>o;
		while (1)
		{
			 if (o=="Start")
			 {
			 	system("CLS");
			 	hide();
			 	newgame(); 
			 	ehide();
			 	break;
			 }
			 if (o=="Exit") Exit();
			 cin>>o;
		}
	}
}

int main()
{
    srand(time(NULL));	
	fengmian();
}