contributor

快乐分享,一起学习进步~

墨攻棋阵 - 黑白棋中的 AI

到了考试周了佯,可是偏偏这个时候迎来了很多很多的课程设计,幸好教授把C语言的课程设计提前发出了,不然都在最后几周,加上数据结构的课程设计就没有时间做这个啦~ 刚开始打算做成UWP应用的,可是网上的教程都是C#,并且用C++做的话某些功能和C#不一样,所以就这样拖了好多周,省赛前一点儿也没有开始做,等到省赛结束之后,别人都差不多完成啦!而我才开始准备查找资料…… 然而一周过去了,进度还是0%。噫,1%吧! 眼看就要开始验收了,算了,还是用最简单的 EasyX 做吧!以后的 C# 课程设计再考虑 UWP。 周一开始敲代码,整整一周的课余时间,都在努力做这个,现在想起来,那个时候真的好累唉,居然没有感觉到~ 最初做这个游戏是因为想起来 秦时明月 中的 墨攻棋阵 ,也就是黑白棋,努力还原动漫中的场景,周末的时候终于完成了。 先附图:     怎么说千千也都是新手呢!感觉做的还算满意吧! 人机对战中有三种模式哦!简单、中等、困难 那么,接下来,我们一起来看看黑白棋中的AI是如何实现的。 对于我们来说,下棋的时候总是想着如何才能对自己最有利,当前最优?还是全局最优? 如果我们往后几步考虑的话,那便是全局最优啦!那当我们只看眼下哪一个位置的落子对自己最有利,这样便是当前最优,也是局部最优。 在黑白棋中,我们同样可以采用这样的思想。 首先来看看简单AI,因为简单呗,所以它返回的仅仅只是当前的最优解,再怎么说也不能让它随机返回坐标对吧! 那局部最优解又是以什么为评测标准的呢? 嗯,我们采用的是能够转换对方棋子最多的位置,这个可不是行动力哦! POINT2 Easy() //人机对战简单AI { POINT2 MAX; //定义以及初始化最优解 MAX.INIT(0, 0); int maxx = 0; for (int i = 0; i < SIZE; ++i) for (int j = 0; j < SIZE; ++j) { if (expect[i][j] >= maxx) //寻找可以转化棋子最多的点作为最优解 { maxx = expect[i][j]; MAX.INIT(i, j); } } if (ESCEXIT)gameStart(); Sleep(800); //间歇 return MAX; //返回最优解 } 呐,expect中便是每个点可以转换对方棋子的个数,这个 AI 简单吧! 其他难度 AI: 既然是简单以上的难度,就不能再像那样简单啦!不然一个中等AI被简单AI击败多没意思,O(∩_∩)O哈哈~ 首先,我们应该知道一个估值表的问题,在黑白棋中,不同位置都有不同位置的估值,虽然这样的估值表的用处并不是很大,但却在某些细节中表现出至关重要的作用。 黑白棋的棋盘默认是8*8的,总共64格。 从游戏规则我们可以看出来,角上的子很重要,因为这里不会被对方转换,角边上的点很危险,它给了对方直接进角的机会。 边上中间的四个点比较重要,只能从一个方向被翻转……等等。 根据这样的经验,我们大致可以得到以下的估值表: A B C D E F G H 1 90 -60 10 10 10 10 -60 90 2 -60 -80 5 5 5 5 -80 -60 3 10 5 1 1 1 1 5 10 4 10 5 1 1 1 1 5 10 5 10 5 1 1 1 1 5 10 6 10 5 1 1 1 1 5 10 7 -60 -80 5 5 5 5 -80 -60 8 90 -60 10 10 10 10 -60 90 有了这张表,AI 进行估值的时候就很简单了,不过仅凭这一点可不行哦! 黑白棋的AI中,我们要考虑的除了估值表,还有稳定子。 稳定子,即不能被转换的棋子,稳定子的数量在游戏中是变化的,比如,一方占据整整一条边,那么这一条边上的所有棋子都是稳定子。 行动力,某方当前可走位置的个数,因为在黑白棋的游戏规则中,每一步的走棋都要形成转换,否则不能走棋,既然这样的话,我们在AI中便要尽可能让自己的行动力最大,而对方行动力最小,也就是尽可能让双方行动力差最大,这样的话,很容易AI便可以把玩家逼上绝路,玩笑而已…… 除了这两个还有余裕手和潜在行动力,虽然并不懂~ 对电脑AI设定中,我们的原则是能走角就走角,不到万不得已的情况下不要走邻角点。 对其他情况下采用极大极小博弈树搜索: 这里假设AI的对手都是最聪明的,会选择最优解,即会选择对AI最不利的选择。 搜出来的结果集是AI方的结果,那么要选择最终得分最高的那个位置 搜出来的结果集是玩家方的结果,那么要选择最终得分最低的那个位置。 如下图: 假设圆形代表的是AI节点,方形代表玩家节点。 对于A2和A3这两种选择,AI显然是选择A2得10分。对于A4和A4这两种选择,AI显然是选择A4得20分。 但是对于B1,B2来说,玩家如果下B2,使得AI可以得20分,下B1,使得AI只能得10分,那么玩家显然是下B1。 所以最终A1这一步,AI只能得10分。这就是极大极小算法。 然后就是α-β剪枝: 现在A2,A3已经选出最大值10,B1的得分是10分。 而对于B1,B2来说是要选最小值,既然B1的得分是10分,则B1,B2之间的最终结果是<=10的。 而A4的得分是20分,对于A4,A5来说是选择最大值得,即A4,A5之间的最终结果是>=20的,说明B2的最终结果是>=20的。 那么这种情况下肯定是选B1了,对于还没有搜索的A5节点来说,已经影响不到最终的选择结果了,所以就可以不用考虑了。 然后得分的计算: 这里每一步的得分,都是相对于AI来说的得分。 AI自己落子某一个位置,得一个正分,之后对手落子某一个位置,所得的分数对于AI来说就是一个负分(即玩家取得的优势,对于AI来说就是劣势)。 对于已经搜到最大深度的节点来说,它的得分就是这个位置的本身得分(因为后面已经不搜了)。 而对于中途节点来说,它的得分应该是这个位置的本身得分,加上下一步对方的选择结果的得分。这里不能只以最后一步的结果逆推的。 举个例子: 如上图的左右两种情况。 假设圆形代表的是AI节点,方形代表玩家节点。 其中分值表示的是节点自身落子该位置所获得的在估值表中的得分,玩家节点取负分。 如果只是用最深层的节点的得分,来计算最上层的节点的得分,那么按照上面极大极小算法,AI最后的得分:左边是10分,右边是5分。那么AI选择左边的10分这种情况。 但是却造成了中间过程中,玩家可以得到50分的这样一个相对来说是比较好的分值。 而AI应该不让玩家取得这样一个比较好的优势。 所以要综合前后对方的落子位置以及得分来考虑最终得分: AI最后的得分:左边是-30分,右边是-15分。最终选择为右边,而不是左边。 极大极小搜索就是这样了,难度的抉择取决于搜索的深度,不过要保证的是不要超时哦! 接下来附上我的 墨攻棋阵 中的AI算法,估计只有一点点的沾边吧! 还有很多需要优化的地方惹 int difai(int x,int y,int mapnow[SIZE][SIZE],int expectnow[SIZE][SIZE],int depin,int depinmax) //极大极小搜索 { if (depin >= depinmax)return 0; //递归出口 int maxx = -10005; //最大权值 POINT2 NOW; int expectnow2[SIZE][SIZE] , mapnow2[SIZE][SIZE],mapnext[SIZE][SIZE],expectlast[SIZE][SIZE]; //定义临时数组 copymap(mapnow2, mapnow); //复制当前棋盘 mapnow2[x][y] = NOWCOLOR ? 1 : -1; //模拟在当前棋盘上下棋 int ME = MAPPOINTCOUNT[x][y] + expectnow[x][y]; //当前棋子权 NOW.INIT(x,y); Change(NOW, mapnow2, false); //改变棋盘AI结束 int MAXEXPECT = 0, LINEEXPECT = 0, COUNT = 0; for (int i = 0; i < SIZE; ++i) for (int j = 0; j < SIZE; ++j) { expectnow2[i][j] = Judge(i, j, !NOWCOLOR, mapnow2);//预判对方是否可以走棋 if (expectnow2[i][j]) { ++MAXEXPECT; if ((i == 0 && j == 0) || (i == 0 && j == SIZE - 1) || (i == SIZE - 1 && j == SIZE - 1) || (i == SIZE - 1 && j == 0))return -1800; //如果对方有占角的可能 if ((i < 2 && j < 2) || (i < 2 && SIZE - j - 1 < 2) || (SIZE - 1 - i < 2 && j < 2) || (SIZE - 1 - i < 2 && SIZE - 1 - j < 2))++LINEEXPECT; } } if (LINEEXPECT * 10 > MAXEXPECT * 7)return 1400;//如果对方走到坏点状态较多 剪枝 for (int i = 0; i < SIZE; i++) for (int j = 0; j < SIZE; j++) if (expectnow2[i][j]) //如果对方可以走棋 { int YOU = MAPPOINTCOUNT[i][j] + expectnow2[i][j];//当前权值 copymap(mapnext, mapnow2); //拷贝地图 mapnext[i][j] = (!NOWCOLOR) ? 1 : -1; //模拟对方走棋 NOW.INIT(i, j); Change(NOW, mapnext, false); //改变棋盘 for (int k = 0; k < SIZE; k++) for (int l = 0; l < SIZE; l++) expectlast[k][l] = Judge(k, l, NOWCOLOR, mapnext); //寻找AI可行点 for (int k = 0; k < SIZE; k++) for (int l = 0; l < SIZE;l++) if (expectlast[k][l]) { int nowm = ME - YOU + difai(k, l, mapnext, expectlast, depin + 1, depinmax); maxx = maxx < nowm ? nowm : maxx; } } return maxx; } 有关黑白棋AI极大极小搜索的算法也就这些了,希望本文能对你有一点帮助。 另外,墨攻棋阵的项目源码在我的 GitHub 里面,欢迎大家 Fork ,发现 Bug 后不要忘记给我留言哦! 项目完整源码【请点击这里下载】。 作者:千千QQ:1335661317主页:www.dreamwings.cn编程语言:C++编译环境:VS2015 + EasyX编译平台:Windows

