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"開");
}

由於程序中加載了音樂以及一些不容易繪製出來的圖形,所以需要資源包的可以下載:(由於用的相對地址,所以請把資源包內的圖片和音樂放到源文件一個文件夾中,不是把這個資源文件夾放到源代碼哪個文件,而是裏面的圖片和音樂。)
歡樂小魚資源包

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章