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