基于stm32f103c8t6与OLED实现的贪吃蛇游戏

阅读: 评论:0

基于stm32f103c8t6与OLED实现的贪吃蛇游戏

基于stm32f103c8t6与OLED实现的贪吃蛇游戏

一、前言

本篇实现了一个使用c8t6驱动0.96寸OLED的贪吃蛇游戏。也可以使用rct6,就是改改启动文件,芯片类型,宏定义等等。需要完整代码的可以私信我。

二、硬件介绍

1、0.96寸OLED

我是用的是四线IIC接口的OLED

2、stm32f103c8t6

三、硬件连接

B5 -> OLED上的SDA

B6 -> OLED上的SCL

B8 -> 左按键

3.3v -> 左按键

B9 -> 右按键

3.3v -> 右按键

B10 -> 下按键

3.3v -> 下按键

B11 -> 上按键

3.3v -> 上按键

B12 -> 结束按键

3.3v -> 结束按键

R -> 复位按键

GUD -> 复位按键

四、主要代码实现

1、在OLED屏幕上显示/删除一个点

该代码主要实现在指定的x,y上打印一个点,将它存放在自定义的OLED_GRAM中,最终通过OLED_Refresh他们一并刷新到OLED上。

void OLED_DrawPoint(u8 x,u8 y)
{u8 pos,bx,temp=0;if(x>127||y>63)return;//超出范围了.pos=7-y/8;bx=y%8;temp=1<<(7-bx);OLED_GRAM[x][pos]|=temp;
}
void OLED_DrawNoPoint(u8 x,u8 y)
{u8 pos,bx,temp=0;if(x>127||y>63)return;//超出范围了.pos=7-y/8;bx=y%8;temp=1<<(7-bx);OLED_GRAM[x][pos]&=~temp; 
}

2、主要结构体与变量的定义

因为0.96寸OLED屏幕是128*64,将每2*2的四个OLED上的节点看做蛇的一个节点,所以定义地图大小为32*12

#define MAXLENGTH  100    //蛇的最大长度int map[32][12]={0};//地图大小  x,y(一个坐标为4*4个像素点)     实际按4倍尺寸放大后地图大小为128*48个像素点int score;            //分数bool eated=false;      //蛇吃到食物的标记u8 KeyValue=0;        //获取按键值struct {       int snake_Grid[MAXLENGTH][2];      //二维数组,行坐标表示蛇节点,列表示当前节点的x,y坐标int length;    //蛇的长度int direction;//蛇的方向
}snake;                          //定义结构体变量snakeint tailX, tailY; //标记尾部位置
int FoodX, FoodY; //标记食物位置

3、地图各个部分的输出

