贪吃蛇

先来了解一些简单的基础知识

下面是一个20 x 20的矩阵 用来表示贪吃蛇的地图

坐标原点为左下角

我们需要有一个数组来保存当前蛇的蛇身体

snake数组是存在顺序的,数组的第一个元素是蛇头的位置,数组的最后一位就是蛇的尾巴

 

接下来是蛇的移动,也就是数组数据的移动

  • 上边移动 蛇头数据+20
  • 下边移动 蛇头数据-20
  • 左边移动 蛇头数据-1
  • 右边移动 蛇头数据+1

上边只说到蛇头数据,因为我们只需要修改一个蛇头的数据,不用修改整条蛇的数据

蛇的数据

 

当前蛇的方向是右边,也就是数据+1,加入一个新的蛇头

 

当前蛇的长度变成了3,可是我们的蛇应该只有2的长度,还需要把蛇的尾巴去掉一个

 

这样蛇就完成了向右一格的移动 上下左移动都是同理,这里就不赘述了

下面进入正题了

10分钟编写一个贪吃蛇,先确定下规则

  • 贪吃蛇由上下左右键位控制
  • 蛇头能穿越墙壁从另一面出来
  • 吃到食物增加一个长度
  • 撞到自己的身体即为失败

新建一个空的项目

加入一个空节点,用来承载地图,命名为map

  • map需要挂载一个画图的组件

接下来是编写脚本Map.ts

初始化一些变量

 

先加入控制的方法

 

简单分析这段代码:

 
  • this.moveOffset 是蛇头的移动变量 也就是到下一格变化量
  • this.snake[1] - this.snake[0] 获得当前蛇头不能变化的方法
  • this.nextIndex 在这里做了下临时变量,记录操作值
  • 左上右下的keyCode 分别为37 38 39 40 如果按其他按键就使用原来的移动变量

如果还不理解可以看下运算符的执行顺序

主要的移动和碰撞判断代码,有几个点需要简单分析下

  • [].unshift 从头部加入数组
  • [].indexOf 获得元素在数组中的位置(这里用来判断是否在数组中)
  • 循环遍历食物不存在与当前的蛇体内 不会无限循环 因为覆盖会在上面的函数中跳出
  • 尾部去除的格子用背景色覆盖
 

最简单的Draw方法

  • 画出当前方块的实体
 

ps 可以扩展的部分

  • 以上就是主要代码的部分,下面是一些扩展和方向,就不属于10分钟内的了
  • 设置蛇头颜色,清理尾部格子的时候顺便清理snake[1]为蛇身颜色即可
  • 多个食物,设置food为数组,判断数组内是否是蛇头就好了
  • 关卡加速,控制帧率越来越高即可 ps: 30差不多就难以操作了

源码地址: https://gitee.com/limo/snake