2D 横向对抗射击游戏

花了一天时间,用最新版 easyx 做了一个小游戏,程序中所有的类函数都是内联函数,大约 300 行,开发环境是 Visual Studio 2015 Community,其他的编译器能不能通过编译不确定。 游戏运行截图如下: 代码说明:关于无阻塞延时,首先,先要 ctime 创建一个 clock_t 变量 a,初始化为 clock(),貌似是自从 1970 年到现在的毫秒数。我们要每隔 0.5 秒执行函数 func() 一次。那么创建主循环 while(1)调用前用 clock() - a;如果 clock() - a > 500,那么执行 func(),并把 a 重新赋值为 clock()。如果使用 Sleep(500) 的话,这个循环就只能执行 func 函数了,在此期间什么也做不了。 完整的游戏源代码如下: /* * 作者:674729261 * QQ:2292683261 * 图像引擎:EasyX(http://www.easyx.cn) * 编译环境:Visual Studio 2015 Community * 这只是个小游戏,所以全部内联 * 编译需要先安装 EasyX 2015(beta) */ #include <easyx.h> #include <time.h> #include <conio.h> class Bullet; class Tank; class E_Bullet; class Boss; bool dead = false; bool wined = false; struct pos//坐标类 { int a; int b; }; class E_Bullet//敌人打出的子弹 { public: clock_t d; int x; int y; bool on = false; pos show()//画出新的位置 { setfillcolor(RGB(255, 180, 20)); fillrectangle(x - 5, y - 5, x + 5, y + 5); return pos{ x,y }; } pos del()//覆盖原来的位置 { setfillcolor(0); setlinecolor(0); fillrectangle(x - 5, y - 5, x + 5, y + 5); rectangle(x - 5, y - 5, x + 5, y + 5); return pos{ x,y }; } pos move()//左移 { x -= 3; return pos{ x,y }; } }; class Bullet//玩家打出的子弹,同上 { public: clock_t d; int x; int y; bool on = false; pos show() { setfillcolor(RGB(150, 180, 210)); fillrectangle(x - 5, y - 5, x + 5, y + 5); return pos{ x,y }; } pos del() { setfillcolor(0); setlinecolor(0); fillrectangle(x - 5, y - 5, x + 5, y + 5); rectangle(x - 5, y - 5, x + 5, y + 5); return pos{ x,y }; } pos move()//右移 { x += 3; return pos{ x,y }; } }; class Boss//敌人 { public: bool hurting = false; clock_t d_hurt; COLORREF clr = RGB(0, 130, 125); int x; int y; int hp = 100;//生命 clock_t d;//无阻塞延时,其实不是延时,只是判断举例上一次执行某一函数过了多久 clock_t att_d; bool angle = false;//方向 pos show() { setfillcolor(clr); fillrectangle(x - 20, y - 40, x + 20, y + 40); return pos{ x,y }; } pos del() { setfillcolor(0); setlinecolor(0); rectangle(x - 20, y - 40, x + 20, y + 40); fillrectangle(x - 20, y - 40, x + 20, y + 40); return pos{ x,y }; } void fire(E_Bullet& but)//攻击 { but.on = true;//放置一个子弹 but.x = x -20; but.y = y; but.d = clock(); } void move()//上上下下得移动 { if (angle == true) y -= 5; if (angle == false) y += 5; if (y >= 440) angle = true; if (y <= 40) angle = false; } void hurt()//受伤 { hp -= 4; d_hurt = clock(); setfillcolor(0); setlinecolor(WHITE); fillrectangle(160, 485, 560, 510);//更新血条 rectangle(160, 485, 160+hp*4, 510); setfillcolor(RGB(230, 0, 1)); setlinecolor(RGB(255, 255, 255)); fillrectangle(160, 485,160+hp*4, 510); rectangle(160, 485, 160 + hp * 4, 510); hurting = true; if (hp <= 0)//挂屁 { wined = true; } } }; class Tank//玩家类,同上 { public: bool hurting = false; int hp = 100; int x; COLORREF clr = RGB(150, 180, 210); int y; clock_t d_hurt; Tank(){} Tank(int _x, int _y) { x = _x; y = _y; } Tank operator=(pos p) { x = p.a; y = p.a; } pos show() { setfillcolor(clr); fillrectangle(x - 25, y - 25, x + 25, y + 25); setfillcolor(RGB(100, 200, 180)); fillrectangle(x, y + 5, x + 40, y - 5); return pos{ x,y }; } pos del() { setfillcolor(0); setlinecolor(0); fillrectangle(x - 25, y - 25, x + 25, y + 25); rectangle(x - 25, y - 25, x + 25, y + 25); fillrectangle(x, y + 5, x + 40, y - 5); rectangle(x, y + 5, x + 40, y - 5); return pos{ x,y }; } void fire(Bullet& but) { but.on = true; but.x = x + 45; but.y = y; but.d = clock(); but.show(); } void hurt() { hp -= 2; d_hurt = clock(); setfillcolor(0); setlinecolor(WHITE); fillrectangle(160, 515, 560, 540); rectangle(160, 515, 560, 540); rectangle(160, 515, 160 + hp * 4, 540); setfillcolor(RGB(0, 255, 1)); setlinecolor(RGB(255, 255, 255)); fillrectangle(160, 515, 160 + hp * 4, 540); rectangle(160, 515, 160 + hp * 4, 540); hurting = true; if (hp <= 0) dead = true; } }; #define BT_MAX 8 int main() { initgraph(640, 550, 4);//初始化屏幕 settextcolor(RGB(0, 254, 0)); settextstyle(35, 0, "黑体"); outtextxy(150, 200, "W,S移动,K攻击"); Sleep(3000); setlinecolor(0); setfillcolor(0); rectangle(0, 0, 640, 550); fillrectangle(0, 0, 640, 550); setlinecolor(RGB(255, 255, 255)); setfillcolor(RGB(255, 255, 255)); clock_t delay = clock();//玩家移动的延时 clock_t d_f = clock();//玩家开火的延时 line(0, 481, 640, 481);//分割画面与血条 Bullet bt[BT_MAX];//玩家的子弹 Tank tk(30, 30);//玩家 Boss bo;//敌人 bo.x = 580; bo.y = 240; E_Bullet ebt[BT_MAX];//敌人的子弹 bo.d = clock();//初始化延时 bo.att_d = clock(); tk.show(); settextstyle(20, 0, "黑体"); outtextxy(10,485,"BOSS的生命值:"); setfillcolor(RGB(230, 0, 1)); fillrectangle(160, 485, 560, 510);//敌人血条 outtextxy(10, 520, "玩家的生命值:"); setfillcolor(RGB(0, 255, 1)); fillrectangle(160, 515, 560, 540);//玩家血条 while (1)//主循环 { if (wined||dead)//玩家死了或者敌人死了 break; if (GetAsyncKeyState('W') & 0x8000)//玩家移动 { if (tk.y > 28 && (clock() - delay) >= 40) { tk.del(); tk.y -= 3; tk.show(); delay = clock(); } } if (GetAsyncKeyState('w') & 0x8000)//玩家移动 { if (tk.y > 28 && (clock() - delay) >= 40) { tk.del(); tk.y -= 3; tk.show(); delay = clock(); } } if (GetAsyncKeyState('k') & 0x8000)//玩家开火 { for (int i = 0; i < BT_MAX; i++) { if (bt[i].on == false && (clock() - d_f) > 800) { bt[i].on = true; tk.fire(bt[i]); d_f = clock(); break; } } } if (GetAsyncKeyState('K') & 0x8000)//玩家开火 { for (int i = 0; i < BT_MAX; i++) { if (bt[i].on == false && (clock() - d_f) > 800) { tk.fire(bt[i]); d_f = clock(); break; } } } if (GetAsyncKeyState('S') & 0x8000)//玩家移动 { if (tk.y < 452 && (clock() - delay) >= 40) { tk.del(); tk.y += 3; tk.show(); delay = clock(); } } if (GetAsyncKeyState('s') & 0x8000)//玩家移动 if (tk.y < 452 && (clock() - delay) >= 40) { tk.del(); tk.y += 3; tk.show(); delay = clock(); } for (int i = 0; i < BT_MAX; i++)//遍历子弹,使子弹刷新 { if (bt[i].on == true && (clock() - bt[i].d) > 20) { bt[i].del(); bt[i].move(); bt[i].show(); bt[i].d = clock(); if (bt[i].x >= 635) bt[i].on = false, bt[i].del();//到达了屏幕最右端 if ((bt[i].x + 5 >= bo.x - 20 && bt[i].x - 5 <= bo.x + 20) && (bt[i].y - 5 < bo.y + 40 && bt[i].y + 5 > bo.y - 40)) //击中敌人 bt[i].on = false, bo.hurt(),bt[i].del(); } } if (clock() - bo.att_d > 700)//敌人自动开火 { for (int i = 0; i < BT_MAX; i++) { if (ebt[i].on == false) { bo.fire(ebt[i]); break; } } bo.att_d = clock(); } for (int i = 0; i < BT_MAX; i++)//敌人子弹刷新,同上 { if (ebt[i].on == true && (clock() - ebt[i].d > 20)) { ebt[i].del(); ebt[i].move(); ebt[i].show(); ebt[i].d = clock(); if (ebt[i].x < 5) ebt[i].del(),ebt[i].on = false; if (ebt[i].x - 5 < tk.x + 25 && ebt[i].x + 5 > tk.x - 25 && ebt[i].y - 5 < tk.y + 25 && ebt[i].y + 5 > tk.y - 25) { ebt[i].on = false, tk.hurt(), ebt[i].del(); } } } if (tk.hurting == true)//玩家受伤闪烁0.1秒 if (clock() - tk.d_hurt > 100) { tk.clr = RGB(150, 180, 210), tk.show(), tk.hurting = false; } else tk.clr = RGB(255, 0, 0), tk.show(); if (bo.hurting == true)//敌人受伤闪烁0.1秒 if (clock() - bo.d_hurt > 100) { bo.clr = RGB(0, 130, 125), bo.show(), bo.hurting = false; } else bo.clr = RGB(0, 255, 0), bo.show(); if (clock() - bo.d > 50)//敌人移动延时; bo.del(), bo.move(), bo.show(), bo.d = clock(); } if (wined)//胜负已分 { settextcolor(RGB(0, 254, 0)); settextstyle(35, 0, "黑体"); outtextxy(150, 200, "你打败了boss!你赢了!!"); } else { settextcolor(RGB(254, 0, 0)); settextstyle(35, 0, "黑体"); outtextxy(140, 200, "你被boss打败了!"); } Sleep(5000); closegraph();//关闭画布 return 0; } 作者:674729261QQ:2292683261

