c++入门小程序:2.字母游戏

代码

#include<iostream>
#include<Windows.h>
#include<conio.h>//使用getch函数 
#include<time.h>
#include<vector> //需要在LetterShower类中使用向量
#pragma comment(lib,"winmm.lib")//需要使用playsound函数播放音乐



using namespace std;
HANDLE handle;//获取输出设备句柄
COORD crd;//用于设置输出坐标
const short GROUND=27;//地面
const short SCR_WIDTH = 60;//屏幕宽度
const short HEALTH = 5;//初始血量

class Vitality//管理生命力
{
    
    
private:
	short vitality;//剩余血量
public:
	Vitality() {
    
     vitality = HEALTH; }
	void ShowVitality()//显示当前血量
	{
    
    
		crd.X = SCR_WIDTH * 0.6; crd.Y = 0;
		SetConsoleCursorPosition(handle, crd);
		SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
		cout << "HP:";//hit points 血量
		for (short i = 0; i < HEALTH; i++)
			cout << (i < vitality ? "■" : "_");
		SetConsoleTextAttribute(handle, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);//恢复为黑底白字

	}
	short GetWound(short n = -1)//扣血
	{
    
    
		vitality += n;
		ShowVitality();
		return vitality;
	}
	short GetRestore()//恢复满血
	{
    
    
		vitality = HEALTH;
		ShowVitality();
		return vitality;
	}
};

Vitality vty;

struct Letter//字母相关信息
{
    
    
	char letter;//当前字母
	short x;//x轴坐标
	short y;//y轴坐标
}; 
class LetterShower//管理字母的产生,下落,掉落地面等行为
{
    
    
private:
	vector<Letter>letters[26];//建立26个成员的向量数组,下标为0的保存字母A的出现,下落情况,下标25的保存Z的各种情况
	short score;//保存玩家得分
	short delay;//字母掉落时的延时
	bool Ground(vector<Letter>::iterator l)//判断一个字母已掉落到地面
	{
    
    
		return l->y >= GROUND;
	}

public:
	LetterShower() {
    
     score = 0; }
	void GenerateLetter()
	{
    
    
		Letter l = {
    
     'A' + rand() % 26,rand() % SCR_WIDTH,1 };
		letters[l.letter - 'A'].push_back(l);
	} 
	
