基于单片机的贪吃蛇游戏

简介: 贪吃蛇游戏的规则是:玩家通过四个方向键来控制蛇的移动,控制其在地图上吃豆子。吃掉豆子后蛇身相应加长,蛇身速度加快。蛇运动过程中撞到墙壁或蛇身,则立即结束游戏。

一. 点亮一个灯
这个很简单,就是把某一行线置1,并且把某一列线置0,其他的行线全部为0,列线全部为1.

void Led(u8 dat,u8 dat2) //dat为行线值,dat2为列线值
{

u16 i;
RCLKS = 1;
SRCLK = 1;


for(i=0;i<8;i++)
{
//行线的输入是由74HC595模块输入的,
//通过时钟的上升沿把每一位的数据输入即可,高位优先
    SET = dat>>7;
    dat = dat <<1;
    SRCLK = 0;
    SRCLK =1;
}

RCLKS = 0;

RCLKS = 1;
P0 = dat2;   //列线由P0端口输入

}

这里令dat = 0x20,dat2=fb的时候,一个发光二极管就被点亮啦!

二. 一个灯的移动
前面我们已经知道了,行线可以控制那一行亮那一行不亮,列线也同样如此。
假设当我们的列线不变,行线左移一位或者右移一位,是不是我们的灯向上或者向下移动了一个!行线不变时,列线的移动同样如此,但是要注意,列线是为0点亮,每一次左移或右移,低位或高位就会多出来一个0,这时,我们还需要加上0x01或者0x80以消掉这个多出来的0

1.向上移动

列线不变,行线左移一位即可

if(Rows[0] != 0x80) //防止移过头了

    Rows[0] <<=1;

2.向下移动

列线不变,行线右移一位即可

if(Rows[0] != 0x01)

    Rows[0]>>=1;

3.向左移动

行线不变,列线左移一位加0x01即可

if(Cols[0] != 0x7F)

{
    Cols[0] <<=1;
    Cols[0] += 1;
}

4.向右移动

行线不变,列线右移一位加0x80即可

if(Cols[0] != 0xFE)

{
    Cols[0] >>=1;
    Cols[0] += 0x80;
}

自此,一个灯的上下左右的移动我们已经完成了,接下来蛇的移动了

三. 贪吃蛇
认真看玩过贪吃蛇的朋友应该都清楚,蛇身是随着蛇头的移动而移动的。其中不难发现。当前蛇的某一节的位置是它前面一节蛇的上一个状态的位置,知道了这个规律之后,我们就可以很方便地更新蛇的状态了。
由于8×8点阵显示有限,我就只设置了蛇的最大长度为5,防止闪烁。

1.蛇的存储

这里我采取的是数组的方式,存储每一节的行线值和列线值

u8 Rows[5]; //行线值
u8 Cols[5]; //列线值

2.蛇的更新

前面说过,蛇的当前蛇的某一节的位置是它前面一节蛇的上一个状态的位置,也就是说,Rows[n-1] = Rows[n],Cols[n-1] = Cols[n]
当然这里的Rows[n],和Cols[n]是上一个状态的值了

void Up(u8 len) //当前蛇的长度
{

u8 i;
u8 tmp = Rows[0];
u8 rr,cc_1,cc_2;
if(Rows[0] != 0x80)
    Rows[0] <<=1;
cc_1 = Cols[0];
    //后一节依次等于前一节的上一个状态的值
for(i=1;i<len;i++)
{
    
    rr = Rows[i];  // 保存上一个状态
    Rows[i] =tmp;  //Rows[i]为当前状态
    tmp = rr;
    
    cc_2 = Cols[i];   // 保存上一个状态
    Cols[i] = cc_1;   
    cc_1 = cc_2;
}

}

这里就只拿了向上移动的代码作为参考,其他方向的移动类型,基本上一样,这里蛇的移动也完成了。

3.食物

食物的行线与列线同样用两个变量存储。食物的位置是随机的,这里我们用rand产生随机数并对8求余数,这样就得到了0-7的随机数,然后对0x01进行相应的左移,就得到了选定的行,取反就得到了选定的列。

Food_col = ~(0x01 << rand()%8);
Food_row = 0x01 << rand()%8;

4.吃到食物

这也是很好办的事,只需要判断蛇头的Row和Col是否等于食物的Row和Col,
如果相等,则更新食物的位置,蛇身加一.

if((Rows[0] == Food_row) && (Cols[0] == Food_col)) // 判断是否吃到食物

    {
        if(len<5)  //判断蛇长是否达到最大值
        {
            Rows[len] = Rows[len-1];
            Cols[len] = Cols[len-1];
            len++;
        }
        //随机更新食物的位置
        Food_col = ~(0x01 << rand()%8);
        Food_row = 0x01 << rand()%8;
    }

自此,贪吃蛇可以说已经基本完成了,剩下的就是用键盘来控制蛇的移动方向了

四. 蛇方向的控制
方向的控制我把它放在中断里面,这样可以解决如下问题

