Loading...     这两天刚考完试,有两天的休息时间。本打算出去逛逛,可是又不知道去哪好......所以就待在学校写代码吧!:laughing:(~~其实是因为没有女票qwq~~)     贪吃蛇大家都玩过吧,实现起来也并不难,主要思路就是用数组来模拟画布(即蛇活动的那个地方)。关于蛇的移动与吃食物后变长,用的是移动前后数组中各个元素间的关系的方法。详见代码。     另外,为了熟悉C++中类的使用,这次用的是OOP的思想(而不再是“用C++的语法写C”),写了两个类,即Snake类和Canvas类,分别表示蛇和画布。 代码如下 #include <windows.h> #include <conio.h> #include <cstdlib> #include <cstdio> #include <ctime> #include <iostream> #include <cstdlib> int new_tail_i,new_tail_j; void gotoxy(int x,int y) //将光标的坐标设为(x,y) { HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE); //取得一个句柄 COORD pos; pos.X=x; pos.Y=y; SetConsoleCursorPosition(handle,pos); //设置光标的坐标 } class Canvas{ //定义一个Canvas类来表示画布 public: Canvas(); //构造函数 void show(); //显示画布 void generate_food(); //生成画布上的食物 int get_hei(); //得到画布高度 int get_wid(); //得到画布宽度 void change_canvas(int i,int j,int value_to_write); //改变画布(即修改私有成员canvas数组中的某个元素值) int show_ele(int i,int j); //得到画布上某个位置的状态(即canvas中某个元素的元素值) private: int canvas[100][100]; //用一个数组来表示画布各处的状态 int hei; //画布高度 int wid; //画布宽度 }; void Canvas::generate_food() { int success=1; int flag=1; for(int i=1;i<hei-1;i++) { for(int j=1;j<wid-1;j++) { if(canvas[i][j]==-2) { flag=0; goto out_loop; } } } //上面一段代码用于判断画布中是否有食物。若有,则不需要生成新食物;否则生成新食物 out_loop:; if(flag) { while(success) //加个while循环是为了在生成错误(指食物生成到了蛇的身上或墙壁上)的情况下重新再生成 { int x=rand()%(hei-2)+1; int y=rand()%(wid-2)+1; if(canvas[x][y]==0) { canvas[x][y]=-2; success=0; } } return ; } else return ; } Canvas::Canvas() { hei=20;wid=40; system("cls"); //清屏 memset(canvas,0,sizeof(canvas)); for(int i=0;i<hei;i++) { canvas[i][0]=-1; canvas[i][wid-1]=-1; } for(int j=1;j<wid-1;j++) { canvas[0][j]=-1; canvas[hei-1][j]=-1; } } void Canvas::show() { // system("cls"); gotoxy(0,0); for(int i=0;i<hei;i++) { for(int j=0;j<wid;j++) { if(canvas[i][j]==-1) printf("#"); if(canvas[i][j]==0) printf(" "); if(canvas[i][j]==1) printf("@"); if(canvas[i][j]>1) printf("*"); if(canvas[i][j]==-2) printf("F"); } printf("\n"); } } int Canvas::show_ele(int i,int j) { return canvas[i][j]; } void Canvas::change_canvas(int i,int j,int value_to_write) { canvas[i][j]=value_to_write; } int Canvas::get_hei() { return hei; } int Canvas::get_wid() { return wid; } class Snake{ public: void move(int dir,Canvas& can); void grow(int x,int y,Canvas& can); void put_snake(Canvas& sele_can,int x,int y,int len); bool check(Canvas& can,int x,int y); int get_score(); int get_head_i(); int get_head_j(); void quit(); Snake(); private: int head_i,head_j; int old_tail_i,old_tail_j; int score; int live; }; Snake::Snake() { live=3; score=0; } int Snake::get_score() { return score; } int Snake::get_head_i() { return head_i; } int Snake::get_head_j() { return head_j; } bool Snake::check(Canvas& can,int x,int y) //用于判断蛇是否撞墙或咬到自己 { if(can.show_ele(x,y)>0||can.show_ele(x,y)==-1) return false; return true; } void Snake::put_snake(Canvas& sele_can,int x,int y,int len) //把蛇放到一个画布上。这样做的目的是为了蛇和画布能更彻底地分离 { int hei=sele_can.get_hei(); int wid=sele_can.get_wid(); int body=1; for(int j=y;j>=y-len;j--,body++) sele_can.change_canvas(x,j,body); } void Snake::move(int dir,Canvas& can) //蛇的移动 { int hei=can.get_hei(); int wid=can.get_wid(); for(int i=1;i<hei-1;i++) { for(int j=1;j<wid-1;j++) { if(can.show_ele(i,j)>=1) { int tmp=can.show_ele(i,j); can.change_canvas(i,j,tmp+1); } } } //将蛇的身体"+1" int maxi=-10; for(int i=1;i<hei-1;i++) { for(int j=1;j<wid-1;j++) { if(can.show_ele(i,j)==2) { head_i=i; head_j=j; } if(can.show_ele(i,j)>maxi) { maxi=can.show_ele(i,j); old_tail_i=i; old_tail_j=j; } } } //找到头部坐标 //下面则是根据移动方向放置蛇头 if(dir==1) //左移 { if(can.show_ele(head_i,head_j-1)==-2) grow(head_i,head_j-1,can); else { if(check(can,head_i,head_j-1)) { can.change_canvas(head_i,head_j-1,1); can.change_canvas(old_tail_i,old_tail_j,0); can.show(); } else { quit(); //这个还没写 return; } } } else if(dir==2) //上移 { if(can.show_ele(head_i-1,head_j)==-2) grow(head_i-1,head_j,can); else { if(check(can,head_i-1,head_j)) { can.change_canvas(head_i-1,head_j,1); can.change_canvas(old_tail_i,old_tail_j,0); can.show(); } else { quit(); return ; } } } else if(dir==3) //右移 { if(can.show_ele(head_i,head_j+1)==-2) grow(head_i,head_j+1,can); else { if(check(can,head_i,head_j+1)) { can.change_canvas(head_i,head_j+1,1); can.change_canvas(old_tail_i,old_tail_j,0); can.show(); } else { quit(); return ; } } } else if(dir==4) //下移 { if(can.show_ele(head_i+1,head_j)==-2) grow(head_i+1,head_j,can); else { if(check(can,head_i+1,head_j)) { can.change_canvas(head_i+1,head_j,1); can.change_canvas(old_tail_i,old_tail_j,0); can.show(); } else { quit(); return ; } } } } //蛇的变长函数,其原理与蛇的移动函数相似,只是不需要擦除蛇尾 void Snake::grow(int x,int y,Canvas& can) { for(int i=1;i<can.get_hei()-1;i++) { for(int j=1;j<can.get_wid()-1;j++) { if(can.show_ele(i,j)>=1) { int tmp=can.show_ele(i,j); can.change_canvas(i,j,tmp+1); } } } can.change_canvas(x,y,1); score++; can.generate_food(); can.show(); printf("\t Your score is %d.\n",score); } void Snake::quit() { printf("\nI(the snake) lose!\n"); printf("Press any key to quit.\n"); getchar(); exit(0); } //应实现,同一条蛇可以在两个或多个不同的画布上移动、吃食物 //主体应该是蛇本身,而非画布 int main() { srand(time(NULL)); //用时间作为随机数种子,这样每一局的食物分布都会与上一局不同 Snake sna; Canvas canv; sna.put_snake(canv,canv.get_hei()-3,(canv.get_wid())/2+2,0); canv.generate_food(); canv.show(); printf("\t Your score is %d.\n",sna.get_score()); while(1) { char op; op=getch(); switch(op) { case 'a':sna.move(1,canv);break; case 'w':sna.move(2,canv);break; case 'd':sna.move(3,canv);break; case 's':sna.move(4,canv);break; } } return 0; } 简单说一下蛇移动的思路:     首先,蛇的表示方法是这样的:若数组中某个元素为1,则它表示蛇头所在处;若数组中某个元素大于1,则它表示蛇身。从蛇头到蛇尾,是一个从1开始的连续自然数序列(即1,2,3,4,5,···)     通过观察下面的图片,我们可以得出这样的方法:若要移动蛇,只需要先将蛇头到蛇身的每一个数都++,然后将移动方向所对应的元素的值改为1,并将移动前的蛇尾的元素值改为0(0表示空白处,即蛇可以到达的地方)。 ![微信截图_20190113215711.png](https://blog.domineto.top/usr/uploads/2019/01/3380500415.png)                         移动前 ![微信截图_20190113215745.png](https://blog.domineto.top/usr/uploads/2019/01/777375332.png)                     将蛇头和蛇身++ ![微信截图_20190113215800.png](https://blog.domineto.top/usr/uploads/2019/01/1675874567.png)                        完成移动 大致就是如此,接下来应该还会有所补充,~~现在就先这样了吧~~~~(其实是懒)~~ 最后修改:2019 年 01 月 13 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