C++课程设计之我的小游戏欢乐小鱼

C++课程设计之我的小游戏欢乐小鱼

这是我大一下学期做的程序,在这里仅为了记录一下,避免以后电脑出问题,文件丢失。
C++课程设计通常都是要求两三周之内做一个C++语言的课程设计,有的学校老师会给每个学生安排题目,有的学校老师也允许自由选题。我们学校老师的要求就是可以自己选题,也可以选择老师给出的题目。
我选择的是自己做一个有界面小游戏。
数据结构与算法课程设计之五子棋
登录界面
这是我做的小游戏的登录界面,这并不是一个静态的界面,是有一个进入的界面的。
整个程序有672行,用到了数据结构链表,思想比较简单。由于有相对比较漂亮的界面效果,所以需要用到图形库。这里给大家推荐一个非常适合初学者的图形库网站:Easyx,感兴趣的可以去学学。
这个界面使用动态的画点函数,画出了一个心形图形,然后用红色填充这个心。点击【开始游戏】可以跳转到游戏的主界面:
跳转界面
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

整个程序的思想:一条小鱼躲避障碍物,并拾取金币。小鱼是一个类,障碍物是一个类,金币是一个类。所有障碍物用一条链表串联在一起。出了屏幕的障碍物被释放,避免内存占用过大造成后面程序崩溃。游戏运行过程中的最高分数保存在一个txt文件中。
我编译的环境:windows 10、Visual Studio 2017、Easy_x春分版2018(加载图形库)。
(高版本的vs+高版本的easy_x都可以运行这个程序。)
程序代码如下:

