目录
球球大作战
一、开发环境
二、流程图预览
三、代码逻辑
1、初始化时间
2、设置开始界面大小
3、设置开始界面
4、让玩家选择速度
5、设置玩家小球、人机小球、食物的属性
6、一次性把图绘制到界面里
7、进入死循环
8、移动玩家小球
9、移动人机
10、食物刷新
11、画出边界、食物、人机、玩家、小地图,添加击杀数、半径(质量)、玩家名字
12、将内存中的绘图操作批量地绘制到屏幕上,从而提高绘图效率
四、代码预览+运行结果
球球大作战
一、开发环境
VisualStudio专业版:
所需依赖库:EasyX库
二、流程图预览
由于上面的比较模糊,下面分开截取流程图图片
三、代码逻辑
1、初始化时间
starttime();
2、设置开始界面大小
initgraph(WIDTH, HEIGHT);
3、设置开始界面
void start() {setbkcolor(WHITE); // 白色背景cleardevice(); // 初始化背景settextcolor(BLACK); // 改字体setbkmode(TRANSPARENT); //设置背景是透明的//加载背景图片IMAGE image;loadimage(&image, _T("D:\\桌面\\file2\\球球大作战\\source\\Ball Ball\\x64\\img\\10.jpg"), WIDTH, HEIGHT);//在当前设备上绘制指定图像putimage(0, 0, &image);//加入提示信息settextcolor(WHITE);settextstyle(22, 0, _T("黑体"));outtextxy(50, 480, _T("请选择关卡:"));outtextxy(50, 550, _T("1.小试牛刀"));outtextxy(200, 550, _T("2.炉火纯青"));outtextxy(350, 550, _T("3.登峰造极"));settextstyle(15, 0, _T("宋体"));outtextxy(600, 550, _T("注:按序号选择,默认选择关卡1;游戏中按空格键可以暂停。"));settextcolor(BLACK);settextstyle(22, 0, _T("黑体"));TCHAR s[5];//_stprintf(s, _T("%d"), readCount());_stprintf_s(s, _countof(s), _T("%d"), readCount());outtextxy(810, 200, _T("欢迎进入游戏!"));outtextxy(810, 240, _T("游戏次数:"));outtextxy(910, 240, s);
}
4、让玩家选择速度
void ChooseSpeed() {switch (_getch()) {case 1:speed = 4;case 2:speed = 3;case 3:speed = 2;default:speed = 4;}
}
5、设置玩家小球、人机小球、食物的属性
void setall() {srand((unsigned)time(NULL)); // 随机数mover.color = RGB(rand() % 256, rand() % 256, rand() % 256); // 随机颜色mover.life = 1; // 赋初值1//把玩家的球一直放在屏幕中央mover.x = int(WIDTH * 0.5);mover.y = int(HEIGHT * 0.5);//设置半径mover.r = 20;
for (int i = 0; i < AINUM; i++) { // AI 的属性ai[i].life = 1;ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);//ai[i].r = float(rand() % 10 + 10);ai[i].r = 20;ai[i].x = rand() % (MAPW - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);ai[i].y = rand() % (MAPH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);}
for (int i = 0; i < FNUM; i++) { // 食物的属性food[i].eat = 1;food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);food[i].x = rand() % MAPW;food[i].y = rand() % MAPH;food[i].type = rand() % 10 + 1;}
pBuffer = GetImageBuffer(NULL); // 获取显存指针setbkcolor(WHITE); // 白色背景cleardevice(); // 初始化背景settextcolor(LIGHTRED); // 改字体//设置背景是透明的setbkmode(TRANSPARENT);settextstyle(16, 0, _T("宋体"));
}
6、一次性把图绘制到界面里
BeginBatchDraw();
7、进入死循环
8、移动玩家小球
void move(BALL* ball) {if (ball->r <= 0)ball->life = false;if (ball->life == false) { // 判定游戏是否接束HWND hwnd = GetHWnd();MessageBox(hwnd, _T("你被吃了"), _T("游戏结束"), MB_ICONEXCLAMATION);endtime();
}
if (eaten + ai_eaten == AINUM) // 是否吃掉所有 AI{HWND hwnd = GetHWnd();MessageBox(hwnd, _T("恭喜过关"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION); // 结束endtime();}
for (int i = 0; i < AINUM; i++) { // 玩家吃 AI 判定if (ball->r >= ai[i].r) {if (ai[i].life == 0) continue;if (DISTANCE(ball->x, ball->y, ai[i].x, ai[i].y) < (4 / 5.0 * (ball->r + ai[i].r))) {ai[i].life = 0; //AI被吃ball->r = sqrt(ai[i].r * ai[i].r + ball->r * ball->r);eaten++;}}}
for (int n = 0; n < FNUM; n++) { // 玩家吃食物if (food[n].eat == 0) continue;if (DISTANCE(ball->x, ball->y, food[n].x, food[n].y) < ball->r) {ball->r += 4 / ball->r; // 增加面积food[n].eat = 0; // 食物被吃}}
static int mx = 0, my = 0; // 记录偏移量
//判断怎么移动if (GetAsyncKeyState(VK_UP) && (ball->y - ball->r > 0 && ball->y <= (MAPH - ball->r + 10))) {ball->y -= speed;my += speed;}if (GetAsyncKeyState(VK_DOWN) && (ball->y - ball->r >= -10 && ball->y < (MAPH - ball->r))) {ball->y += speed;my -= speed;}if (GetAsyncKeyState(VK_LEFT) && ball->x - ball->r > 0 && (ball->x <= (MAPW - ball->r + 10))) {ball->x -= speed;mx += speed;}if (GetAsyncKeyState(VK_RIGHT) && ball->x - ball->r >= -10 && (ball->x < (MAPW - ball->r))) {ball->x += speed;mx -= speed;}
//判断是否输入其他用于退出、暂停、继续的按键if (GetAsyncKeyState(VK_SPACE)) {settextcolor(WHITE);settextstyle(32, 0, _T("宋体"));outtextxy(384 - mx, 350 - my, _T("游戏已暂停!"));outtextxy(20 - mx, 500 - my, _T("(ESC)退出"));outtextxy(780 - mx, 500 - my, _T("(回车键)继续"));FlushBatchDraw();_getch();if (GetAsyncKeyState(VK_ESCAPE))exit(0);else_getch();}
setorigin(mx, my); //坐标修正
}
9、移动人机
void AI() {for (int i = 0; i < AINUM; i++) { // AI 吃玩家if (ai[i].r > mover.r) {if (DISTANCE(mover.x, mover.y, ai[i].x, ai[i].y) < (ai[i].r + mover.r)) {ai[i].r = sqrt(ai[i].r * ai[i].r + mover.r * mover.r);mover.life = 0;mover.r = 0;}}for (int j = 0; j < AINUM; j++) { // AI 吃 AIif (ai[i].r > ai[j].r) {if (ai[j].life == 0) continue;if (DISTANCE(ai[i].x, ai[i].y, ai[j].x, ai[j].y) < (ai[i].r + ai[j].r)) {ai[i].r = sqrt(ai[i].r * ai[i].r + ai[j].r * ai[j].r);ai[j].life = 0;ai[j].r = 0;ai_eaten++;}}}
double min_DISTANCE = 100000;int min = -1;for (int k = 0; k < AINUM; k++) { // AI 靠近 AIif (ai[i].r > ai[k].r && ai[k].life != 0) {if (DISTANCE(ai[i].x, ai[i].y, ai[k].x, ai[k].y) < min_DISTANCE) {min_DISTANCE = DISTANCE(ai[i].x, ai[i].y, ai[k].x, ai[k].y);min = k;}}}if ((min != -1) && (rand() % 2 == 1) && (ai[i].y - ai[i].r > 0 && ai[i].y <= (MAPH - ai[i].r + 10))) {if (rand() % 2) {if (ai[i].x < ai[min].x)ai[i].x += speed ;elseai[i].x -= speed ;}else {if (ai[i].y < ai[min].y)ai[i].y += speed ;elseai[i].y += speed ;}}for (int n = 0; n < FNUM; n++) { // AI 吃食物if (food[n].eat == 0) continue;if (DISTANCE(ai[i].x, ai[i].y, food[n].x, food[n].y) < ai[i].r) {ai[i].r += 4 / ai[i].r;food[n].eat = 0;}}}
}
10、食物刷新
void Food() {for (int i = 0; i < FNUM; i++) { // 食物刷新if (food[i].eat == 0) {food[i].eat = 1;food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);food[i].x = rand() % MAPW;food[i].y = rand() % MAPH;food[i].type = rand() % 10 + 1;}}
}
11、画出边界、食物、人机、玩家、小地图,添加击杀数、半径(质量)、玩家名字
void draw() {float asp = 1;//清空裁剪区,超出区域的绘图操作将被裁剪掉clearcliprgn();IMAGE image;loadimage(&image, _T(""), WIDTH * 4, HEIGHT * 4);putimage(0, 0, &image);//绘画出一个矩形框setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 20); // 改变笔的颜色、状态setlinecolor(RGB(0, 100, 0));line(-20, MAPH + 20, -20, -20); // 左竖line(-20, MAPH + 20, MAPW + 20, MAPH + 20); // 上横line(-20, -20, MAPW + 20, -20); // 下横line(MAPW + 20, -20, MAPW + 20, MAPH + 20); // 右竖setfillcolor(GREEN);//当球接近边界时,会在边界外侧绘制一个绿色的填充矩形,// 是用来表示碰撞或者边界的视觉效果if (mover.x - 0.5 * WIDTH / asp < -20)floodfill(-20 - 11, mover.y, RGB(0, 100, 0));if (mover.x + 0.5 * WIDTH / asp > MAPW + 20)floodfill(MAPW + 20 + 11, mover.y, RGB(0, 100, 0));if (mover.y - 0.5 * HEIGHT / asp < -20)floodfill(mover.x, -20 - 11, RGB(0, 100, 0));if (mover.y + 0.5 * HEIGHT / asp > MAPH + 20)floodfill(mover.x, MAPH + 20 + 11, RGB(0, 100, 0));setlinecolor(WHITE);setlinestyle(PS_NULL);for (int i = 0; i < FNUM; i++) { // 画出食物if (food[i].eat == 0) continue;setfillcolor(food[i].color);switch (food[i].type) { // 形状case 1: solidellipse(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;case 2: solidellipse(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2); break;case 3: solidrectangle(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2); break;case 4: solidrectangle(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;case 5: solidroundrect(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4, 2, 2); break;case 6: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 2); break;case 7: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 4, 2); break;case 8: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 4); break;case 9: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 1, 1); break;case 10: fillcircle(food[i].x, food[i].y, 4); break;}}for (int i = 0; i < AINUM; i++) { // 画 AIif (ai[i].life == 0) continue;setfillcolor(ai[i].color);//绘圆fillcircle(ai[i].x, ai[i].y, int(ai[i].r + 0.5));}setfillcolor(mover.color); // 画玩家fillcircle(mover.x, mover.y, int(mover.r + 0.5));IMAGE map(150, 100); // 小地图SetWorkingImage(&map);setbkcolor(RGB(120, 165, 209)); // 浅灰色背景cleardevice();for (int i = 0; i < AINUM; i++) // 画 AI(小地图){if (ai[i].life == 0) continue;setfillcolor(ai[i].color);fillcircle(ai[i].x * 150 / WIDTH / 4, ai[i].y * 100 / HEIGHT / 4, int(ai[i].r / 28 + 1.5));}setfillcolor(mover.color); // 画玩家(小地图)fillcircle(mover.x * 150 / WIDTH / 4, mover.y * 100 / HEIGHT / 4, int(mover.r / 28 + 3.5));setlinecolor(RGB(0, 100, 0));SetWorkingImage(); // 恢复绘图背景putimage(mover.x + int(0.5 * WIDTH) - 150, mover.y - int(0.5 * HEIGHT), 150, 100, &map, 0, 0); // 画出小地图setlinecolor(LIGHTBLUE);setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 4);line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT), mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99); // 地图边框线line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99, mover.x + int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT) + 99); // 地图边框线setlinestyle(PS_NULL); // 恢复笔TCHAR str[32];swprintf_s(str, _T("质量:%.1fg 击杀:%d"), mover.r, eaten);settextcolor(WHITE); // 改字体outtextxy(mover.x - int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT), str);settextcolor(WHITE);outtextxy(mover.x - 20, mover.y, _T("itlsl"));
}
12、将内存中的绘图操作批量地绘制到屏幕上,从而提高绘图效率
FlushBatchDraw();
四、代码预览+运行结果
源代码+流程图+README资源:https://download.csdn.net/download/2403_82436914/90623088?spm=1001.2014.3001.5503