嵌入式贪吃蛇

基于arm的嵌入式LCD显示屏贪吃蛇游戏

开始界面选择挑战模式,随机产生目标食物,触摸显示屏,控制蛇身移动,吃到食物时蛇身加长,分数加一,达到一定的数目挑战成功,碰到障碍物,挑战失败,在游戏开始之后,伴有背景音乐。

系统功能实现过程:
在这里插入图片描述

父进程开始,初始化LCD,设置LCD地址映射,打开LCD表面电容触摸屏触摸功能,打开BMP背景图片,进入开始界面,判断触摸点位置,回收LCD的资源,关闭LCD, 选择功能关卡,对应两个功能,父进程创建子进程,根据触摸点位置,子进程使用execl()函数,子进程执行贪吃蛇游戏代码。在子进程中,初始化LCD,设置LCD的地址映射,打开LCD表面电容触摸屏触摸功能,打开BMP背景图片,创建三个线程,通过三个线程配合使用实现随机食物的产生,蛇身移动,背景音乐的播放功能。

线程一:轮询LCD的触摸屏,判断触摸点的位置,判断蛇身下一次的移动方向。

线程二:打开madplay软件,实现背景音乐的播放。

线程三:根据线程一的触摸信息控制蛇身移动,蛇身的移动使用队列的方式,蛇头作为队尾,蛇尾作为队首,根据蛇头下一点的移动方向判断是否吃到食物,判断是否碰到了墙壁。

(1)吃到食物,判断是否完成挑战,即吃到了指定的食物数量,完成挑战,则发送cancel信号给其他两个线程,等待其他两个线程结束,回收资源,执行_exit()结束子进程。否则,入队,食物的显示位置作为新的蛇头,不进行出队操作,蛇尾保持不变,

(2)没有吃到食物,同时进行入队出队操作,增加新的蛇头,删除蛇尾。蛇尾到达下一点的队列的尾部。

(3)碰到了障碍物,则发送cancel信号给其他两个线程,等待其他两个线程结束,回收资源,执行_exit()结束子进程。

关键代码:

(1)线程一轮询LCD的触摸屏位置信息:

void *KEY_value(void *p)
{
   while(1)
{
     get_xy(&X0,&Y0);
     sem_wait(&touch_condition);
if  ( X0< 600 && Y0>300)      KEY_state =turn_LEFT;
     
else if( ((X0> 611 && X0<670) && ( Y0>380 && Y0<440)) )KEY_state=turn_down;
    
else if( ((X0> 680 && X0<734) && ( Y0>380 && Y0<440)) )KEY_state=turn_right;
     
else if( ((X0> 610 && X0<670) && ( Y0>300 && Y0<360)) )KEY_state =turn_up ;
     
else {KEY_state=KEY_state;}
     
sem_post(&touch_condition);
     
if(OVER==2)pthread_exit(NULL);
    
    }
}

get_xy(&X0,&Y0);实现LCD触摸屏位置信息的获取。

x0,y0,用于保存当前的触摸点坐标位置。

turn_LEFT;turn_right;turn_up ;turn_down得到按键的位置,赋值给KEY_state。

由于考虑到多线程通信是通过全局变量实现的,因此必须考虑变量的使用顺序问题,通过信号量的限制,更新KEY_state的值,KEY_state保存着当前触摸屏的位置信息,供线程三控制蛇身移动。

(2)蛇移动的实现:

从蛇头到蛇尾,每一处都是结构体数组的一个元素,每个元素存放该显示点的像素点坐标,循环的执行入队出队操作,根据蛇头蛇尾的坐标信息,触摸点的位置信息,确定下一点的坐标信息。

根据线程一KEY_state的值;


switch(KEY_state)
        {
      case turn_LEFT :
             SNAK[snake_front_next].x_point=SNAK[snake_front].x_point-20;
             SNAK[snake_front_next].y_point=SNAK[snake_front].y_point;
             break;
     
case turn_right:
         SNAK[snake_front_next].x_point=SNAK[snake_front].x_point+20;
             SNAK[snake_front_next].y_point=SNAK[snake_front].y_point;
             break;
      
case turn_up   :
             SNAK[snake_front_next].x_point=SNAK[snake_front].x_point;
             SNAK[snake_front_next].y_point=SNAK[snake_front].y_point-20;
             break;
      
case turn_down :
             SNAK[snake_front_next].x_point=SNAK[snake_front].x_point;
             SNAK[snake_front_next].y_point=SNAK[snake_front].y_point+20;
             break;
    
 default:
break;
}

蛇身的每一点图片大小为20*20的BMP格式图片。

SNAK[snake_front_next] 存放当前蛇头的位置信息

SNAK[snake_front] 存放下一点蛇头的位置信息

根据蛇头下一点位置信息,确定执行移动操作,通关操作和挑战失败操作:

sem_post(&touch_condition);
/
//判断是否撞在障碍物上:
/
if( (SNAK[snake_front_next].x_point>=520)||(SNAK[snake_front_next].x_point<0) ||  (SNAK[snake_front_next].y_point<0) || (SNAK[snake_front_next].y_point>=480))
       
 {
                end_condition=fail;
                break;
        }
/
//判断是否咬到蛇身:
/
for(value=0;value<MAX_NUM;value++)
{
     if(SNAK[value].stat)
     {
         if( (SNAK[snake_front_next].x_point==SNAK[value].x_point) && 
                ( (SNAK[snake_front_next].y_point==SNAK[value].y_point) ) )
           {
                end_condition=fail;
                break;
           }
      }
}
/
//判断是否吃到了食物:
/
    
if((SNAK[snake_front_next].x_point==target.x_point) && 
            ( (SNAK[snake_front_next].y_point==target.y_point) ))
{
      snake_front=snake_front_next;
      SNAK[snake_front].stat=1;
      score+=1  ;
      speed+=50 ;
      eat_value=0;
      printf("吃到了食物\r\n");
}
else 
{
      printf("处于查找状态\r\n");
      snake_front=snake_front_next;
      SNAK[snake_front].stat=1;



//蛇身位置更新:
			 

bmp_show(S_PIC,SNAK[snake_front].x_point,SNAK[snake_front].y_point);
//画出新的舌头
bmp_show_bck(SNAK[snake_rear].x_point, SNAK[snake_rear].y_point,20,20);
//覆盖旧的蛇尾

SNAK[snake_rear].stat=0;
snake_rear=(snake_rear+1) %MAX_NUM;
}

在这里插入图片描述

总结

第一次使用带有操作系统的开发板完成一个小的项目,从纯裸机的开发,到操作系统的简单应用,从裸机程序到带有操作系统的的程序编写,对用户空间,内核空间有了简单的了解,用户空间的应用程序调用open()打开一个设备,再到内核空间通过系统调用(一堆函数)调用与硬件对应的驱动程序,实现了对外设的控制,实现了数据的获取,进而得到需要处理的数据,裸机的代码,与应用层的代码,有着很大的不同,裸机是操作一个一个的寄存器,而应用层则使用那些接口函数,在贪吃蛇这个项目的实现中,遇到了很多的问题,发现了自己的不足,对C语言的知识得到了巩固,也对嵌入式的这段学习有了简单的实际应用。

获取详细代码:关注该公众号呀!
LLP学嵌入式

  • 8
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值