///////////////////////////////////////////////////////////////////
//需要安装Easyx_2018春分版,可在vs上无错运行。
//插件网址:http://www.easyx.cn
//作者:[email protected]
//作品名称:欢乐小鱼
//语言:c++
//
//
//图形库头文件,包含easyx.h。
#include<graphics.h>
#include<conio.h>
#include<ctime>
#include<iostream>
#include<fstream>
#include<cmath>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
using  namespace std;
//全局变量
const double PI = 3.1415926535;
const int Heart = 50;//心形线前的系数
const int W = 640;//窗口宽度
const int H = 480;//窗口高度
const int Block_w = 40;//障碍物的宽度
int Score = 0;//游戏得分
int Money = 0;
int Speed = 2;
bool Music = true;//true表示开,false表示关。
bool Mode = true;//true表示单人模式,false表示双人模式。
IMAGE m[3], n1[4];//游戏所需图片类
//函数申明
void Game_begin();//开始游戏
void Game_over();//游戏结束
void Result();//用于输出游戏结果。
void out_score(int score);//显示游戏分数
void out_money(int money);//显示游戏金币
void Interface();//游戏开始界面函数。
void Text();//输出游戏文字。
void HLXY();//输出游戏名称。
void Draw_ground();
void Record();//记录最高分。
void Loadpicture();//加载图片。
int output();//从文件中读取游戏历史最高分。
void Swimming(int i);//鱼儿循环移动函数。
void Change_interface();//跳转特效
void Seting();
enum Dir {
	UP, DOWN
};
//基类
class Base {
public:
	int x;
	int y;
};
//控制目标(小鱼)类
class Fish : public Base {
public:
	Fish()
	{
		y = H >> 2;
		loadimage(&img[0], L"fish3.jpg", 60, 60);
		loadimage(&img[1], L"fish5.jpg", 60, 60);
		loadimage(&img[2], L"fish6.jpg", 60, 60);
		loadimage(&img[3], L"fish7.jpg", 60, 60);
	}
	void Draw(int m)
	{
		switch (m)
		{
		case UP:
			putimage(x, y, &img[0]);
			break;
		case DOWN:
			putimage(x, y, &img[1]);
			break;
		}
	}
	void move()
	{
		if (GetAsyncKeyState(VK_UP) & 0x8000)
		{
			clearrectangle(x, y, x + 60, y + 60);
			if (y >= 0) y -= 2+int(Speed/2);
			t = 0;
			Draw(UP);
			Sleep(10);
		}
		else
		{
			clearrectangle(x, y, x + 60, y + 30);
			t++;
			y += (t >> 2) + int(Speed * 2.5);
			Draw(DOWN);
		}
	}
	void move(int m)
	{
		if ((GetAsyncKeyState('w') || GetAsyncKeyState('W')))
		{
			clearrectangle(x, y, x + 55, y + 60);
			y -= 2;
			t = 0;
			putimage(x, y, &img[2]);
			Sleep(10);
		}
		else
		{
			clearrectangle(x, y, x + 45, y + 45);
			t++;
			y += t >> 2;
			putimage(x, y, &img[3]);
		}
	}
	int Get_y()
	{
		return y;
	}
	int Get_x()
	{
		return x;
	}
private:
	const int x = W >> 2;
	IMAGE img[4];
	int t = 0;
};
//障碍物类
class Block : public Base {
public:
	Block()
	{
		head = tail = next = NULL;
		w = Block_w;
		x = W + Block_w;
		h = rand() % 120 + 60;
		color = RGB(rand() % 200 + 50, rand() % 200 + 50, rand() % 200 + 50);
		m = 1;
	}
	void Store()//进队列
	{
		Block *item;
		item = new Block;
		if (!item)
		{
			outtext(L"开辟空间失败!");
			exit(1);
		}
		if (tail) tail->next = item;
		tail = item;
		if (!head) head = tail;
	}
	void Retrieve()//出队列
	{
		Block *p;
		if (!head)
		{
			outtext(L"障碍物链表为空!");
			exit(0);
		}
		p = head;
		head = head->next;
		delete p;
	}
	void Draw()
	{
		fillrectangle(x, 0, x + w, 0 + h);
		fillrectangle(x, H - 81, x + w, H - (240 - h) - 81);
	}
	void Move()
	{
		setfillcolor(RGB(0, 0, 255));
		setlinecolor(RGB(0, 0, 255));
		Draw();
		x -= Speed;
		setlinecolor(WHITE);
		setfillcolor(color);
		Draw();
		//if (x <0) Retrieve( );
		if (x <= (W >> 2)&&m==1)
		{
			out_score(++Score);
			m = 0;
		}
	}
	int Get_x()
	{
		return x;
	}
	Block  * head;
	Block  * tail;
	Block  * next;
	int h;//障碍物长度
private:
	int w;//障碍物宽度
	int m;//用于判断是否加得分
	COLORREF  color;
};
class Coin : public Base {
public:
	Coin()
	{
		x = W;
		y = rand() % 300 + 50;
		r = 20;
		color = RGB(251, 219, 48);
	}
	void Store()//进队列
	{
		Coin *item;
		item = new Coin;
		if (!item)
		{
			outtext(L"开辟空间失败!");
			exit(1);
		}
		if (tail) tail->next = item;
		tail = item;
		if (!head) head = tail;
	}
	void Retrieve()//出队列
	{
		Coin *p;
		if (!head)
		{
			outtext(L"障碍物链表为空!");
			exit(0);
		}
		p = head;
		head = head->next;
		delete p;
	}
	void Draw()
	{
		setfillcolor(color);
		solidcircle(x, y, r);
	}
	void Remove()
	{
		setfillcolor(RGB(0, 0, 255));
		solidcircle(x, y, r + 2);
	}
	void Move()
	{
		Remove();
		x -= Speed;
		setfillcolor(color);
		Draw();
	}
	int Get_y()
	{
		return y;
	}
	int Get_x()
	{
		return x;
	}
	void Set_x(int x1)
	{
		x = x - x1;
	}
	Coin *head;
	Coin *tail;
	Coin *next;
private:
	COLORREF color;
	int r;
};
bool Judge(Block *p, Fish fish);//判断游戏是否结束。
int main()
{
	// 调用控制台 API,清空之前缓冲区内的所有按键。
	FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
	// 设置随机函数种子
	srand((unsigned)time(NULL));
	mciSendString(_T("open 亡灵序曲.mp3 alias music1"), NULL, 0, NULL);
	mciSendString(_T("open 获取金币.mp3 alias music2"), NULL, 0, NULL);
	mciSendString(_T("play music1 repeat"), NULL, 0, NULL);
	Interface();
	Game_begin();
	return 0;
}
void Interface()
{
	int W = 600, H = 600;
	Loadpicture();
	initgraph(W, H);
	setbkcolor(WHITE);//设置背景为白色
	cleardevice();
	HLXY();
	setorigin(500, 280);
	setlinecolor(RGB(191, 161, 40));
	for (int i = 0; i <= 100; i++)
	{
		if (i >= 50 || i <= 40)circle(0, 0, i);
		Sleep(20);
	}
	setlinecolor(WHITE);
	setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 7);
	line(int(cos(PI / 4) * 40), int(sin(PI / 4) * 40) + 10, int(cos(PI / 4) * 40) - 80, int(sin(PI / 4) * 40) + 80);
	line(int(sin(PI / 12) * 40), -int(cos(PI / 12) * 40) - 5, int(sin(PI / 12) * 40 + cos(PI / 12) * 100), -int(cos(PI / 12) * 40 - sin(PI / 12) * 100));
	line(-int(cos(PI / 12) * 40) - 5, int(sin(PI / 12) * 40), -int(cos(PI / 12) * 40 + sin(PI / 12) * 100), int(sin(PI / 12) * 40 - cos(PI / 12) * 100));
	Text();
	MOUSEMSG m;	// 定义鼠标消息
	int l = 0, v = 0, e = 0;
	while (true)
	{
		if (Music == false)mciSendString(_T("stop music1 "), NULL, 0, NULL);
		if (Music == true)mciSendString(_T("play music1 "), NULL, 0, NULL);
		setorigin(500, 280);
		m = GetMouseMsg();// 获取一条鼠标消息
		switch (m.uMsg)
		{
		case WM_LBUTTONDOWN:
			if ((m.x - 500)*(m.x - 500) + (m.y - 280)*(m.y - 280) <= 100 * 100 && (m.x - 500)*(m.x - 500) + (m.y - 280)*(m.y - 280) >= 50 * 50)
				if (m.x >= 500 && m.y >= 280)
				{
					Change_interface();
					v = 1;
				}
				else if (m.y <= 280 && m.x >= 450)
				{
					setlinecolor(BLUE);
					setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 1);
					for (int i = 0; i < 100; i++)
					{
						arc(-20 - i, -20 - i - 100, 20 + i, 20 + i - 100, PI / 6, PI / 6 * 5);
						Sleep(10);
						e = 1;
					}
					Seting();
				}
				else if (m.x <= 500 && m.y >= 230)exit(0);
				if (e == 1 && m.x >= 440 && m.x <= 620 && m.y <= 150 && m.y >= 80)
					if (m.y <= 120)
					{
						setfillcolor(BLUE);
						if (Mode == true)
						{
							Mode = false;
							solidrectangle(0, -200, 30, -170);
							outtextxy(0, -200, L"双人");
						}
						else
						{
							Mode = true;
							solidrectangle(0, -200, 30, -170);
							outtextxy(0, -200, L"单人");
						}
					}
					else
					{
						setfillcolor(BLUE);
						if (Music == true)
						{
							Music = false;
							solidrectangle(0, -160, 30, -130);
							outtextxy(0, -160, L"关");
						}
						else
						{
							Music = true;
							solidrectangle(0, -160, 30, -130);
							outtextxy(0, -160, L"开");
						}
					}
		}
		if (v == 1) break;
		int W = 600, H = 600;
		setorigin(0, 0);
		setfillcolor(RGB(0, 0, 255));
		solidrectangle(0, H - 200, W, H);
		setfillcolor(YELLOW);
		solidrectangle(W - 150, H - 100, W - 150 + 30, H);
		l++;
		if (l >= 390) l = 0;
		Swimming(l);
	}
}
void Draw_ground()
{
	setlinecolor(WHITE);
	line(0, H - 80, W, H - 80);
	for (int i = W + 40; i >= 0;)
	{
		i = i - 10;
		line(i, H - 80, i - 40, H);
	}
}
void Record()
{
	ofstream file("MAX.txt", ios::out);
	file << Score;
	file.close();
}
int output()
{
	int temp;
	ifstream file;
	file.open("MAX.txt", ios::in);
	if (!file.is_open())
	{
		cout << "Can't open !!! error!!!" << endl;
		system("pause");
		exit(0);
	}
	file >> temp;
	file.close();
	return temp;
}
bool Judge(Block *p, Fish fish)
{
	if (fish.Get_y() - p->h <= 5 || H - (240 - p->h) - 81 - (fish.Get_y() + 45) <= 5)
		return false;
	else
		return true;
}
void Game_begin()
{
	Fish fish1, fish2;
	int n = 0;
	Block block;
	Block *p;
	p = &block;
	Coin coin;
	Coin *g;
	g = &coin;
	initgraph(W, H);
	setbkcolor(RGB(0, 0, 255));//设置背景颜色为蓝色
	cleardevice();
	Draw_ground();
	settextcolor(WHITE);
	settextstyle(25, 0, L"楷体");
	outtextxy(W >> 2, H - 55, L"得分:0");
	if (Mode == true)outtextxy((W >> 2) + 200, H - 55, L"金币:0");
	fish1.Draw(DOWN);
	if (Mode == false) fish2.Draw(DOWN);
	outtextxy(W >> 1, H >> 2, L"游戏即将开始");
	outtextxy((W >> 1) - 50, (H >> 2) + 30, L"操作");
	outtextxy((W >> 1) - 40, (H >> 2) + 60, L"单人模式: 方向键(上)");
	outtextxy((W >> 1) - 40, (H >> 2) + 90, L"双人模式: 方向键(上)和W(w)键");
	Sleep(4000);
	setfillcolor(RGB(0, 0, 255));
	solidrectangle((W >> 1) - 50, H >> 2, (W >> 1) + 320, (H >> 2) + 200);
	while (true)
	{
		int m = 0;//用来判断是否退出循环
		bool bl = true;
		fish1.move();
		if (Mode == true) coin.Move();
		if (Mode == false) fish2.move(1);
		if (n % int(180 / Speed) == 0)//间隔180个像素点产生一个障碍。
		{
			p->Store();
			if (Mode == true)g->Store();
		}
		n++;
		Sleep(20);
		BeginBatchDraw();
		for (Block *q = p->head; q != NULL; q = q->next)
		{
			q->Move();
			if (fish1.Get_y() >= H - 81 - 45)
			{
				m = 1;
				break;
			}
			if (q->Get_x() >= W >> 2 && q->Get_x() <= (W >> 2) + 45)bl = Judge(q, fish1);
			if (!bl)
			{
				m = 1;
				break;
			}
			if (Mode == false && q->Get_x() >= W >> 2 && q->Get_x() <= (W >> 2) + 45)bl = Judge(q, fish2);
			if (!bl)
			{
				m = 1;
				break;
			}
			FlushBatchDraw();
		}
		if (Mode == true)
		{
			for (Coin *h = g->head; h != NULL; h = h->next)
			{
				h->Move();
				FlushBatchDraw();
				if ((fish1.Get_x() + 45 - h->Get_x())*(fish1.Get_x() + 45 - h->Get_x()) + (fish1.Get_y() - h->Get_y())*(fish1.Get_y() - h->Get_y()) <= 440 ||
					(fish1.Get_x() + 50 - h->Get_x())*(fish1.Get_x() + 50 - h->Get_x()) + (fish1.Get_y() + 50 - h->Get_y())*(fish1.Get_y() + 50 - h->Get_y()) <= 440)
				{
					out_money(++Money);
					h->Remove();
					mciSendString(_T("play music2 "), NULL, 0, NULL);//repeat
					h->Set_x((W >> 2) + 100);
				}
			}
		}
		EndBatchDraw();
		if (m == 1) break;
		mciSendString(_T("close music2 "), NULL, 0, NULL);
		for (int i = 1; i <= 10; i++)
			if (Score == i * 10)Speed=2+i;
	}
	Result();
	Game_over();
}
void Game_over()
{
	HWND wnd = GetHWnd();
	if (MessageBox(wnd, _T("游戏结束。\n您想重新来一局吗?"), _T("游戏结束"), MB_YESNO | MB_ICONQUESTION) == IDYES)
	{
		Score = 0;
		Money = 0;
		Game_begin();
	}
	else
		exit(0);
}
void Result()
{
	setorigin(160, 100);
	int t1;
	t1 = output();
	if (t1 <= Score) Record();
	t1 = output();
	TCHAR s1[5], s2[5], s3[5];
	_stprintf_s(s1, _T("%d"), t1);
	_stprintf_s(s2, _T("%d"), Score);
	_stprintf_s(s3, _T("%d"), Money);
	//绘制结果界面
	setfillcolor(WHITE);//设置填充颜色
	setlinecolor(BLACK);//设置画线颜色
	fillrectangle(0, 0, 300, 300);//画一个填充矩形
	line(0, 50, 300, 50);
	line(0, 250, 300, 250);
	line(50, 50, 50, 250);
	line(250, 50, 250, 250);
	line(50, 50, 0, 100);
	line(0, 100, 0, 200);
	line(0, 200, 50, 250);
	line(250, 50, 300, 100);
	line(300, 100, 300, 200);
	line(300, 200, 250, 250);
	setfillcolor(BLUE);
	floodfill(25, 150, BLACK);
	setfillcolor(RED);
	floodfill(275, 150, BLACK);
	setfillcolor(BLUE | RED | RGB(0, 255, 0));
	floodfill(150, 150, BLACK);
	//以一定形式输出结果
	setbkmode(TRANSPARENT);//设置字体背景透明
	settextcolor(BLUE);
	settextstyle(40, 0, _T("宋体"));
	outtextxy(70, 3, L"游戏结束");
	settextstyle(30, 0, L"宋体");
	settextcolor(BLACK);
	outtextxy(50, 70, L"Score:");
	outtextxy(150, 70, s2);
	outtextxy(50, 120, L"Money:");
	outtextxy(150, 120, s3);
	settextstyle(25, 0, _T("宋体"));
	outtextxy(50, 210, L"MAX_score:");
	outtextxy(175, 210, s1);
	settextcolor(YELLOW);
	outtextxy(20, 260, L"按任意键退出...");
	getchar();
}
void out_score(int score)
{
	TCHAR s[5];
	_stprintf_s(s, _T("%d"), score);
	settextcolor(WHITE);
	settextstyle(25, 0, L"楷体");
	outtextxy((W >> 2) + 62, H - 55, s);
}
void out_money(int money)
{
	TCHAR s[5];
	_stprintf_s(s, _T("%d"), money);
	settextcolor(WHITE);
	settextstyle(25, 0, L"楷体");
	outtextxy((W >> 2) + 262, H - 55, s);
}
void Loadpicture()
{
	loadimage(&m[0], L"fish1.jpg");
	loadimage(&m[1], L"fish22.jpg");
	loadimage(&m[2], L"幽灵.jpg");
	loadimage(&n1[0], L"欢.jpg");
	loadimage(&n1[1], L"乐.jpg");
	loadimage(&n1[2], L"小.jpg");
	loadimage(&n1[3], L"鱼.jpg");
}
void Text()
{
	settextcolor(GREEN);
	settextstyle(35, 0, L"楷体");
	setbkmode(TRANSPARENT);
	outtextxy(60, -20, L"开");
	outtextxy(40, 10, L"始");
	outtextxy(20, 40, L"游");
	outtextxy(-10, 65, L"戏");
	settextcolor(BLACK);
	outtextxy(-55, 45, L"出");
	outtextxy(-80, 20, L"退");
	outtextxy(-95, -10, L"忍");
	outtextxy(-98, -45, L"残");
	settextcolor(RGB(250, 0, 250));
	outtextxy(-50, -75, L"游");
	outtextxy(-15, -85, L"戏");
	outtextxy(20, -80, L"设");
	outtextxy(50, -65, L"置");
}
void HLXY()
{
	int x, y;
	for (int i = 0; i <= 440; i++)
	{
		if (i <= 135)putimage(200 + 3 * i, H - i - 100, &m[2]);
		if (i <= 100)
		{
			putimage(i, 80, &n1[0]);
			putimage(i, 170, &n1[1]);
			Sleep(20);
		}
		putimage(W - i, 80, &n1[2]);
		putimage(W - i, 170, &n1[3]);
	}
	setorigin(200, 150);
	for (double t = 0; t <= 2 * PI; t += 0.00001)
	{
		y = -int(Heart * (2 * cos(t) - cos(2 * t)));
		x = -int(Heart * (2 * sin(t) - sin(2 * t)));
		putpixel(x, y, BLACK);
	}
	setfillcolor(RED);
	floodfill(0, 0, BLACK);
}
void Swimming(int i)
{
	int H = 600;
	if (i <= 250)putimage(i, H - 50, &m[0]);
	if (i >= 200 && i <= 240)putimage(i, H - 199, &m[1]);
	if (i == 241)
	{
		setfillcolor(RGB(0, 0, 255));
		solidrectangle(250, H - 199, 450, H);
	}
	if (i >= 260)putimage(i, H - 50, &m[0]);
	Sleep(10);
}
void Change_interface()
{
	setorigin(500, 280);
	setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 10);
	for (int i = 0; i <= 790; i += 4)
	{
		setlinecolor(RGB(rand() % 250, rand() % 250, rand() % 250));
		int points[] = { 0, -30 - i,  30 + i, 0,  0, 30 + i,  -30 - i, 0 };
		drawpoly(4, points);
		Sleep(5);
	}
}
void Seting()
{
	settextstyle(25, 0, _T("楷体"));
	settextcolor(WHITE);
	outtextxy(-60, -200, L"模式:");
	outtextxy(-60, -160, L"声音:");
	outtextxy(0, -200, L"单人");
	outtextxy(0, -160, L"开");
}

由于程序中加载了音乐以及一些不容易绘制出来的图形,所以需要资源包的可以下载:(由于用的相对地址,所以请把资源包内的图片和音乐放到源文件一个文件夹中,不是把这个资源文件夹放到源代码哪个文件,而是里面的图片和音乐。)
欢乐小鱼资源包

猜你喜欢

转载自blog.csdn.net/qq_41789960/article/details/106379307