如果不用延迟,蛇移动得太快,根本看不清楚蛇的移动。
如果用延迟来控制蛇移动的速度,那么键盘的读取就会变动不灵敏,
要按下许久之后,才能读取,游戏效果不好。
因此我决定把它放在定时器中断中,通过设定初值,以极小的时间差,来读取键盘的内容,即可达到实时的效果,而且延时对这个完全没有干扰。

void Time_0() interrupt 1
{

u8 key;
key = KEY();
if(key != -1)
{
    if(key == 1)
    {
        //Up(len);
        direct = 0;
        delay(10000); // 不用也没有关系,不会造成影响
    }
    if(key == 9)
    {
        //Down(len);
        direct = 1;
        delay(10000);
    }
    if(key == 4)
    {
        //Left(len);
        direct = 2;
        delay(10000);
    }
    if(key == 6)
    {
        //Right(len);
        direct = 3;
        delay(10000);
    }
}
//防止p过大
if(p>8*100)
    p = 0;
p++;
//每8次移动一下,这是合理的,由于每一次的时间差极小
//8次加起来的时间差也是非常小的,
//该时间差小于先后按下两个不同方向的时间差,因为这是合理的
if(p%8 == 0)
{
switch(direct)
{
    case 0: Up(len);break;
    case 1: Down(len);break;
    case 2: Left(len);break;
    case 3: Right(len);break;
}
}
TH0 = 0x0c;
TL0 = 0x0c;

}

五. main函数
这部分也是非常简单的。

void main()
{

u8 i;
//u8 len = 1;  // 初始化长度,这个放到全局变量中了
u8 Food_row = 0x20;
u8 Food_col = 0xfb;
//u8 direct = 0;// 初始化方向,这个放到全局变量中了
Rows[0] = Row;  //初始化,蛇头的位置
Cols[0] = Col;
Init_time_0();   //配置定时器0,开启中断
while(1)
{
    //判断蛇头是否到达食物的位置
    if((Rows[0] == Food_row) && (Cols[0] == Food_col))
    {
        if(len<5)
        {
            Rows[len] = Rows[len-1];
            Cols[len] = Cols[len-1];
            len++;
        }
                    //随机更新食物的位置
            Food_col = ~(0x01 << rand()%8);
            Food_row = 0x01 << rand()%8;
    }
    
    Led(Food_row,Food_col);  //显示食物
    for(i=0;i<len;i++)
        Led(Rows[i],Cols[i]);  // 显示蛇
        
    //这里用延时来控制速度的话,容易产生闪烁。
}

}

相关文章
|
4天前
|
算法 定位技术 C语言
51单片机实现俄罗斯方块游戏编程
设计了一款基于AT89C51单片机的俄罗斯方块游戏机,使用LCD12864液晶显示,按键控制方块移动与变形。游戏中,7种不同形状的方块随机下落,填满一行得分,满屏则游戏结束。包含电源、单片机最小系统、LCD和按键模块的硬件电路通过Proteus进行了仿真,展示了游戏运行、得分和计时等。代码部分展示了检查碰撞和更新地图的函数。
16 1
|
存储 异构计算
51单片机项目实战---贪吃蛇(测试版)
一、元器件 1、AT89C51     关于51单片机就不在啰嗦了,相信大家都已经很熟悉了,关于它的一些常用细节,已经在另一篇博文中提到     http://blog.chinaunix.net/uid-29270124-id-4571661.html2、8x8点阵     点阵里面就是一些二极管啦,通过纵横交叉连接,横8竖8,每个交叉点都接一个二极管。
1059 0
|
4天前
|
编译器 C语言 开发者
单片机原理与应用:探索微型计算机世界
单片机原理与应用:探索微型计算机世界
21 1
|
4天前
|
数据采集 数据处理 C语言
单片机:探索其原理、应用与编程实践
单片机:探索其原理、应用与编程实践
22 1
|
4天前
|
物联网
STC51单片机-实验开发装置仿真-物联网应用系统设计
STC51单片机-实验开发装置仿真-物联网应用系统设计
64 0
|
4天前
|
物联网
STC51单片机-控制LED闪亮的仿真-物联网应用系统设计
STC51单片机-控制LED闪亮的仿真-物联网应用系统设计
47 0
|
4天前
|
芯片
AT89S52单片机的最小应用系统
AT89S52单片机的最小应用系统
6 0
|
4天前
|
存储 芯片
【期末不挂科-单片机考前速过系列P11】(第十一章:15题速过串行口的工作原理和应用)经典例题盘点(带图解析)
【期末不挂科-单片机考前速过系列P11】(第十一章:15题速过串行口的工作原理和应用)经典例题盘点(带图解析)
【期末不挂科-单片机考前速过系列P10】(第十章:11题中断系统的工作原理及应用)经典例题盘点(带图解析)
【期末不挂科-单片机考前速过系列P10】(第十章:11题中断系统的工作原理及应用)经典例题盘点(带图解析)