2D 射击游戏:大战黑帮

这是一款经典的2D射击游戏,ASDW控制,鼠标左键射击,空格键放技能,P键暂停 你正以一己之力撼动整个社区最大的黑帮!杀死敌人!越多越好! 游戏运行截图如下: 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:Starsky作者邮箱:lcj20000101@163.com

贪吃蛇

一个比较新颖的贪吃蛇程序。 用左右表示蛇向左转或向右转,上用来加速。 源代码如下: /////////////////////////////////// // 程序名称:贪吃蛇 // 编译环境:Visual C++ 6.0 / 2008,EasyX 2013冬至版 // 作者:王垣恒 QQ:646361765 // 最后修改:2014-5-20 // 操作方式:以蛇为第一视角,左 左转;右 右转;下 暂停;上 快进。 // 状态: 黄色 蛇头;红色 蛇身;绿色 食物。 #include <graphics.h> #include <string.h> #include <time.h> #define NUM_R 10 //半径 #define NUM_X 25 //横向个数 #define NUM_Y 25 //纵向个数 #define NUM 30 //所需节点个数 void exe(int x,int y,int f); int GetCommand(); void eat(int x,int y); void clear(); void set(); void flush(); void over(bool a); struct pos //建立链表储存每个关节的位置 { int x; int y; struct pos*next; }; struct pos*head=(pos*)malloc(sizeof(pos)); //建立头指针 int n=0; //记录节点个数 void main() //初始化游戏 { int x,y,f; //储存初始化点的位置方向 srand((unsigned) time(NULL)); //初始化随机库 do { x=rand()%NUM_X*NUM_R*2+NUM_R; y=rand()%NUM_Y*NUM_R*2+NUM_R; } while(x<4*NUM_R || y<4*NUM_R || 2*NUM_R*(NUM_X-2)<x || 2*NUM_R*(NUM_Y-2)<y); //产生不在矩形边缘的初始点 f=rand()%4; //随机方向 struct pos*a=(pos*)malloc(sizeof(pos)),*p=head; //建立链表第一个节点 a->x=x; //指针a储存第一个点数据 a->y=y; head->next=a; //接链 a->next=NULL; //结尾 initgraph(2*NUM_R*NUM_X,2*NUM_R*NUM_Y+50); //初始绘图窗口 setcolor(WHITE); line(0,2*NUM_R*NUM_Y+1,2*NUM_R*NUM_X,2*NUM_R*NUM_Y+1); setcolor(getbkcolor()); //取消圆的边缘 setfillcolor(YELLOW); //设置填充颜色 fillcircle(x,y,NUM_R); //绘出初始点 set(); //产生食物 exe(x,y,f); //进入控制函数 } void exe(int x,int y,int f) //操作游戏 { int xf,yf,c,i; while(1) //进入循环 { c=0; //初始化方向 for(i=0;i<5;i++) //循环5次获取命令 { Sleep(100-50*n/NUM); //等待 if(c==0) //若没获取到命令就进行获取 { c=GetCommand(); if(c==4) //返回4时退出循环等待 break; } } f=f+c; //改变方向 if(f>3) //溢出处理 f=f-4; xf=yf=0; //初始化方向参数 switch(f) { case 0:xf=1;break; //方向向右时 x坐标增加 case 1:yf=1;break; //方向向右时 y坐标增加 case 2:xf=-1;break; //方向向右时 x坐标减少 case 3:yf=-1;break; //方向向右时 y坐标减少 } x=x+2*NUM_R*xf; //x坐标变化 y=y+2*NUM_R*yf; //y坐标变化 if(getpixel(x,y)==RED || x<0 || y<0 || 2*NUM_X*NUM_R<x || 2*NUM_Y*NUM_R<y) //判断是否遇到自身或碰到边界 over(0); //结束游戏 else //不结束进行下步运算 { if(getpixel(x,y)==GREEN) //判断前方是否为食物 set(); //产生新食物 else clear(); //清除尾结点 eat(x,y); //在前方生成新结点 if(n>NUM-1) //判断胜利条件 over(1); //结束游戏 } } } int GetCommand() //获取方向 { int c=0; //初始化方向变量 if(GetAsyncKeyState(VK_RIGHT) & 0x8000) c = 1; //右转为1 if(GetAsyncKeyState(VK_LEFT) & 0x8000) c = 3; //左转为3 if(GetAsyncKeyState(VK_UP) & 0x8000) c = 4; //按上为4 快进 if(GetAsyncKeyState(VK_DOWN) & 0x8000) system("pause"); //按下则暂停 return c; } void eat(int x,int y) //增加新结点 { struct pos*a=(pos*)malloc(sizeof(pos)),*p=head; //声明指针变量 while(p->next!=NULL) //寻找链表尾节点 p=p->next; a->x=x; //把数据储存到结点 a->y=y; p->next=a; //指针a接到尾节点后 a->next=NULL; //结尾 setcolor(getbkcolor()); //取消圆的边缘 setfillcolor(RED); //设置填充颜色 fillcircle(p->x,p->y,NUM_R); //绘制新结点 setfillcolor(YELLOW); //设置填充颜色 fillcircle(x,y,NUM_R); //绘制新结点 } void clear() //清除尾结点 { setcolor(getbkcolor()); //取消圆的边缘 setfillcolor(getbkcolor()); //设置填充颜色 fillcircle(head->next->x,head->next->y,NUM_R); //擦除结点 head->next=head->next->next; //删除节点数据 } void set() //产生食物和胜利判断 { flush(); int x,y; //声明变量 do { x=rand()%NUM_X*NUM_R*2+NUM_R; y=rand()%NUM_Y*NUM_R*2+NUM_R; } while (getpixel(x,y)==RED); //随机产生食物在非蛇的位置 setcolor(getbkcolor()); setfillcolor(GREEN); //设置填充颜色 fillcircle(x,y,NUM_R); //产生食物 } void flush() { n++; //节点计数累加 char strnum[20],string[10]="进度:"; itoa(n,strnum,10); //转换 strcat(string,strnum); //链接 strcpy(strnum,"/"); //赋值 strcat(string,strnum); //连接 itoa(NUM,strnum,10); strcat(string,strnum); setcolor(WHITE); settextstyle(32,0,_T("宋体")); //设置字体类型 outtextxy(20,2*NUM_R*NUM_Y+2," "); outtextxy(20,2*NUM_R*NUM_Y+2,string); } void over(bool a) //结束游戏 { setcolor(WHITE); //设置字体颜色 settextstyle(48,0,_T("宋体")); //设置字体类型 if(a) //判断条件 outtextxy(NUM_X*NUM_R-20,NUM_Y*NUM_R-20,"胜利"); //输出结果 else outtextxy(NUM_X*NUM_R-20,NUM_Y*NUM_R-20,"失败"); //输出结果 Sleep(2000); system("pause"); exit(0); } 作者:王垣恒QQ:646361765