	short Fall()//管理所有字母的一次掉落与触地
	{
    
    
		short i;
		vector<Letter>::iterator itr;
		for (i = 0; i < 26; i++)
		{
    
    
			for (itr = letters[i].begin(); itr != letters[i].end();)
			{
    
    
				crd.X = itr->x; crd.Y = itr->y;//获得字母原来的坐标,准备输出空格将其擦除
				SetConsoleCursorPosition(handle, crd);
				cout << ' ';   
				if (Ground(itr))//若已触地,则需要处理扣血
				{
    
    
					if (vty.GetWound() <= 0)//处理game over的输出信息
					{
    
    
						crd.X = 13; crd.Y = GROUND + 2;
						SetConsoleCursorPosition(handle, crd);
						SetConsoleTextAttribute(handle, BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
						cout << "Game Over!";
						SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
						PlaySound(L".\\sound\\over.wav", NULL, SND_ASYNC | SND_FILENAME);//SND_ASYNC开始播放音乐后就执行下面的代码;SND_FILENAME使用文件路径
						return -1;//返回-1告知本函数的调用块游戏已结束
					}
					itr=letters[i].erase(itr);//将落地的字母从向量中清清除掉,迭代器自动指向下一个字母
					PlaySound(L".\\sound\\wound.wav", NULL, SND_ASYNC | SND_FILENAME);
					continue; 
				}
				itr->y++;
				crd.Y = itr->y;
				SetConsoleCursorPosition(handle, crd);
				cout << itr->letter;
				itr++;
			}
		}
		return 0;//返回0表示游戏尚未game over
	}
	void ClearAll()//清空字母向量组,恢复为初始值,为重开游戏做准备
	{
    
    
		for (short i = 0; i < 26; i++)
			while (!letters[i].empty())
				letters[i].pop_back();
		score = 0;
	}
	void ShowScore()
	{
    
    
		crd.X = 1; crd.Y = GROUND + 2;
		SetConsoleCursorPosition(handle, crd);
		cout << "Score:" << score << "    ";//在分数后面输出空格,防止上轮游戏的分数对其造成因像
	}
	void SetDelay(short d) {
    
     delay = d; }
	void Wait() {
    
     Sleep(delay); }
	void Rain()//让字母反复执行Fall函数,持续向下掉落,并捕捉用户的按键,消除被按中的字母
	{
    
    
		char ch;//保存用户按键信息
		vector<Letter>::iterator itr;
	Repeat:
		while (!_kbhit())
		{
    
    
			if (Fall() == -1)
				return;
			Wait();
			if (rand() % 3 == 0)
				GenerateLetter();//每个循环有三分之一的机会产生新字母
		}
		ch = _getch();
		if (ch >= 'a' && ch <= 'z')
		{
    
    
			if (!letters[ch - 'a'].empty())
			{
    
    
				itr = letters[ch - 'a'].begin();
				crd.X = itr->x;
				crd.Y = itr->y;
				SetConsoleCursorPosition(handle, crd);
				cout << ' ';
				letters[ch - 'a'].erase(itr);
				PlaySound(L"./sound/erase.wav", NULL, SND_ASYNC | SND_FILENAME);
				score++;
				ShowScore();
			 }
		}
		goto Repeat;//回到while (!kbhit())的位置
	}
	  
};

void Pause()
{
    
    
	
}
void PrintLevel(short lv)//参数0表示简单,1为中等,2为困难
{
    
    
	crd.X = 4; crd.Y = 0;
	SetConsoleCursorPosition(handle, crd);
	switch (lv)
	{
    
    
	case 0:cout << "Level:EASY"; break;
	case 1:cout << "Level:INTERMEDIATE"; break;
	default:cout << "Level:HARD"; break;
	}
}
void Welcome()//设置欢迎界面
{
    
    
	crd.X = 13, crd.Y = 10;
	SetConsoleCursorPosition(handle, crd);
	cout << "Welcome to Type Game!";
	crd.X = 10, crd.Y = 12;
	SetConsoleCursorPosition(handle, crd);
	cout << "Press any key to continue...";
}
short ShowMenu()//返回值显示用户所选难度级别。容易0,中级1,困难2
{
    
    
	system("cls");
	crd.X = 10; crd.Y = 10;
	SetConsoleCursorPosition(handle, crd);
	cout << "Which level do you want try?";
	short result = 0;
	char ch=0;
	do
	{
    
    
		if (ch == 75) result = (result + 2) % 3;//按下了左方向键
		if (ch == 77) result = (result + 1) % 3;//按下了右方向键
		crd.X = 9; crd.Y = 12;
		SetConsoleCursorPosition(handle, crd);
		if (result == 0)
			SetConsoleTextAttribute(handle, BACKGROUND_GREEN);
		else
			SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
		cout << " EASY ";
		crd.X = 19; crd.Y = 12;
		SetConsoleCursorPosition(handle, crd);
		if (result == 1)
			SetConsoleTextAttribute(handle, BACKGROUND_GREEN);
		else
			SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
		cout << " INTERMEDIATE ";
		crd.X = 36; crd.Y = 12;
		SetConsoleCursorPosition(handle, crd);
		if (result == 2)
			SetConsoleTextAttribute(handle, BACKGROUND_GREEN);
		else
			SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
		cout << " HARD ";
		ch=_getch();//将造成阻塞,等待用户按键
		if (ch == 0)
			ch = _getch();
	} while (ch!=VK_RETURN);//只有当按下回车键时才结束循环
	SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);//恢复成默认的文字以及背景色
	return result;
}
void DrawGround()//绘制地面
{
    
    
	crd.X = 0; crd.Y = GROUND+1;
	SetConsoleCursorPosition(handle, crd);
	for (int i = 0; i < SCR_WIDTH; i++)
		cout << '=';
}

int main()
{
    
    
	system("mode con cols=60 lines=31");//设置控制台大小
	srand(time(0));//随机种子
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	Welcome();//欢迎界面
	_getch();
	short level;//接收用户选择的难度级别
	char choice;//有用户输出是否继续游戏
	LetterShower ls;
	do
	{
    
    
		system("cls");//清除欢迎界面的文字,如果第二,三......次循环,则清除窗体已有字母
		level = ShowMenu();//显示菜单
		system("cls");
		vty.GetRestore();//恢复血量
		vty.ShowVitality();//显示血量
		PrintLevel(level);//显示难度
		DrawGround();//画出地面
		ls.ClearAll();//得分归0,并清空向量
		ls.ShowScore();//显示分数
		ls.SetDelay(300 - level * 100);//根据难度,设置延时
		ls.Rain();//字母下落
		cout << "Try again?(y/n)";
		cin >> choice;
	} while (choice == 'Y' || choice == 'y');

	return 0;
}

结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_60534571/article/details/130539500