#define N 200<br>#include <graphics.h><br>#include <stdlib.h><br>#include <dos.h><br>#define LEFT 0x4b00<br>#define RIGHT 0x4d00<br>#define DOWN 0x5000<br>#define UP 0x4800<br>#define ESC 0x011b<br>int i,key;<br>int score=0;/*得分*/<br>int gamespeed=50000;/*游戏速度自己调整*/<br>struct Food<br>{<br> int x;/*食物的横坐标*/<br> int y;/*食物的纵坐标*/<br> int yes;/*判断是否要出现食物的变量*/<br>}food;/*食物的结构体*/<br>struct Snake<br>{<br> int x[N];<br> int y[N];<br> int node;/*的节数*/<br> int direction;/*移动方向*/<br> int life;/* 的生命,0活着,1死亡*/<br>}snake;<br>void Init(void);/*图形驱动*/<br>void Close(void);/*图形结束*/<br>void DrawK(void);/*开始画面*/<br>void GameOver(void);/*结束游戏*/<br>void GamePlay(void);/*玩游戏具体过程*/<br>void PrScore(void);/*输出成绩*/<br>/*主函数*/<br>void main(void)<br>{<br> Init();/*图形驱动*/<br> DrawK();/*开始画面*/<br> GamePlay();/*玩游戏具体过程*/<br> Close();/*图形结束*/<br>}<br>/*图形驱动*/<br>void Init(void)<br>{<br> int gd=DETECT,gm;<br> initgraph(&gd,&gm,"c:\\tc");<br> cleardevice();<br>}<br>/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/<br>void DrawK(void)<br>{<br>/*setbkcolor(LIGHTGREEN);*/<br> setcolor(11);<br> setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型*/<br> for(i=50;i<=600;i+=10)/*画围墙*/<br> {<br> rectangle(i,40,i+10,49); /*上边*/<br> rectangle(i,451,i+10,460);/*下边*/<br> }<br> for(i=40;i<=450;i+=10)<br> {<br> rectangle(50,i,59,i+10); /*左边*/<br> rectangle(601,i,610,i+10);/*右边*/<br> }<br>}<br>/*玩游戏具体过程*/<br>void GamePlay(void)<br>{<br> randomize();/*随机数发生器*/<br> food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/<br> snake.life=0;/*活着*/<br> snake.direction=1;/*方向往右*/<br> snake.x[0]=100;snake.y[0]=100;/*头*/<br> snake.x[1]=110;snake.y[1]=100;<br> snake.node=2;/*节数*/<br> PrScore();/*输出得分*/<br> while(1)/*可以重复玩游戏,压ESC键结束*/<br> {<br> while(!kbhit())/*在没有按键的情况下,自己移动身体*/<br> {<br> if(food.yes==1)/*需要出现新食物*/<br> {<br> food.x=rand()%400+60;<br> food.y=rand()%350+60;<br> while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让吃到*/<br> food.x++;<br> while(food.y%10!=0)<br> food.y++;<br> food.yes=0;/*画面上有食物了*/<br> }<br> if(food.yes==0)/*画面上有食物了就要显示*/<br> {<br> setcolor(GREEN);<br> rectangle(food.x,food.y,food.x+10,food.y-10);<br> }<br> for(i=snake.node-1;i>0;i--)/*的每个环节往前移动,也就是贪吃蛇的关键算法*/<br> {<br> snake.x[i]=snake.x[i-1];<br> snake.y[i]=snake.y[i-1];<br> }<br> /*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动头*/<br> switch(snake.direction)<br> {<br> case 1:snake.x[0]+=10;break;<br> case 2: snake.x[0]-=10;break;<br> case 3: snake.y[0]-=10;break;<br> case 4: snake.y[0]+=10;break;<br> }<br> for(i=3;i<snake.node;i++)/*从的第四节开始判断是否撞到自己了,因为头为两节,第三节不可能拐过来*/<br> {<br> if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])<br> {<br> GameOver();/*显示失败*/<br> snake.life=1;<br> break;<br> }<br> }<br> if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||<br> snake.y[0]>455)/*是否撞到墙壁*/<br> {<br> GameOver();/*本次游戏结束*/<br> snake.life=1; /*死*/<br> }<br> if(snake.life==1)/*以上两种判断以后,如果死就跳出内循环,重新开始*/<br> break;<br> if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/<br> {<br> setcolor(0);/*把画面上的食物东西去掉*/<br> rectangle(food.x,food.y,food.x+10,food.y-10);<br> snake.x[snake.node]=-20;snake.y[snake.node]=-20;<br> /*新的一节先放在看不见的位置,下次循环就取前一节的位置*/<br> snake.node++;/*的身体长一节*/<br> food.yes=1;/*画面上需要出现新的食物*/<br> score+=10;<br> PrScore();/*输出新得分*/<br> }<br> setcolor(4);/*画出*/<br> for(i=0;i<snake.node;i++)<br> rectangle(snake.x[i],snake.y[i],snake.x[i]+10,<br> snake.y[i]-10);<br> delay(gamespeed);<br> setcolor(0);/*用黑色去除的的最后一节*/<br> rectangle(snake.x[snake.node-1],snake.y[snake.node-1],<br> snake.x[snake.node-1]+10,snake.y[snake.node-1]-10);<br> } /*endwhile(!kbhit)*/<br> if(snake.life==1)/*如果死就跳出循环*/<br> break;<br> key=bioskey(0);/*接收按键*/<br> if(key==ESC)/*按ESC键退出*/<br> break;<br> else<br> if(key==UP&&snake.direction!=4)<br>/*判断是否往相反的方向移动*/<br> snake.direction=3;<br> else<br> if(key==RIGHT&&snake.direction!=2)<br> snake.direction=1;<br> else<br> if(key==LEFT&&snake.direction!=1)<br> snake.direction=2;<br> else<br> if(key==DOWN&&snake.direction!=3)<br> snake.direction=4;<br> }/*endwhile(1)*/<br>}<br>/*游戏结束*/<br>void GameOver(void)<br>{<br> cleardevice(); <br> PrScore();<br> setcolor(RED);<br> settextstyle(0,0,4);<br> outtextxy(200,200,"GAME OVER");<br> getch();<br>}<br>/*输出成绩*/<br>void PrScore(void)<br>{ <br> char str[10];<br> setfillstyle(SOLID_FILL,YELLOW);<br> bar(50,15,220,35);<br> setcolor(6);<br> settextstyle(0,0,2);<br> sprintf(str,"score:%d",score);<br> outtextxy(55,20,str);<br>}<br>/*图形结束*/<br>void Close(void)<br>{ <br> getch();<br> closegraph();<br>}<br>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值