一个简单的小游戏:盒子接球

用VC写了一个小小的游戏,在界面右侧有运行时间,接到的小球个数等信息,有 10 个小球下落,玩家可以控制一个盒子左右移动(方向键),来接小球,按 Esc 键退出,最后会显示接到的小球的数目。就是这么简单。 游戏运行截图如下: 以下是游戏的全部源代码: /////////////////////////////////////////////////// // 程序名称:盒子接球(一个简单的小游戏) // 编译环境:Visual C++ 6.0,EasyX 2013霜降版 // 作  者:圣石 <2464847121@qq.com> // 最后修改:2013-12-1 // 玩法:按方向键控制盒子移动接住小球,总共有 20s 的游戏时间,倒计时为 0 时游戏结束 // #include <graphics.h> #include <conio.h> #include <time.h> #include <stdio.h> // 定义常量 #define NUM 10 #define CMD_LEFT 1 #define CMD_RIGHT 2 #define CMD_QUIT 4 int box_x = 10; int box_y = 420; // 定义球的结构体 struct Ball { int x, y, v; }; // 获取用户控制 int GetCommand() { int c = 0; if (GetAsyncKeyState(VK_LEFT) & 0x8000) c |= CMD_LEFT; if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c |= CMD_RIGHT; if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) c |= CMD_QUIT; return c; } // 倒计时 int Time(int t) { char strsec[10]; int sec = 20 - (GetTickCount() - t) / 1000; itoa(sec, strsec, 10); outtextxy(570, 110, " "); outtextxy(570, 110, strcat(strsec, "s")); return sec; } // 介绍 void menu() { line(449, 0, 449, 480); char runTime[] = "游戏倒计时 : ", receiveBallNum[] = "接到的球的数量:", copyRight[] = "版权所有:圣石", finishWorkDate[] = "完成日期:2012年12月1日", introductiona[] = "按方向键控制盒子移动接住", introductionb[] = "小球,倒计时为0时游戏结束"; settextcolor(GREEN); outtextxy(450, 10, introductiona); outtextxy(450, 30, introductionb); outtextxy(450, 110, runTime); outtextxy(450, 210, receiveBallNum); outtextxy(450, 310, copyRight); outtextxy(450, 410, finishWorkDate); } // 产生随机球 void ballRandom(Ball ball[], int i) { ball[i].x = 16 + 45 * i; ball[i].y = 8 + rand() % 32; ball[i].v = 1 + rand() % 5; } // 画球,并计算得分 void calculateScore(Ball ball[], int &score) { for(int i = 0; i < NUM; i++) { fillcircle(ball[i].x, ball[i].y, 8); if(ball[i].y >= 472) { ballRandom(ball, i); continue; } if(box_x + 8 <= ball[i].x && ball[i].x <= box_x + 72 && ball[i].y >= 412) { score++; ballRandom(ball, i); } } } // 主函数 int main() { // 初始化 initgraph(640, 480); srand(time(NULL)); BeginBatchDraw(); setlinecolor(GREEN); setfillcolor(WHITE); menu(); Ball ball[NUM]; int dx, i, c, score = 0; bool flag = true; for(i=0; i<NUM; i++) { ballRandom(ball, i); } int t = GetTickCount(); char strScore[10], str[] = "your score:"; // 游戏主循环 while(flag) { dx = 0; // 显示得分 char strScore[10]; itoa(score, strScore, 10); outtextxy(570, 210, strScore); // 画球,并计算得分 calculateScore(ball, score); // 画盒子 fillrectangle(box_x, box_y, box_x+80, box_y+60); FlushBatchDraw(); // 获取用户控制命令 c = GetCommand(); if (c & CMD_LEFT) dx = -10; if (c & CMD_RIGHT) dx = 10; if (c & CMD_QUIT) flag = false; if (!Time(t)) flag = false; // 延时 Sleep(25); // 擦除游戏区 clearrectangle(0, 0, 448, 480); // 计算球的新坐标 for(i = 0; i < NUM; i++) { ball[i].y += ball[i].v; } // 移动盒子 box_x += dx; if(box_x < 0) box_x = 0; if(box_x > 368) box_x = 368; } // 清空键盘缓冲区 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); // 输出游戏结果 itoa(score, strScore, 10); outtextxy(222, 240, strcat(str, strScore)); outtextxy(220, 300, "按任意键退出"); EndBatchDraw(); // 按任意键退出 getch(); closegraph(); return 0; } 作者:圣石邮箱:2464847121@qq.com