//创建地图函数
void Creat_map()//创建地图
{int i,j;for(i=0;i<12;i++){for(j=0;j<32;j++){if(i==0||i==11){map[j][i]=-2;}if(j==0||j==31){map[j][i]=-2;}}}
}//绘制地图函数
void Paint_Map(int x,int y)//绘制地图点坐标
{int i,j;for(i=4*y;i<4*y+4;i++)     {for(j=4*x;j<4*x+4;j++){OLED_DrawPoint(j,i+16); }}}//绘制蛇头函数
void Paint_Head(int x,int y )//绘制蛇头点坐标
{int i,j;for(i=4*y;i<4*y+4;i++)     {for(j=4*x;j<4*x+4;j++){if(i==4*y||i==4*y+3){OLED_DrawPoint(j,i+16);  }if(j==4*x||j==4*x+3){OLED_DrawPoint(j,i+16);  }}}
}//绘制蛇身函数
void Paint_Body(int x,int y )//绘制蛇身函数
{int i,j;for(i=4*y;i<4*y+4;i++)     {for(j=4*x;j<4*x+4;j++){if(i==4*y||i==4*y+3){OLED_DrawPoint(j,i+16);  }if(j==4*x||j==4*x+3){OLED_DrawPoint(j,i+16);  }}}
}//绘制食物坐标函数
void Paint_Food(int x,int y )//绘制食物点坐标
{int i,j;for(i=4*y;i<4*y+4;i++)     {for(j=4*x;j<4*x+4;j++){if(i==4*y+1||i==4*y+2){OLED_DrawPoint(j,i+16);  }if(j==4*x+1||j==4*x+2){OLED_DrawPoint(j,i+16); } }}// 更新食物的坐标FoodX = x;FoodY = y;
}void Paint_Clean(int x,int y)//取消地图点坐标
{int i,j;for(i=4*y;i<4*y+4;i++)     {for(j=4*x;j<4*x+4;j++){OLED_DrawNoPoint(j,i+16); }}}
//清除界面函数
void GUI_Clear()//界面清除
{int i,j;for(i=0;i<32;i++){for(j=0;j<12;j++){map[i][j]=0; }}
}//画蛇函数:将二维数组snake.snake_Grid里面的各个蛇坐标的值存入map数组
void drawSnake()            //画蛇
{int i,x,y;//蛇头x=snake.snake_Grid[0][0];y=snake.snake_Grid[0][1];map[x][y]=1; //蛇身for(i=1;i<snake.length;i++){x=snake.snake_Grid[i][0];y=snake.snake_Grid[i][1];map[x][y]=2;       }}

4、界面刷新函数

通过这个函数来输出这个游戏的所有显示数据。

//刷新界面函数:根据map数组里面的值一次性刷新游戏界面内的点坐标
void GUI_Refresh()//界面刷新
{int i,j,temp;for(i=0;i<32;i++)                 {for(j=0;j<12;j++){temp=map[i][j];switch (temp){case 2:	      Paint_Body(i,j);  break;case  1:		   Paint_Head(i,j);  break;case -2:		   Paint_Map(i,j);  break;case-1:		   Paint_Food(i,j);  break;case 0:		   Paint_Clean(i,j);break;}		   }}
}

5、蛇的初始化

初始化蛇长度为5、方向向右、蛇头坐标位于(7,5)。

//初始化蛇和地图函数:初定蛇长度为5、方向向右、蛇头坐标位于(7,5)
void Snake_Init()//蛇及地图初始化
{  int i;snake.length=5;snake.direction=RIGHT;score=0;snake.snake_Grid[0][0]=7;//x坐标,蛇头坐标snake.snake_Grid[0][1]=5;//y坐标,蛇头坐标tailX = snake.snake_Grid[snake.length - 1][0]; // Initialize tail coordinatestailY = snake.snake_Grid[snake.length - 1][1];for(i=1;i<snake.length;i++){snake.snake_Grid[i][0]=snake.snake_Grid[0][0]-i;snake.snake_Grid[i][1]=snake.snake_Grid[0][1];  //给刚开始的蛇身几个初始坐标}Creat_map();
}

6、获取键盘值

初始在snake.h中宏定义了方向

#define RIGHT 1
#define LEFT 2
#define DOWN 3
#define UP 4

使用中断的方法读取按键对应引脚的上升沿,将值赋给全局变量KeyValue;

//按键处理函数:自定义矩形键盘值控制蛇的方向
void Get_Command()//获取键盘值
{u8 key=1;key=KeyValue;	switch(key){case 1:if(snake.direction!=RIGHT)         //左snake.direction=LEFT;			break;case 2:if(snake.direction!=LEFT)           //右snake.direction=RIGHT;			break;case 3:if(snake.direction!=DOWN)        //上snake.direction=UP;break;case 4:if(snake.direction!=UP)         //下snake.direction=DOWN;break;		}    
}

7、中断部分函数为下

void EXTI9_5_IRQHandler(void)
{					 if(KEY8==1)		//按键0{KeyValue=1;EXTI->PR=1<<8;}else if(KEY9==1){KeyValue=2;EXTI->PR=1<<9;}//清除LINE5上的中断标志位  
}
//外部中断15~10服务程序
void EXTI15_10_IRQHandler(void)
{					 if(KEY10==1)		//按键1{KeyValue=3;EXTI->PR=1<<10;}else if(KEY11==1)		//按键1{KeyValue=4;EXTI->PR=1<<11;}else if(KEY12==1)		//按键1{Show_Endface();KeyValue=5;EXTI->PR=1<<12;}//清除LINE15上的中断标志位  
}
//外部中断初始化程序
//初始化PA0,PC5,PA15为中断输入.
void EXTI_Init(void)
{KEY_Init();Ex_NVIC_Config(GPIO_B,8,RTIR); 		//上升沿触发Ex_NVIC_Config(GPIO_B,9,RTIR);		//上升沿触发Ex_NVIC_Config(GPIO_B,10,RTIR);		//上升沿触发Ex_NVIC_Config(GPIO_B,11,RTIR);		//上升沿触发Ex_NVIC_Config(GPIO_B,12,RTIR);		//上升沿触发MY_NVIC_Init(2,0,EXTI9_5_IRQn,2);    	//抢占2,子优先级2,组2MY_NVIC_Init(2,1,EXTI15_10_IRQn,2);    	//抢占2,子优先级2,组2 
}

8、蛇的移动函数

主要思想就是先判断蛇头结点是否与食物结点重合,如果没重合就删掉尾节点,头结点根据方向移动;如果重合,就不删掉尾节点,头结点根据方向移动。然后前结点的坐标等于后结点的坐标。

//蛇的移动函数:蛇身移动就让其坐标等于前一个坐标的值,蛇头则根据蛇的方向就行移动
void Move() {int i;int headX = snake.snake_Grid[0][0];int headY = snake.snake_Grid[0][1];tailX = snake.snake_Grid[snake.length - 1][0]; // 存储当前尾巴的坐标tailY = snake.snake_Grid[snake.length - 1][1];// 判断蛇头是否与食物坐标重合if (headX == FoodX && headY == FoodY) {snake.length++;eated = true;  // 设置为true,表示吃到了食物score += 1;Food(); // 生成新的食物} else {map[tailX][tailY] = 0; // 清除尾巴}for (i = snake.length - 1; i > 0; i--) {snake.snake_Grid[i][0] = snake.snake_Grid[i - 1][0];snake.snake_Grid[i][1] = snake.snake_Grid[i - 1][1];}switch (snake.direction) {case UP:snake.snake_Grid[0][1]--;break;case DOWN:snake.snake_Grid[0][1]++;break;case LEFT:snake.snake_Grid[0][0]--;break;case RIGHT:snake.snake_Grid[0][0]++;break;}drawSnake();
}

9、生成食物

//生成食物函数:在游戏界面内空位生成食物点坐标,并将食物坐标存入map数组
int Chek(int i,int j)//检查地图空位
{if(map[i][j]!=0){return 0;}return 1;   //是空位就返回1
}void Food()//生成食物
{int i,j;do{i=(rand()%30)+1;                 //生成1~30之间的一个数j=(rand()%10)+1;                 //生成1~10之间的一个数}while(Chek(i,j)==0);                //检查该点是否为空位map[i][j]=-1;//画出食物
}

10、判断游戏是否结束

bool GameOver()//游戏结束
{bool isGameOver=false;int sx=snake.snake_Grid[0][0],sy=snake.snake_Grid[0][1],i;//蛇头坐标for(i=1; i<snake.length; i++)    //判断有没有吃到自己{if(snake.snake_Grid[i][0]==sx&&snake.snake_Grid[i][1]==sy)isGameOver=true;}if(snake.snake_Grid[0][0]==31||snake.snake_Grid[0][0]==0|| snake.snake_Grid[0][1]==11||snake.snake_Grid[0][1]==0)        //判断有没有撞墙isGameOver=true;return isGameOver;
}

11、显示分数

//显示分数
void Show_Score()//显示分数
{OLED_ShowString(30,6,"Score:",16);OLED_ShowNum(80,6,score,2,16);}

五、效果展示

本文发布于:2024-01-29 00:55:57,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170646096211550.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:贪吃蛇   游戏   OLED
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23