×
单片机 > 其他资讯 > 详情

基于stm32、0.96寸OLED实现的贪吃蛇小游戏(详细源码注释)

发布时间:2020-07-10 发布时间:
|

简介:本实验基于stm32最小系统、0.96寸OLED(68*128)和摇杆实现一个经典的贪吃蛇小游戏。


硬件设计:

普通摇杆,0.96寸OLED 单色屏幕(SPI协议通讯),stc32f103c8t6最小系统开发板,如下所示。

器件齐全后,用杜邦线将摇杆和oled正确地连接到stm32开发板上,注意各个器件的电源需要接到同一电压,下图是接线说明:


 接好线之后,将源码编译下载,进入调试,正常运行如下图所示,如果屏幕出现花屏,那么将res引脚接到GND进行复位,再重新进行调试或单片机复位:


接着按下摇杆的中键就可以进入游戏:


屏幕的上方显示得分,通过摇杆控制蛇的运动方向。


游戏失败后可按下摇杆中键重新开始游戏。


代码设计: 

源代码下载解压后,利用keil4工具打开工程可看到:


上面已表明各个文件的作用, 可重点看Snake.c游戏设计文件。如果代码里面的注释是乱码,点击Edit->Configuration->Editor->Encoding->选择Chinese GB2312。下面面只列举部分代码说明。


main函数


int main(void)

{

  RCC_PCLK1Config(RCC_HCLK_Div4);

  USART1_Configuration(); //初始化串口

  TIME_Configuration(); //初始化定时器

  ADC_Configuration(); //初始化摇杆的ad采集

  OLED_Init(); //oled初始化默认参数

      GameReady(); //进入游戏准备界面

 

  Tick_Updata(&sysms);

      while (1){

  event=JoyState(); //获取摇杆的状态

  ret=Game_InputHandle(event);//蛇移动

  if(ret){ //ret=1 表示屏幕需刷新

GameMapToLcdCache(); //将像素从游戏图像gamemap位图经过放大后写进LcdCache显存

OLED_Updata();//将LcdCache[8][128]显存的数据发送到屏幕进行显示

sprintf(str,"Score=%d",GameScore);

OLED_DispString(0,0,str); //屏幕上方显示分数

  }

     }

}

main函数并不复杂,while循环里面不断获取摇杆状态,将状态传进Game_InputHandle函数进行游戏操作。


实现原理:


运用链表的特性,蛇的每一个节点就是链表的节点,节点的内容是该点的x,y坐标,如上图所示。遍历链表逐个读取蛇身的每个节点里面的x,y坐标,根据该坐标在屏幕上描点,即可描绘出蛇的形状来。


蛇的运动的原理是从蛇尾节点开始,其x,y坐标等于前一个节点的坐标,直至到头节点,头节点的新x,y坐标跟蛇运动的方向有关。每当蛇迟到食物时,尾部追加节点。


void GAME_NewSnake(SNAKELIST* SnakeList) //初始化链表,初始化蛇长度,4+1节

{

int x=4,y=15,i;//蛇的初始位置

SnakeList->x=x;

SnakeList->y=y++;

SnakeList->prev=SnakeList;

SnakeList->next=SnakeList;

for(i=0;i<4;i++){

GAME_SnakeListAddNode(SnakeList,x,y+i);

}

GAME_SnakeFillInGameMap(gamemap,SnakeList);

}

GAME_NewSnake游戏开始前,给蛇初始化5个节点,头节点在x=4,y=15处,其余4个节点在其下方。通过GAME_SnakeFillInGameMap函数将蛇在gamemap上描画出来。gamemap再放大映射到LCDcache显存里面去,再通过spi把整个屏幕的像素发送到屏幕进行显示。


void GAME_NewFood(unsigned char (*gamemap)[WIDTH]) //在地图上随机产生新的食物

{

unsigned int seed1,seed2;

int x,y;

while(1){

Tick_Updata(&seed1);

Tick_Updata(&seed2);

x=seed1%WIDTH;

y=seed2%HEIGHT;

if(gamemap[y][x]==0){

gamemap[y][x]=2;

break;

}

}

}

GAME_NewFood在地图上随机生成一个食物,当然这里的随机数,利用不断变化的时钟进行求余,得到的随机坐标后,先判断该左边是否可用,若是已经存在东西(蛇身或者边框)则继续获取随机数,如此反复直到得到一个空的的随机坐标。所以,当游戏玩到最后,蛇身很长的时候(界面没有多少空白点),产生食物的时间会长很多。


unsigned char Game_InputHandle(unsigned char event)//对输入按键事件的处理

{

unsigned char ret=0;

if(GameStatus==GAMEPAUSE&&event!=RESTART_EV){ //游戏状态未运行时,除非按下restart,否则不进入

return 0;

}

if(event==5-Snokedirection){//按下蛇前进的相反方向时,忽略

event=NON; 

}

switch(event){

case NON:

speed_max=200;

if(If_TimeOut(&speed_move,SPPED_MOVE)){ //自动前进

Tick_Updata(&speed_move);

    event=Snokedirection;

    }else{

break;

}

case TURN_LEFT_EV: //蛇向左移动

case TURN_RIGHT_EV://蛇向右移动

case TURN_DOWN_EV: //蛇向下移动

case TURN_UP_EV: //蛇向上移动

if(If_TimeOut(&speed_turn,speed_max)){

Tick_Updata(&speed_turn);

speed_max=150;

Snokedirection=event;

ret=GAME_SnakeMove(gamemap,&SnokeHeadNode,event,&GameScore);

printf("event=%drn",event);

}

break;

case RESTART_EV://游戏复位

if(If_TimeOut(&speed_restart,SPPED_RESTART_MAX)){

Tick_Updata(&speed_restart);

GameStatus=GAMERUNING;

GameScore=0;

    Snokedirection=TURN_UP_EV;

GAME_BackgroundInit(gamemap);

GAME_NewSnake(&SnokeHeadNode);

GAME_NewFood(gamemap);

ret=1;

printf("event=%drn",event);

}

  break;

default:

//error

break;

}

return ret;

}

Game_InputHandle函数在main函数里被调用,SPPED_MOVE这个宏是控制蛇自动移动的速度的,所设置的值越低则运动的越快。speed_max的值是控制手动移动的速度,当摇杆状态被持续维持为一个方向时,就会按照该速度进行前进。

关键字:stm32  96寸OLED  贪吃蛇小游戏

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
详解漏电保护器的工作原理