游戏:AyaCrossX(十字消除游戏)

十字消除是一款经典消除类小游戏。玩法如下: 点击空白处,所在横纵十字线上同色方块会被消除。 消除方块会累加得分,并恢复一定量的时间。 方块数量少于某数值会出现新方块并回复时间。 时间耗尽时则游戏结束。 游戏运行截图如下: 游戏的源码编译环境:Visual C++ 6.0 / 2008 / 2010 / 2012,EasyX 2013霜降版 游戏的源代码如下: ///////////////////////////////////////////////////////// // 程序名称:AyaCrossX(十字消除游戏) // 编译环境:Visual C++ 6.0 / 2012,EasyX 2013霜降版 // 作 者:ls9512 <http://www.baidu.com/p/ls9512> // 最后修改:2013-11-2 // //系统函数库 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <math.h> #include <time.h> //EasyX图形库 #include <graphics.h> //////////////////////////////以下是 宏定义参数 ////////////////////////////// #define WIN_WIDTH 600 //屏幕宽度 #define WIN_HEIGHT 430 //屏幕高度 #define WIN_BLANKTOP 45 //屏幕顶部空边 #define WIN_BLANK 25 //屏幕边缘留空 #define G_BN 20 //方块横向数量 #define G_BM 12 //方块纵向数量 #define G_BW 20 //方块宽度 #define G_BS 8 //方块间隔宽度 #define G_BSELECT 3 //方块选中大小 #define G_FLOATW 4 //选中浮动大小 #define G_BDWO 1 //消失初始大小 #define G_BDW 6 //消失大小 #define G_CN 10 //颜色数量 #define G_BUL 25 //方块增量程度 #define C_BLOCKPANEL RGB(255, 255, 221) //底板颜色 #define C_HPBAR RGB(255, 170, 255) //HP条颜色 //////////////////////////////以下是数据结构定义////////////////////////////// //方块结构 struct Block{ COLORREF color; //颜色 float FLOAT; //浮动大小 float DIS; //消除延迟 bool isDIS; //是否消失中 bool isClick; //是否被点击 }; //点结构 struct Point{ int x; int y; }; //矩形结构 struct Rect{ int x; int y; int w; int h; }; //////////////////////////////以下是 全局变量 ////////////////////////////// int GamePhase = 0; //游戏阶段 0 准备 1 进行 2 结束 3 帮助界面 int isShowFPS = 0; //是否显示帧数 int mouseX; //鼠标位置坐标X int mouseY; //鼠标位置坐标Y int time_max; //总游戏时间 int time_now; //当前剩余时间 int level; //等级 int score; //分数 bool isMouseDown; //鼠标按下 Block block[G_BM][G_BN]; //方块数组 COLORREF Defcolor[G_CN]; //候选颜色数组 //////////////////////////////以下是 函数声明 ////////////////////////////// float GetFPS(); //获取帧数 void HpSleep(DWORD ms); //绝对延时 Point GetMouseLocal(int x, int y); //获取鼠标所在坐标 void AddBlock(int n); //添加指定个数的未选中方块 void Init(); //初始化 void DisCheck(int x, int y); //检测指定位置的消除 int CountBlock(); //统计方块个数 void Manager(); //逻辑处理 void Draw(); //绘图处理 void StartDraw(); //游戏开始绘图 void GamingDraw(); //游戏进行中绘图 void EndDraw(); //游戏结束绘图 void HelpDraw(); //游戏帮助绘图 void EndFrame(); //帧结束处理 bool IsInRect(int x, int y, Rect r); //是否在矩形内 //////////////////////////////以下是辅助功能函数////////////////////////////// //计算画面FPS(每秒帧数) float GetFPS() { #define FPS_COUNT 8 static int i = 0; static DWORD oldTime = GetTickCount(); static float fps; if (i > FPS_COUNT) { i = 0; int newTime = GetTickCount(); int elapsedTime = newTime - oldTime; fps = FPS_COUNT / (elapsedTime / 1000.0f); oldTime = newTime; } i++; return fps; } //绝对延时 void HpSleep(DWORD ms) { static clock_t oldclock = clock(); // 静态变量,记录上一次 tick oldclock += ms * CLOCKS_PER_SEC / 1000; // 更新 tick if (clock() > oldclock) // 如果已经超时,无需延时 oldclock = clock(); else while(clock() < oldclock) // 延时 Sleep(1); // 释放 CPU 控制权,降低 CPU 占用率 } //获取鼠标选中点 Point GetMouseLocal(int x, int y) { Point p; x = (x - WIN_BLANK) / (G_BW + G_BS); y = (y - WIN_BLANK - WIN_BLANKTOP) / (G_BW + G_BS); if (x < 0 || x >= G_BN) x = -1; if (y < 0 || y >= G_BM) y = -1; p.x = x; p.y = y; return p; } //是否在矩形内 bool IsInRect(int x, int y, Rect r) { return ((x >= r.x && x <= r.w) && (y >= r.y && y <= r.h)); } //添加制定个数的未选中方块 void AddBlock(int n) { //随机生成方块 int num = 0, x1, y1, x2, y2; int num_max = n; while(num < num_max) { x1 = rand() % G_BN; y1 = rand() % G_BM; x2 = rand() % G_BN; y2 = rand() % G_BM; if(block[y1][x1].isClick && block[y2][x2].isClick) { COLORREF color = Defcolor[rand() % G_CN]; block[y1][x1].color = color; block[y1][x1].isClick = false; block[y1][x1].FLOAT = 0; block[y1][x1].DIS = 0; block[y1][x1].isDIS = false; block[y2][x2].color = color; block[y2][x2].isClick = false; block[y2][x2].FLOAT = 0; block[y2][x2].DIS = 0; block[y2][x2].isDIS = false; num += 2; } } } //初始化 void Init() { //预置颜色 Defcolor[0] = RGB(255, 153, 0); Defcolor[1] = RGB(204, 102, 0); Defcolor[2] = RGB(27, 118, 255); Defcolor[3] = RGB(255, 136, 255); Defcolor[4] = RGB(204, 204, 102); Defcolor[5] = RGB(104, 204, 204); Defcolor[6] = RGB(255, 125, 125); Defcolor[7] = RGB(204, 104, 204); Defcolor[8] = RGB(190, 190, 190); Defcolor[9] = RGB(0, 204, 0); //初始化时间 time_max = 10000; time_now = 10000; //初始化分数 score = 0; //置全选中 for(int i = 0; i < G_BM; i++) { for(int j = 0; j < G_BN; j++) { block[i][j].isClick = true; block[i][j].FLOAT = 0; block[i][j].DIS = 0; } } //添加方块 AddBlock(G_BN * G_BM * 2 / 3); //清除鼠标消息队列 FlushMouseMsgBuffer(); } //统计方块个数 int CountBlock() { int n = 0; for(int i = 0; i < G_BN; i++) { for(int j = 0; j < G_BM; j++) { if(!block[j][i].isClick) n++; } } return n; } //检测指定位置消除 void DisCheck(int x, int y) { //记录待消除的方块 Block* b[4]; int i, j, n = 0; //向左 for(i = x; i >= 0; i--) { if(!block[y][i].isClick) { b[n] = &block[y][i]; n++; break; } } //向右 for(i = x; i < G_BN; i++) { if(!block[y][i].isClick) { b[n] = &block[y][i]; n++; break; } } //向上 for(j = y; j >= 0; j--) { if(!block[j][x].isClick) { b[n] = &block[j][x]; n++; break; } } //向下 for(j = y; j < G_BM; j++) { if(!block[j][x].isClick) { b[n] = &block[j][x]; n++; break; } } //消除 for(i = 0; i < n; i++) { for(j = i + 1; j < n; j++) { if(b[i]->color == b[j]->color) { if(!b[i]->isDIS){ b[i]->DIS = G_BDWO; b[i]->isDIS = true; } if(!b[j]->isDIS){ b[j]->DIS = G_BDWO; b[j]->isDIS = true; } } } } isMouseDown = false; } //逻辑处理 void Manager() { //如果在游戏中 if(GamePhase == 1) { Point p = GetMouseLocal(mouseX, mouseY); int x = p.x, y = p.y; //如果选中 if(p.x != -1 && p.y != -1) { //如果单击 if(isMouseDown && block[y][x].isClick) { //触发消除检测 DisCheck(x, y); } } //添加新方块添加随机个数新方块 if(CountBlock() < G_BN * G_BM / 3) { AddBlock((rand() % 15 + 15) * 2); //时间恢复 time_now += 500; if(time_now > time_max) time_now = time_max; } } } //开始绘图 void StartDraw() { settextstyle(52, 30, _T("Impact")); //标题 settextcolor(RGB(255, 17, 102)); outtextxy(143, 93, _T("AyaCrossX")); settextcolor(RGB(255, 153, 238)); outtextxy(140, 90, _T("AyaCrossX")); //版本 settextstyle(22, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(340, 153, _T("v0.91 By:ls9512")); //开始游戏按钮 Rect r; r.x = 240; r.y = 220; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //开始游戏按键响应 if(isMouseDown) { Init(); GamePhase = 1; isMouseDown = false; } } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T("PLAY GAME")); //帮助游戏按钮 r.x = 240; r.y = 270; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //帮助按键响应 if(isMouseDown) GamePhase = 3; } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T("HELP INFO")); //退出游戏按钮 r.x = 240; r.y = 320; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //退出按键响应 if(isMouseDown) exit(0); } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T("EXIT GAME")); //说明 settextstyle(16, 5, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(175, 400, _T("Programing By VC++ & EasyX Date:2013.11.01")); } //游戏中绘图 void GameingDraw() { int x, y; COLORREF c, c2; //时间条 x = WIN_BLANK; y = WIN_BLANK; int HPBARW = (G_BW + G_BS) * G_BN - 200; setlinecolor(RGB(255, 17, 255)); setfillcolor(WHITE); fillrectangle(x, y, x + HPBARW, y + 10); setfillcolor(C_HPBAR); fillrectangle(x, y, x + (int)(HPBARW * (1.0 * time_now / time_max)), y + 10); //底板 setlinecolor(RGB(255, 25, 22)); setfillcolor(C_BLOCKPANEL); x = WIN_BLANK - G_BS; y = WIN_BLANK + WIN_BLANKTOP - G_BS; fillrectangle(x, y, x + (G_BW + G_BS) * G_BN + G_BS, y + (G_BW + G_BS) * G_BM + G_BS); //画方块 for(int i = 0; i < G_BM; i++) { for(int j = 0; j < G_BN; j++) { if(!block[i][j].isClick) { c = block[i][j].color; c = RGB(GetRValue(c) - (BYTE)G_BUL, GetGValue(c) - (BYTE)G_BUL, GetBValue(c) - (BYTE)G_BUL); int fw = (int)block[i][j].FLOAT; int fd = (int)block[i][j].DIS; setlinecolor(c); setfillcolor(block[i][j].color); x = j * (G_BW + G_BS) + WIN_BLANK - fw - fd; y = i * (G_BW + G_BS) + WIN_BLANK + WIN_BLANKTOP - fw - fd; fillrectangle(x, y, x + G_BW + 2 * (fw + fd), y + G_BW + 2 * (fw + fd)); //浮动缩减 if(block[i][j].FLOAT > 0) block[i][j].FLOAT -= 0.4f; //消失延迟 if(block[i][j].isDIS) { if(block[i][j].DIS < G_BDW) block[i][j].DIS += 0.4f; else { //消除 block[i][j].isClick = true; //加分 score += 100; time_now += 25; if (time_now > time_max) time_now = time_max; } } } } } //获取鼠标位置 Point p = GetMouseLocal(mouseX, mouseY); //画出鼠标光标 if(p.x != -1 && p.y != -1) { c = RED; x = p.x, y = p.y; int fw; if(block[y][x].isClick) fw = 0; else fw = (int)block[y][x].FLOAT; x = x * (G_BW + G_BS) + WIN_BLANK - G_BSELECT - fw; y = y * (G_BW + G_BS) + WIN_BLANK + WIN_BLANKTOP - G_BSELECT -fw; //选中方块加亮 if(!block[p.y][p.x].isClick) { //置浮动大小 block[p.y][p.x].FLOAT = G_FLOATW; c2 = block[p.y][p.x].color; } else { c2 = C_BLOCKPANEL; } setlinecolor(c); setfillcolor(c2); fillrectangle(x, y, x + G_BW + 2 * (G_BSELECT + fw), y + G_BW + 2 * (G_BSELECT + fw)); } //画出分数 settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(155, 51, 68)); TCHAR b[10]; #if _MSC_VER > 1200 _stprintf_s(b, _T("%d"), score); #else _stprintf(b, _T("%d"), score); #endif outtextxy(390, 15, _T("分数:")); settextcolor(RGB(255, 51, 68)); outtextxy(440, 16, b); } //游戏结束绘图 void EndDraw() { //标题 settextstyle(52, 30, _T("Impact")); settextcolor(RGB(255, 17, 102)); outtextxy(143, 103, _T("GAME OVER")); settextcolor(RGB(215, 193, 238)); outtextxy(140, 100, _T("GAME OVER")); //版本 settextstyle(34, 12, _T("Verdana")); settextcolor(RGB(255, 51, 68)); TCHAR b[10]; #if _MSC_VER > 1200 _stprintf_s(b, _T("%d"), score); #else _stprintf(b, _T("%d"), score); #endif outtextxy(232, 173, _T("分数:")); outtextxy(290, 173, b); //重新开始游戏按钮 Rect r; r.x = 240; r.y = 240; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //开始游戏按键响应 if(isMouseDown) { Init(); GamePhase = 1; } } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T(" REPLAY")); //退出 r.x = 240; r.y = 290; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //退出按键响应 if(isMouseDown) exit(0); } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 10, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T("EXIT GAME")); } //游戏帮助绘图 void HelpDraw() { //标题 settextstyle(52, 30, _T("Impact")); settextcolor(RGB(255, 17, 152)); outtextxy(233, 33, _T("HELP")); settextcolor(RGB(215, 193, 238)); outtextxy(230, 30, _T("HELP")); //底板 setlinecolor(RGB(255, 17, 204)); setfillcolor(RGB(255, 221, 255)); fillrectangle(60, 100, 550, 280); //版本 settextstyle(18, 10, _T("黑体")); settextcolor(RGB(245, 126, 92)); outtextxy(70, 110, _T("十字消除是一款经典消除类小游戏。")); outtextxy(70, 145, _T("【玩法】")); outtextxy(80, 170, _T("1.点击空白处,所在横纵十字线上同色方块会被消除。")); outtextxy(80, 195, _T("2.消除方块会累加得分,并恢复一定量的时间.")); outtextxy(80, 220, _T("3.方块数量少于某数值会出现新方块并回复时间.")); outtextxy(80, 245, _T("4.时间耗尽时则游戏结束.")); //返回 Rect r; r.x = 240; r.y = 360; r.w = r.x + 125; r.h = r.y + 35; setlinecolor(RGB(255, 17, 102)); if(IsInRect(mouseX, mouseY, r)) { setfillcolor(RGB(255, 187, 119)); //返回按键响应 if(isMouseDown) GamePhase = 0; } else setfillcolor(RGB(255, 255, 204)); fillrectangle(r.x, r.y, r.w, r.h); settextstyle(25, 9, _T("Verdana")); settextcolor(RGB(255, 51, 68)); outtextxy(r.x + 5, r.y + 5, _T("BACK MENU")); } //输出帧数 void DrawFPS() { //输出帧数 if(isShowFPS) { settextcolor(RED); settextstyle(14, 0, _T("宋体")); TCHAR s[5]; #if _MSC_VER > 1200 _stprintf_s(s, _T("%.1f"), GetFPS()); #else _stprintf(s, _T("%.1f"), GetFPS()); #endif outtextxy(0, 0, s); } } //绘图 void Draw() { //清屏 setlinecolor(WHITE); setfillcolor(WHITE); fillrectangle(0, 0, WIN_WIDTH, WIN_HEIGHT); switch(GamePhase) { case 0: StartDraw(); break; case 1: GameingDraw(); break; case 2: EndDraw(); break; case 3: HelpDraw(); break; } DrawFPS(); } //帧结束处理 void EndFrame() { time_now -= 2; //游戏结束 if(time_now <= 0 && GamePhase == 1) { GamePhase = 2; } } //主入口函数 int main() { //置随机数种子 srand((unsigned)time(NULL)); //初始化设备,加载图片 initgraph(WIN_WIDTH, WIN_HEIGHT); //设置窗口标题 SetWindowText(GetHWnd(), _T("AyaCrossX v0.91 By:ls9512")); cleardevice(); //设置黑色背景 setbkmode(TRANSPARENT); settextcolor(BLACK); //开启双缓冲,防止闪屏 BeginBatchDraw(); // 鼠标消息变量 MOUSEMSG mmsg; //初始化 Init(); while(true) { //处理鼠标消息 while(MouseHit()) { mmsg = GetMouseMsg(); switch(mmsg.uMsg) { case WM_MOUSEMOVE: mouseX = mmsg.x; mouseY = mmsg.y; break; case WM_LBUTTONDOWN: isMouseDown = true; break; case WM_LBUTTONUP: isMouseDown = false; break; } } //逻辑处理 Manager(); //绘图处理 Draw(); //显示缓存的绘制内容 FlushBatchDraw(); //帧结束处理 EndFrame(); //延迟,帧数控制 HpSleep(18); } // 关闭 EndBatchDraw(); closegraph(); return 0; } 作者:ls9512博客:http://www.baidu.com/p/ls9512

