|
闲暇之余发现看了下OLED12864的数据手册,发现他的显示在Y轴上只有页写,也就是一次写8个点。! f3 G* _+ U9 K9 i 突然想到,如果自己程序需要精准定位到某个点,那这不是会很艹蛋么?去网上搜索,基本上都是页写的代码,也就是在Y轴上的定位只能是0~7. 于是花了点时间,做了个贪吃蛇的游戏,写了段程序。8 ^" \4 P6 a0 k4 M# K6 W( [ 程序硬件支持:$ O$ |3 z1 m. `7 u1 ^- X, @# \ STM32F446R+OLED12864+按键 软件结构:5 J- {) B- R0 |% l$ H# U- L 1.DMA跑SPI刷屏# l8 z3 T* R7 h1 } 2.贪吃蛇游戏算法# b$ u0 J* p( n# }' w2 m 3.重新定义OLED显示方式 底层驱动就不说,DMA配置,跑SPI数据。( b" c' _$ _; c 7 k4 a: g6 {2 Y$ n2 O5 k6 R 我先做了个二位数组,存放64*128个点,初始值为0;, g) X2 W8 Z( U7 k% g4 N3 o8 l uint8_t OLED_Display_Data[8][128], V- w7 G" C4 s( u6 a0 f5 T1 j 之后开个定时器,每隔一段时间跑一次屏幕& O& o# v- r6 D if(HardwareParamter.TimingOLED>=Refresh_Time && !HardwareParamter.OLEDFlash_flag) {7 o' d5 Q9 M, C2 T- U* t) ^/ l HardwareParamter.TimingOLED = 0; Display_Process(OLED_Display_Data); : B/ l, n5 `; \7 y+ S }1 A! t2 S: H1 s" x7 H3 u! F+ x ) A/ p7 n9 X( G/ p+ R: ^ 基本想法就是,不停的跑这个数组,数组就是屏幕的每个点。; l% D5 l0 ^' r6 s% _" Q( } 贪吃蛇算法做的简单: 首先是一个结构体,存放相关参数: [& h. S8 [" C0 x0 q$ ^! E typedef struct {+ S" k' q: o/ V uint8_t food_x; //食物横坐标 uint8_t food_y; //食物纵坐标, O- w& Z; }" B! ?! s* |8 S, {; m1 C" l uint8_t gameEsc; //游戏开始暂停 uint8_t gameSpeed; //游戏速度 uint8_t gameLevel; //游戏难度3 C2 v/ J8 {, P( c6 G q uint8_t x[39]; uint8_t y[39]; O: B9 ^' a( C, ~ uint8_t node; //蛇的节数 uint8_t direction; //蛇头方向 }GameParamter_t;, T: n5 x3 H$ ~: @ 两个核心函数:移动和创建食物 食物依赖于随机数生成函数) I/ u0 R# y# V7 u3 V' c // 需要出现新食物5 N) @2 H0 b3 G+ C2 e$ V1 z uint8_t createNewFood(void) {- h' k+ ~- A6 A6 f* u7 t# c4 H uint8_t i;2 d; ]2 @* }1 `5 L8 D2 j5 Q+ q" M1 s uint8_t size = GameParamter.node;0 `5 P3 W; |- C; }( l uint8_t flag = TRUE; // 标记创建的新事物与贪吃蛇的身体冲突# |6 M- s: N4 P. S srand(HardwareParamter.TimingVal);9 i% e: q% y# {# m2 F3 ` GameParamter.food_x = rand() % MAP_H; GameParamter.food_y = rand() % MAP_L;8 R* X- F+ _/ P `! X: }0 B3 a 1 U c+ Q3 v* A! [ // 食物的坐标必须为3的倍数才会在显示屏先被显示 for (; GameParamter.food_x % DOT_H != 0; ++GameParamter.food_x) { ;+ C5 g3 A1 Z- Z {* v }7 J; B i5 V1 A" I ( n5 c; [' U$ x( h G! K" u for (; GameParamter.food_y % DOT_L != 0; ++GameParamter.food_y) { ;% N, H( v& K) L+ a, s9 ^# W } for (i = 0; i < size; ++i) { if (GameParamter.food_x == GameParamter.x[i] && GameParamter.food_y == GameParamter.y[i]) { flag = FALSE; break;" d2 I$ ` P8 _6 w8 M' G: \ } } return flag; }) b2 ^* Z) f% f. S9 o 7 E1 O' e; G3 ], H3 \$ W, k . b1 H3 A/ x2 | N 移动就是简单的数据加减: J! o) L5 X+ X3 o8 Q( ` // 贪吃蛇移动 void move(void): F% j9 x* g! ?6 l" p {% b" S; _8 w( |/ R9 k8 S uint8_t i;8 D( [1 a! ~5 z0 X( r 3 H: G2 t2 n ~- }" y. c& {0 _ if(GameParamter.gameEsc)( D" c# i2 m0 F" A- K! ~. \ { // 将蛇从最后个节点向前一个节点移动 for(i = GameParamter.node - 1; i > 0; i--) { GameParamter.x[i] = GameParamter.x[i - 1];* `# ~# N7 [3 F+ c GameParamter.y[i] = GameParamter.y[i - 1];% O5 A% e8 ^. a) l" H }5 o. _. U8 p8 N# Z6 \0 { 3 r1 q3 _3 ]+ N" I! X. h: N // 根据此时贪吃蛇的方向,设置蛇头的位置 . E2 j6 ?+ i0 ~ switch(GameParamter.direction) { - C) d3 D$ t* F case RIGHT: ! a8 T3 H9 i3 V" F: c GameParamter.x[0] += DOT_H; break;( ~0 j1 J6 U8 P# f case LEFT: ) s v. d1 y; G+ Y# Y3 f. P* {! Q GameParamter.x[0] -= DOT_H;4 d8 y: [* U/ z8 s. b! _2 ] break; case UP: ~: P: [4 V$ v( a GameParamter.y[0] -= DOT_L; break; case DOWN: 6 U% M6 s/ e: S1 ?( v6 Q5 O) O/ {5 G GameParamter.y[0] += DOT_L;6 N& w+ r2 S0 d# L2 w3 m1 e break;! U8 n# r% j# u1 n }! C" _7 s" q( i9 ]2 B0 ? } } 显示部分随时更新" l, E. v/ Y0 Z+ w' Q0 I uint8_t temp;( K: ]$ B8 h w4 K s% O 3 ?) \, B1 f- o7 t switch(State_Flag) { case Snake_Move: //清除蛇尾部% [* O* |0 U& Y for(temp = 0;temp < GameParamter.node;temp++) Oled_Dot(GameParamter.x[temp],GameParamter.y[temp],0); //移动蛇# f2 _4 s. \8 T# C- ? move();3 I* R; B. u3 A( E* E //显示蛇的位置 for(temp = 0;temp < GameParamter.node;temp++)# O; y( Z% m5 y J7 b Oled_Dot(GameParamter.x[temp],GameParamter.y[temp],1); //吃到食物,创建新的食物 if(GameParamter.food_x == GameParamter.x[0] && GameParamter.food_y == GameParamter.y[0]) Oled_food(); + u0 K; h n9 i; A; m! q; a if(GameParamter.x[0] >= MAP_H || GameParamter.y[0] >= MAP_L) { OLEDClear(); OLED_ShowString(((128 - ((strlen("GAME")*10)))>>1),2,"GAME");2 C g% @: s0 d6 ? OLED_ShowString(((128 - ((strlen("OVER")*10)))>>1),5,"OVER"); State_Flag = Game_Over; HardwareParamter.OLEDFlash_flag = 1; } break;* q p& v5 ]6 f* h9 O. ?. v7 C case Game_Over: break;0 P2 _4 {- u- x! s9 F+ ~ default:/ G0 v# p7 A1 U1 ~6 b4 A" f/ {' i OLEDClear();* L- C0 x8 ?/ f2 k; \8 x State_Flag = Snake_Move; HardwareParamter.OLEDFlash_flag = 0;9 n1 }; V5 F& \6 i break;' p# }4 m o9 g& Z }( R2 a. x7 B' `& W) K( {, D7 p9 e 5 ^7 t" i* [3 ?: I* d 外带一个按键处理,解决方向和暂停重置问题。 ( h+ t Z4 u* B' G1 d! v; J |
说起贪吃蛇,以前在大学的时候,学完数据结构,然后就在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 官方根治方案
微信公众号
手机版