|
闲暇之余发现看了下OLED12864的数据手册,发现他的显示在Y轴上只有页写,也就是一次写8个点。 突然想到,如果自己程序需要精准定位到某个点,那这不是会很艹蛋么?去网上搜索,基本上都是页写的代码,也就是在Y轴上的定位只能是0~7.7 s. b6 k4 I+ Y# ]$ i( z 于是花了点时间,做了个贪吃蛇的游戏,写了段程序。 程序硬件支持:& n4 m' j3 B* i) S" l STM32F446R+OLED12864+按键' @- c5 u: k/ ]: F% w & B0 P, K3 Y8 [5 b3 w9 S 软件结构:! }& ^8 j; X& p 1.DMA跑SPI刷屏 2.贪吃蛇游戏算法6 e! w# C3 v$ f; v2 O J5 f! @ 3.重新定义OLED显示方式 5 u7 z2 c; t T3 U+ n, G2 J0 p$ \" H 底层驱动就不说,DMA配置,跑SPI数据。0 w E' m* T% X& b) t % I- ]- j& {) u- ~" b 我先做了个二位数组,存放64*128个点,初始值为0;9 ]% v4 [* `; Q1 S( N) d! A uint8_t OLED_Display_Data[8][128]; W" r1 F6 X, w 4 Y6 L! r3 x' b+ _. V 之后开个定时器,每隔一段时间跑一次屏幕4 F* T& ~( c S8 C6 {$ F% v if(HardwareParamter.TimingOLED>=Refresh_Time && !HardwareParamter.OLEDFlash_flag)) `6 b/ k5 ]3 l; K { HardwareParamter.TimingOLED = 0;& W9 A! d* O( L$ e Display_Process(OLED_Display_Data); 5 p& @! _, d h% B) x8 U0 `( w) V }3 N$ ~8 P e6 p5 ]6 w6 w h5 z 基本想法就是,不停的跑这个数组,数组就是屏幕的每个点。 # ^* w8 r1 I5 i% r9 h3 s4 } 贪吃蛇算法做的简单:* e& @: s! }) `8 ?: o 首先是一个结构体,存放相关参数; W; q7 y$ r3 U) `2 @- _ typedef struct {& J' j( e2 Q& M- S+ f& b" r uint8_t food_x; //食物横坐标 uint8_t food_y; //食物纵坐标 uint8_t gameEsc; //游戏开始暂停 uint8_t gameSpeed; //游戏速度 uint8_t gameLevel; //游戏难度 uint8_t x[39]; uint8_t y[39]; uint8_t node; //蛇的节数 uint8_t direction; //蛇头方向) G5 `: x+ M; f6 O }GameParamter_t; ' I9 V) u. O2 j& I' P: k 两个核心函数:移动和创建食物 食物依赖于随机数生成函数. v) M9 S0 C6 O // 需要出现新食物 uint8_t createNewFood(void) {; [" E1 W ^/ P/ F; ~0 s uint8_t i;8 a5 l# a) _) y9 [ uint8_t size = GameParamter.node;$ d% d4 T6 J9 ]" @0 A4 T" a( R uint8_t flag = TRUE; // 标记创建的新事物与贪吃蛇的身体冲突4 C4 \6 @9 \% G2 G srand(HardwareParamter.TimingVal);5 g: D* a8 ~* y+ ^9 ^, } GameParamter.food_x = rand() % MAP_H; GameParamter.food_y = rand() % MAP_L;. q9 M; C. _! M# {3 u/ l9 z$ z% V# _) S // 食物的坐标必须为3的倍数才会在显示屏先被显示5 |6 [; H1 z- I& z& ^ for (; GameParamter.food_x % DOT_H != 0; ++GameParamter.food_x) { 1 d( S2 t7 y- ]1 H; r! |" h ; }: Q/ u/ j3 w) C 9 v0 s6 ^9 {. ^+ \, N for (; GameParamter.food_y % DOT_L != 0; ++GameParamter.food_y) { ;+ j) M5 ?6 I" D5 i }3 J: B) {9 W) }( H for (i = 0; i < size; ++i) {8 p. s" D; ]. l7 Y! k* l if (GameParamter.food_x == GameParamter.x[i] && GameParamter.food_y == GameParamter.y[i]) { flag = FALSE;( J# d# o' Q. ]# j1 e% u* g break;3 |$ E3 a: s& T- j7 d3 u5 T6 f1 n } } return flag;6 R2 X6 }+ N& S# c7 N }9 k0 V" G4 L( L3 ]4 ?! t( X 移动就是简单的数据加减 // 贪吃蛇移动, F. l8 j9 f" l- G( {: Z7 d0 R void move(void)% z8 _+ W& Q& ?- Y n {. B2 C& T, i: d1 |) Q- H, `0 A; n uint8_t i;) \0 I ^% T' C8 ~" ^, M 0 w: ~+ Z* L& _ H5 [! W8 G$ u, J" I if(GameParamter.gameEsc) {" _) L( t j" F& @3 q% L // 将蛇从最后个节点向前一个节点移动+ ]+ U: S+ l ]3 o$ } for(i = GameParamter.node - 1; i > 0; i--) { GameParamter.x[i] = GameParamter.x[i - 1]; GameParamter.y[i] = GameParamter.y[i - 1]; } 3 [2 L/ b9 b5 B: S: V& s // 根据此时贪吃蛇的方向,设置蛇头的位置 switch(GameParamter.direction) G) H' v/ D9 N8 q# A$ T { case RIGHT: GameParamter.x[0] += DOT_H; break; case LEFT: 6 i* d9 c( A, Q$ z) e' H7 t; c GameParamter.x[0] -= DOT_H; break;( N2 X" u5 n: `: Q' | case UP: GameParamter.y[0] -= DOT_L;+ }2 a4 d# |1 [' T8 ? break; case DOWN: - G! f a7 |, G3 R2 j* }. @ GameParamter.y[0] += DOT_L; break; } } }; F( \, w6 [. X" _2 W$ _ 显示部分随时更新) S9 t4 o2 e9 h) G1 I& x uint8_t temp;6 R/ `& X* R3 \0 B0 p! I switch(State_Flag)) k! l/ S5 |( u7 F% u {1 ~' N9 \/ g% R. Q+ M" N6 o case Snake_Move: //清除蛇尾部 for(temp = 0;temp < GameParamter.node;temp++) Oled_Dot(GameParamter.x[temp],GameParamter.y[temp],0);- W* v2 H, l, G5 J% w0 d //移动蛇* p8 B: ~0 V: D. @# \; d move(); % [1 }2 r1 k0 F) b% i* m //显示蛇的位置 for(temp = 0;temp < GameParamter.node;temp++) Oled_Dot(GameParamter.x[temp],GameParamter.y[temp],1); //吃到食物,创建新的食物. G1 l$ x( P+ R2 Q% `1 | if(GameParamter.food_x == GameParamter.x[0] && GameParamter.food_y == GameParamter.y[0]) Oled_food();" D* H7 M: H* w2 n8 N2 m8 `9 _5 w+ R % G+ R! `$ f3 i% O if(GameParamter.x[0] >= MAP_H || GameParamter.y[0] >= MAP_L)9 u5 P+ d. q3 R" S {$ u+ N6 V$ V$ T$ f OLEDClear(); OLED_ShowString(((128 - ((strlen("GAME")*10)))>>1),2,"GAME"); OLED_ShowString(((128 - ((strlen("OVER")*10)))>>1),5,"OVER"); State_Flag = Game_Over;8 P5 F2 [% i3 D. v1 m% h e# R HardwareParamter.OLEDFlash_flag = 1; } break;# y9 M Y7 W9 A. r5 c case Game_Over: break;2 H w5 }, f3 |1 x' C' L. B default: OLEDClear();3 v% c* D. x. t. n$ u/ {! | State_Flag = Snake_Move;- p$ b/ O. X# y, O8 ?: o HardwareParamter.OLEDFlash_flag = 0; break;* P# U6 d- O6 z6 ]" a } , H2 L( I3 s# V* f+ W# h* U6 ` 8 h8 ]3 V! _2 {4 V: I 外带一个按键处理,解决方向和暂停重置问题。: A4 M" F+ e& v- C2 D, ?6 M |
说起贪吃蛇,以前在大学的时候,学完数据结构,然后就在dos下面写了一个极其简陋的!!!![]() ![]() |
可以试试 |
| 有点意思。楼主有时间放个视频上来看看。 |
| 感谢分享,已汇总到2月技术原创 https://www.stmcu.org.cn/module/forum/thread-614799-1-1.html |
| 程序下载链接木有? |
| 楼主,想知道蛇头方向改变蛇身呈L或者类似矩形方波这些不规则的情况下蛇的移动部分的代码 |
最近正在捣鼓446,等手头的事情告一段落也想试着搞一个 |
【福利三:雨露均沾·逢7狂欢】之四:用一个定时器同步另外两个定时器输出PWM
【逢7发帖赢大礼】STM32开发之WIFI实时时钟
【逢7发帖赢大礼】STM32开发之指纹识别!
【逢7发帖赢大礼】STM32开发之环境空气质量监测
【逢7发帖赢大礼】STM32开发之人体实时运动信息监测!
【逢7发帖赢大礼】STM32开发之IC门禁卡UID读取方法!
【逢7发帖赢大礼】全网最简单的Arduino_STM32开发环境搭建教程!
STM32F4中文用户手册
STM32F400、STM32F402 Cortex-M4超值单片机
SPI 高温读错最后一位?STM32F42xx 官方根治方案
微信公众号
手机版