C++课程设计之我的小游戏欢乐小鱼
这是我大一下学期做的程序,在这里仅为了记录一下,避免以后电脑出问题,文件丢失。
C++课程设计通常都是要求两三周之内做一个C++语言的课程设计,有的学校老师会给每个学生安排题目,有的学校老师也允许自由选题。我们学校老师的要求就是可以自己选题,也可以选择老师给出的题目。
我选择的是自己做一个有界面小游戏。
数据结构与算法课程设计之五子棋
这是我做的小游戏的登录界面,这并不是一个静态的界面,是有一个进入的界面的。
整个程序有672行,用到了数据结构链表,思想比较简单。由于有相对比较漂亮的界面效果,所以需要用到图形库。这里给大家推荐一个非常适合初学者的图形库网站:Easyx,感兴趣的可以去学学。
这个界面使用动态的画点函数,画出了一个心形图形,然后用红色填充这个心。点击【开始游戏】可以跳转到游戏的主界面:
整个程序的思想:一条小鱼躲避障碍物,并拾取金币。小鱼是一个类,障碍物是一个类,金币是一个类。所有障碍物用一条链表串联在一起。出了屏幕的障碍物被释放,避免内存占用过大造成后面程序崩溃。游戏运行过程中的最高分数保存在一个txt文件中。
我编译的环境:windows 10、Visual Studio 2017、Easy_x春分版2018(加载图形库)。
(高版本的vs+高版本的easy_x都可以运行这个程序。)
程序代码如下:
///
//需要安装Easyx_2018春分版,可在vs上无错运行。
//插件网址:http://www.easyx.cn
//作者:1264397259@qq.com
//作品名称:欢乐小鱼
//语言: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"开");
}
由于程序中加载了音乐以及一些不容易绘制出来的图形,所以需要资源包的可以下载:(由于用的相对地址,所以请把资源包内的图片和音乐放到源文件一个文件夹中,不是把这个资源文件夹放到源代码哪个文件,而是里面的图片和音乐。)
欢乐小鱼资源包