上分宝:值得大家信赖的下载网站!
时间:2023-08-23 14:44:32来源:互联网
这是一个贪吃蛇大作战类游戏,修改特性为 AI 不互杀;
该程序有四个类:蛇基类 SnakeBase,玩家类 Player,AI 类,Game 类;SnakeBase 和 AI 均继承自 SnakeBase,SnakeBase 提供基础接口;
Game 提供数据初始化以及游戏主循环。
程序设计之初,采用“实运行”方式,即所有动画均在地图 imgMap 上真实绘制,这样却有一些严重的问题,需要不断地记录节点背景以恢复节点经过的地方等。
后修改为“虚运行”方式,判断位置是否可视后直接绘至窗口内,这样大大降低时间开销,同时不会因为蛇靠近而产生不可擦除的颜色。
至于蛇运行,采用位置继承,即节点下一个位置为上一个节点的位置,但是会发现跨度太大,解决办法是在这个跨度中插入适当帧数。
执行效果如下:
完整的游戏源代码如下:
/* 程序名称: 贪吃蛇大作战 简介: 简单模拟了游戏 贪吃蛇大作战 程序运行中可以通过 ESC 直接退出 左键或右键可以加速移动,加速会消耗长度 环境: VS2019 EasyX_20190529(beta) 作者: Teternity(QQ:1926594835)*/////////// 头文件 //////////include include pragma comment( lib, "MSIMG32.LIB")////////// 窗口大小 //////////const short ScreenWidth = 640;const short ScreenHeight = 480;////////// 全局变量 //////////long ret = 0;MOUSEMSG msg;const short gap = 20;const short xSide = ScreenWidth / 2 gap;const short ySide = ScreenHeight / 2 gap;IMAGE* imgMap = new IMAGE(ScreenWidth * 4, ScreenHeight * 4);const double PI = 3.1415926;const short nodeSize = 17;const short nodeGap = 16;const short stepLen = 4;const short frame = 4;const short snakeSpecies = 20;int killCount = 0;int mapX = 0;int mapY = 0;typedef struct _FOOD{ int x; int y; int r; COLORREF c;}Food;Food* food;short nFood = 520;IMAGE imgFood(nodeSize, nodeSize);const COLORREF mapMainColor = WHITE;const COLORREF playerColor0 = RGB(120, 0, 0);const COLORREF playerColor1 = RGB(200, 0, 0);const COLORREF playerColor2 = RGB(255, 255, 0);const COLORREF mapLineColor = RGB(225, 225, 225);// 透明贴图函数:(更多内容请参考官网)// 参数:// x, y: 目标贴图位置// srcimg: 源 IMAGE 对象指针。null 表示默认窗体// dstimg: 目标 IMAGE 对象指针。NULL 表示默认窗体// transparentcolor: 透明色。srcimg 的该颜色并不会复制到 dstimg 上,从而实现透明贴图void putTimage(int x, int y, IMAGE* srcimg, IMAGE* dstimg = NULL, UINT transparentcolor = 0){ HDC dstDC = GetImageHDC(dstimg); HDC srcDC = GetImageHDC(srcimg); int w = srcimg->getwidth(); int h = srcimg->getheight(); // 使用 Windows GDI 函数实现透明位图 TransparentBlt(dstDC, x, y, w, h, srcDC, 0, 0, w, h, transparentcolor);}////////// 蛇基类 //////////class SnakeBase{public: // 构造函数 SnakeBase() { Count ; isDead = false; length = 50 rand() % 50; nNode = length / 5; maxNode = 9999; imgHead = imgNode = imgTail = nullptr; headNode = tailNode = nullptr; nodeMsg = nullptr; } // 析构函数 virtual ~SnakeBase() { Count--; Node* temp = headNode; while (temp != nullptr) { headNode = headNode->nextNode; delete temp; temp = headNode; } delete imgHead, imgNode, imgTail; if (nodeMsg != nullptr) delete[] nodeMsg; } // 设置image void SetImage(COLORREF headColor, COLORREF nodeColor, COLORREF tailColor){ imgHead = new IMAGE(nodeSize, nodeSize); imgNode = new IMAGE(nodeSize, nodeSize); imgTail = new IMAGE(nodeSize, nodeSize); SetWorkingImage(imgHead); setfillcolor(headColor); solidcircle(nodeSize / 2, nodeSize / 2, nodeSize / 2); setfillcolor(tailColor); solidcircle(nodeSize / 2, nodeSize / 2, 2); SetWorkingImage(imgNode); setfillcolor(nodeColor); solidcircle(nodeSize / 2, nodeSize / 2, nodeSize / 2); SetWorkingImage(imgTail); setfillcolor(tailColor); solidcircle(nodeSize / 2, nodeSize / 2, nodeSize / 2); SetWorkingImage(); } // 创建各节点 void Creat(int headX, int headY){ headNode = new Node; headNode->lastNode = nullptr; headNode->nextNode = nullptr; headNode->x = headX; headNode->y = headY; Node* temp = headNode; for (int i = 0; i lastNode = temp; newNode->x = temp->x; newNode->y = temp->y; temp->nextNode = newNode; temp = newNode; } temp->nextNode = nullptr; tailNode = temp; temp = nullptr; } // 绘制蛇身 void ShowBody(){ int n = nNode % 2; Node* temp = tailNode; while (temp != headNode) { if (temp->x - nodeSize / 2 mapX >= nodeSize * -1 && temp->x - nodeSize / 2 mapX y - nodeSize / 2 mapY >= nodeSize / -2 && temp->y - nodeSize / 2 mapY x - nodeSize / 2 mapX, temp->y - nodeSize / 2 mapY, n % 2 == 0 ? imgNode : imgTail); temp = temp->lastNode; n ; } if (temp->x - nodeSize / 2 mapX >= nodeSize * -1 && temp->x - nodeSize / 2 mapX y - nodeSize / 2 mapY >= nodeSize / -2 && temp->y - nodeSize / 2 mapY x - nodeSize / 2 mapX, temp->y - nodeSize / 2 mapY, imgHead); temp = nullptr; } // 刷新数据 void FlushData(short& n, int& dx, int& dy){ if (n == frame) { nodeMsg = new POINT[nNode]; Node* temp = headNode; int i = 0; while (temp != nullptr) { nodeMsg[i].x = temp->x; nodeMsg[i].y = temp->y; temp = temp->nextNode; i ; } } Node* temp = tailNode; int i = nNode - 2; while (temp != headNode) { if (n == 1) { temp->x = nodeMsg[i].x; temp->y = nodeMsg[i].y; } else { temp->x = int(stepLen * cos(atan2(nodeMsg[i].y - temp->y, nodeMsg[i].x - temp->x))); temp->y = int(stepLen * sin(atan2(nodeMsg[i].y - temp->y, nodeMsg[i].x - temp->x))); } temp = temp->lastNode; i--; } temp = nullptr; headNode->x = dx; headNode->y = dy; if (n == 1) { delete[] nodeMsg; nodeMsg = nullptr; } } // 据长度添加节点 void SetNode(int ex = 0){ int n = nNode; length = ex; n = length / 5 - n; if (n > 0) { while (nNode lastNode = tailNode; newNode->nextNode = nullptr; newNode->x = tailNode->x; newNode->y = tailNode->y; tailNode->nextNode = newNode; tailNode = newNode; newNode = nullptr; } } else if (n 10 && n != 0) { n ; nNode--; Node* temp = tailNode; tailNode = tailNode->lastNode; tailNode->nextNode = nullptr; delete temp; temp = nullptr; } if (nNode == 10) length = 50; } } // 吃到食物 bool GetFood(int k, int x, int y){ int len = nodeGap 5; if (x - headNode->x x - x y y - y getwidth() - xSide * 2) xSide; food[k].y = rand() % (imgMap->getheight() - ySide * 2) ySide; food[k].r = rand() % 2 3; food[k].c = HSVtoRGB(float(rand() % 360), rand() % 1000 / 2000.0f 0.5f, rand() % 1000 / 2000.0f 0.5f); return true; } return false; }protected: long length; int nNode; int maxNode; IMAGE* imgHead, * imgNode, * imgTail; POINT* nodeMsg;public: // 蛇节点 typedef struct _NODE { int x; int y; struct _NODE* lastNode; struct _NODE* nextNode; }Node; bool isDead; static int Count; Node* headNode, * tailNode;};int SnakeBase::Count = 0;////////// Player 类 //////////class Player :public SnakeBase{public: // 构造函数 Player() :SnakeBase() { SetImage(playerColor0, playerColor1, playerColor2); int headX = rand() % (imgMap->getwidth() - xSide * 2 - nodeSize * 10) xSide nodeSize; int headY = rand() % (imgMap->getheight() - ySide * 2 - nodeSize * 12) ySide nodeSize; Creat(headX, headY); nt = frame; } // 是否死亡 void IsDead(){ if (headNode->x x >= imgMap->getwidth() - 1 - xSide || headNode->y y >= imgMap->getheight() - 1 - ySide) isDead = true; else { double radian = atan2(headNode->y - headNode->nextNode->y, headNode->x - headNode->nextNode->x); int x = ScreenWidth / 2 int(nodeSize / 2 * cos(radian)); int y = ScreenHeight / 2 int(nodeSize / 2 * sin(radian)); COLORREF c = getpixel(x, y); if (!(c == mapLineColor || c == mapMainColor)) isDead = true; else { for (int i = 1; i < 8; i ) { x = ScreenWidth / 2 int(nodeSize / 2 * cos(radian)); y = ScreenHeight / 2 int(nodeSize / 2 * sin(radian)); c = getpixel(x, y); if (!(c == mapLineColor || c == mapMainColor)) { isDead = true; break; } x = ScreenWidth / 2 int(nodeSize / 2 * cos(radian)); y = ScreenHeight / 2 int(nodeSize / 2 * sin(radian)); c = getpixel(x, y); if (!(c == mapLineColor || c == mapMainColor)) { isDead = true; break; } } } } } // 移动 void Move(int& ex, int& mapX, int& mapY, short& ddx, short& ddy){ int dx = int(stepLen * cos(atan2(ddy, ddx))); int dy = int(stepLen * sin(atan2(ddy, ddx))); mapX -= dx; mapY -= dy; FlushData(nt, dx, dy); for (int k = 0; k < nFood; k ) if (GetFood(k, food[k].x, food[k].y)) ex = food[k].r / 2; nt--; if (nt getwidth() - xSide * 2 - nodeSize * 3) xSide nodeSize; headY = rand() % (imgMap->getheight() - ySide * 2 - nodeSize * 5) ySide nodeSize; } while (IsInPlayer(headX, headY)); Creat(headX, headY); nt = frame; minLine = 3 * frame; curLine = minLine (rand() % 12) * frame; ddx = (rand() % ScreenWidth) * (rand() % 1000 < 500 ? 1 : -1); ddy = (rand() % ScreenHeight) * (rand() % 1000 x x >= imgMap->getwidth() - 1 - xSide || headNode->y y >= imgMap->getheight() - 1 - ySide) return true; else { bool is_dead = IsInPlayer(headNode->x, headNode->y); if (is_dead) { killCount ; ex = nNode; } return is_dead; } } // 位置是否接触 player bool IsInPlayer(int headX, int headY){ Node* temp = p->headNode; while (temp != nullptr) { if (headX - temp->x x - headX y y - headY nextNode; } return false; } // 移动 void Move(int& ex){ if (curLine <= 0) { double rad = atan2(ddy, ddx); isFast = rand() % 1200 < 100 ? true : false; curLine = minLine (rand() % 21) * frame; do { ddx = (rand() % ScreenWidth 40) * (rand() % 1000 < 500 ? 1 : -1); ddy = (rand() % ScreenHeight 30) * (rand() % 1000 PI / 6 * 5); dx = int(stepLen * cos(atan2(ddy, ddx))); dy = int(stepLen * sin(atan2(ddy, ddx))); } FlushData(nt, dx, dy); for (int k = 0; k < nFood; k ) if (GetFood(k, food[k].x, food[k].y)) exp = food[k].r / 2; nt--; curLine--; if (nt <= 0) { nt = frame; if (rand() % 1000 < 120) { SetNode(rand() % 5 exp); exp = 0; } if (rand() % 1000 < 80) curLine = 0; if (rand() % 1000 0) // 90% 概率避免出界 { int deadX = headNode->x int((rand() % 50 nodeGap) * cos(atan2(ddy, ddx))); int deadY = headNode->y int((rand() % 50 nodeGap) * sin(atan2(ddy, ddx))); if (deadX = imgMap->getwidth() - 1 - xSide) { ddx *= -1; ddy = rand() % 30 30; } if (deadY = imgMap->getheight() - 1 - ySide) { ddy *= -1; ddx = rand() % 40 40; } dx = int(stepLen * cos(atan2(ddy, ddx))); dy = int(stepLen * sin(atan2(ddy, ddx))); } if (rand() % 1000 0) // 40%-80%(也可以理解为60%) 概率躲避 player { int deadX = headNode->x int((nodeGap 5) * cos(atan2(ddy, ddx))); int deadY = headNode->y int((nodeGap 5) * sin(atan2(ddy, ddx))); if (IsInPlayer(deadX, deadY)) { ddx = -1 * ddx rand() % 40 40; ddy = -1 * ddy rand() % 30 30; } dx = int(stepLen * cos(atan2(ddy, ddx))); dy = int(stepLen * sin(atan2(ddy, ddx))); } } isDead = IsDead(ex); if (isDead) { int n = nNode / 2; Node* temp = headNode->nextNode->nextNode; while (n--) { for (int k = 0; k < nFood; k ) { if (food[k].x -1 * mapX nodeSize * 2 ScreenWidth || food[k].y -1 * mapY nodeSize * 2 ScreenHeight) { food[k].x = temp->x (rand() % 5 3) * (rand() % 100 y (rand() % 5 3) * (rand() % 100 nextNode; } temp = nullptr; } }private: short nt; int minLine; int curLine; int ddx, ddy; int dx, dy; Player* p;public: bool isFast; clock_t ct; int exp;};////////// 游戏主体类 //////////class Game{public: // 构造函数 Game() { flushTime = 32; setbkmode(TRANSPARENT); BeginBatchDraw(); SetWorkingImage(imgMap); setlinecolor(mapLineColor); setfillcolor(mapMainColor); setbkcolor(BROWN); cleardevice(); solidrectangle(xSide, ySide, imgMap->getwidth() - 1 - xSide, imgMap->getheight() - 1 - ySide); for (int i = gap xSide; i getwidth() - xSide; i = gap) line(i, ySide, i, imgMap->getheight() - 1 - ySide); for (int j = gap ySide; j getheight() - ySide; j = gap) line(xSide, j, imgMap->getwidth() - 1 - xSide, j); SetWorkingImage(); player = new Player; mapX = -1 * (player->headNode->x - ScreenWidth / 2); mapY = -1 * (player->headNode->y - ScreenHeight / 2); ai = new Ai; ai->ais = new AI(player); Ai* temp = ai; for (int i = 1; i next = new Ai; temp = temp->next; temp->ais = new AI(player); } temp->next = ai; temp = nullptr; food = new Food[nFood]; for (int k = 0; k getwidth() - xSide * 2) xSide; food[k].y = rand() % (imgMap->getheight() - ySide * 2) ySide; food[k].r = rand() % 2 3; food[k].c = HSVtoRGB(float(rand() % 360), rand() % 1000 / 2000.0f 0.5f, rand() % 1000 / 2000.0f 0.5f); } Draw(); outtextxy((ScreenWidth - textwidth(_T("左键或右键加速"))) / 2, ScreenHeight / 4 * 3 25, _T("左键或右键加速")); outtextxy((ScreenWidth - textwidth(_T("按任意键继续"))) / 2, ScreenHeight / 4 * 3 50, _T("按任意键继续")); FlushBatchDraw(); ret = _getwch(); } // 析构函数 ~Game() { EndBatchDraw(); delete imgMap; delete player; if (ai != nullptr) { Ai* temp = ai->next; while (temp != ai) { delete temp->ais; temp = temp->next; } delete ai->ais; delete ai; } } // 绘制食物 void DrawFood(){ for (int k = 0; k = 0 && food[k].x - 9 mapX = 0 && food[k].y - 9 mapY <= ScreenHeight) { if (food[k].r next; while (temp != ai) { temp->ais->ShowBody(); temp = temp->next; } temp->ais->ShowBody(); player->IsDead(); player->ShowBody(); player->Print(); FlushBatchDraw(); } // 运行 void Running(){ short ddx = 0; short ddy = 0; time_t ct = clock() - time_t(100); Ai* temp = ai->next; while (temp != ai) { temp->ais->ct = clock(); temp = temp->next; } temp->ais->ct = clock(); temp = temp->next; int ex = 0; bool isFast = false; while (!(GetAsyncKeyState(VK_ESCAPE) & 0x8000) && !player->isDead) { if (GetAsyncKeyState('P') & 0x8000) ret = _getwch(); if (clock() - ct > flushTime) { ct = clock(); isFast = (msg.mkLButton || msg.mkRButton) ? true : false; player->Move(ex, mapX, mapY, ddx, ddy); if (isFast) { player->Move(ex, mapX, mapY, ddx, ddy); if (rand() % 1000 ais->ct > flushTime && !player->isDead) { temp->ais->ct = clock(); temp->ais->Move(ex); if (temp->ais->isDead) { delete temp->ais; temp->ais = new AI(player); temp->ais->ct = clock(); } else if (temp->ais->isFast) { temp->ais->Move(ex); if (temp->ais->isDead) { delete temp->ais; temp->ais = new AI(player); temp->ais->ct = clock(); } } ai = ai->next; temp = temp->next; } } }private: int flushTime; Player* player; typedef struct _AI { AI* ais; struct _AI* next; }Ai; Ai* ai;};////////// 主函数 //////////int main(){ initgraph(ScreenWidth, ScreenHeight); srand((unsigned)time(NULL)); Game game; game.Running(); settextcolor(BLACK); settextstyle(50, 0, _T("微软雅黑")); outtextxy((ScreenWidth - textwidth(_T("游戏结束"))) / 2, ScreenHeight / 3, _T("游戏结束")); settextstyle(20, 0, _T("微软雅黑")); outtextxy((ScreenWidth - textwidth(_T("按任意键退出"))) / 2, ScreenHeight / 4 * 3 50, _T("按任意键退出")); FlushBatchDraw(); while (_kbhit()) ret = _getwch(); ret = _getwch(); closegraph(); return 0;}
大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C 项目案例,帮助大家在学习C语言的道路上披荆斩棘!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!
对于C/C 感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C 的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!
上海市初中学生综合素质评价登录入口
宝可梦属性克制表2024最新,18种属性克制关系
王者荣耀排位巅峰赛荣耀战力加分公式规则2024
魔塔50层攻略隐藏道具图解,魔塔50层详细图文攻略
美国zoom动物仙踪林详情介绍
重装机兵攻略隐藏物品图文详解,战车具体位置
推荐几款超污的手游游戏,6个很污的养成类游戏
希尔薇攻略
原神主c排行2023,4.2目前各系最强主c角色排名
action对魔忍
动作游戏
2233盒子
其他游戏
oppo助手2.0
其他游戏
touchitrikka
益智休闲
qq飞车测试服
赛车竞速
青云纪事
角色扮演
泰拉tmodloader
其他游戏
菜菜音乐盒
其他游戏
迷你世界老版本0.44.2版本
模拟经营
极乐园
聊天交友
湖北农村商业银行
金融理财
51品茶
交友约会
极乐园paradise
聊天交友
丝目
社交聊天
七点工具箱
工具应用
酷狗输入法(搜狗输入法)
常用工具
shopee东南亚跨境电商
境外购物
日本大阪usj
生活实用