游戏:奔跑的火柴人

这是一款以火柴人为人物的小游戏,人物通过操作躲过各种障碍物,当人物撞到障碍物则游戏结束。 操作说明:W—跳跃,S—滚动 游戏执行效果: 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:星QQ:453496034邮箱:liluxing1993@qq.com

游戏:种地要浇水(创意源自《金庸无双》)

游戏规则 填补水渠使每块田地都被灌溉。方向键选择,空格确定。 特技(耗金币): 重置:R 键 顺时针旋转:S 键 逆时针旋转:N 键 跳过一个:T 键 (具体金币盈亏细则,可以在游戏中按 H 键查看)。 注:游戏创意源自《金庸无双》。 游戏运行截图 源代码下载 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:i92076https://www.baidu.com/p/i92076

游戏:大丰收(含有 VC6 游戏源码 和 完整论文)

喜庆丰收,这是一款锻炼玩家反应能力的游戏,游戏中玩家通过控制上和左右键控制可爱的小猴子在地面上跳跃或者是平行移动,来接取天空中飘落的水果。接到不同的水果会得到不同的分数,桃子 10 分,西瓜 20 分,菠萝 30 分,接到炸弹扣 40 分,接不到水果也会扣 10 分,当扣分达到 500 游戏结束(扣分只计算没接到水果),当得分到达 500 会进入下一关,右侧会显示最高得分玩家的用户名和分数,游戏中可以点击暂停键,暂停,再次点击游戏开始,按空格键也可以暂停游戏,在按任意键开始,点击结束会关闭游戏,不保存游戏信息,正常游戏结束,会将游戏信息保存。 游戏运行截图如下: 游戏附带有完整的 VC6 源代码,以及完整的游戏资源(图片和音效),并附有原作者写的论文。 全部文档请【点击这里下载】。 作者:杨盼QQ:745509409指导教师:蔡越江