极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 71831|回复: 12

Arduino+OLED 简易贪吃蛇教程

[复制链接]
发表于 2014-8-4 00:14:12 | 显示全部楼层 |阅读模式
本帖最后由 韋編弎絕 于 2014-8-9 19:13 编辑

    第一版实现了基本功能,操作上下左右按键实现蛇的移动,吃到食物增长。但没有实现碰壁、碰己的监测,食物固定不随机生成。



=========================准备=========================

一、所需硬件
  1. Arduino Nano  1个;
  2. 0.96寸OLED (SPI接口) 1个;
  3. 10*10*5mm 轻触开关  4个。

二、所需软件
  1. U8glib库;
  2. Arduino 1.0.5 IDE。

三、硬件连接
  1. OLED
      arduino       OLED
      D9        >     MOSI
      D10      >     SCK
      D11      >     DC
      D12      >     CS
      D13      >     RES

  2. 轻触开关
      arduino       button
      D2        >     DOWN  下
      D3        >     RIGHT   右
      D4        >     LEFT     左
      D5        >     UP        上
   
=======================必备知识=======================

    arduino Nano,OLED等的介绍不再赘述,网上很多,看一下贪食蛇游戏所需的 u8glib 库提供的方法,标题中未加参数,仅作简单介绍,详情请查看https://code.google.com/p/u8glib/wiki/userreference
对u8glib熟悉的看官可以忽略~~~。
    引入u8glib的库之后,需要建立一个对象,并定义好引脚。
  1. U8GLIB_SSD1306_128X64 u8g(10, 9, 12, 11, 13); //SCK = 10, MOSI = 9 , CS = 12, A0 = 11, RES = 13
复制代码


1.u8g.drawBitmapP();
    1)方法定义
  1. void U8GLIB::drawBitmapP(u8g_uint_t x, u8g_uint_t y, u8g_uint_t cnt, u8g_uint_t h, const u8g_pgm_uint8_t *bitmap)
复制代码
   2)功能
         显示一个位图
    3)参数
         x:位图左上角的横坐标
         y:位图左上角的纵坐标
         cnt:在水平方向上的位图的字节数。该位图的宽度是cnt* 8(1字节=8位)
         h:位图的高
         *bitmap:位图对象
    4)例子
  1. const uint8_t rook_bitmap[] U8G_PROGMEM = {
  2.   0x00,         // 00000000
  3.   0x55,         // 01010101
  4.   0x7f,          // 01111111
  5.   0x3e,         // 00111110
  6.   0x3e,         // 00111110
  7.   0x3e,         // 00111110
  8.   0x3e,         // 00111110
  9.   0x7f           // 01111111
  10. };
  11. ...
  12. u8g.drawBitmapP(0,0, 1, 8, rook_bitmap);
复制代码


2.u8g.drawFrame();
    1)方法定义
  1. void U8GLIB::drawFrame(u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
复制代码
   2)功能
         此函数是一个画方框的方法。
    3)参数
         x:方框左上角点的横坐标
         y:方框左上角点的纵坐标
         w:方框的宽
         h:方框的高
    4)例子
  1. u8g.drawFrame(10, 12, 30, 20); // 方框的长宽包括了边框所在的像素点
复制代码

   
3.u8g.setFont();
    1)方法定义
  1. U8GLIB::setFont(const u8g_fntpgm_uint8_t *font)
复制代码

    2)功能
         设置要显示字符的字体
    3)参数
         *font:字体样式。u8glib提供的字体样式https://code.google.com/p/u8glib/wiki/fontsize

4.u8g.drawStr();
    1)方法定义
  1. u8g_uint_t U8GLIB::drawStr(u8g_uint_t x, u8g_uint_t y, const char *s)
复制代码
   2)功能
         显示字符
    3)参数
         x:字符左下角的横坐标
         y:字符左下角的纵坐标
         *s:要显示的字符
    4)例子
  1. U8GLIB u8g(...)
  2. ...
  3. u8g.setFont(u8g_font_osb18);
  4. u8g.drawStr(0, 20, "ABC");
复制代码


5.u8g.setPrintPos();
    1)方法定义
  1. void U8GLIB::setPrintPos(u8g_uint_t x, u8g_uint_t y)
复制代码
   2)功能
         设置下文中print()的显示位置
    3)参数
         x:横坐标
         y:纵坐标

6.u8g.print();
    1)方法定义
  1. U8GLIB::print(...)
复制代码
   2)功能
         打印要显示的字符,包括变量值、字符串等。使用前需要使用setPrintPos()函数设置位置

7.u8g.firstPage();
    1)方法定义
  1. void U8GLIB::firstPage(void)
复制代码
   2)功能
          调用此过程,标志着图像循环的开始

8.u8g.nextPage();
    1)方法定义
  1. uint8_t U8GLIB::nextPage(void)
复制代码
   2)功能
          调用此过程,标志着图像循环的结束

    若要使图像正常显示,u8glib库提供了如下的代码格式
  1. void loop() {
  2.         u8g.firstPage();
  3.         do {
  4.                 //draw
  5.         }while(u8g.nextPage());
  6. }
复制代码


=========================教程========================

1.贪吃蛇算法
本贪吃蛇代码参考使用一下教程。
    http://www.oschina.net/code/snippet_143423_4296
    http://v.mybdqn.com/v_show/id_86.html
    http://v.mybdqn.com/v_show/id_87.html

    贪吃蛇会按照一定的间隔时间朝着一个方向移动,通过上下左右操作控制蛇移动方向。蛇的移动有两种算法可以使用。
    1. 火车头拉着走。

    2. 加头去尾。


    相对来说用火车头拉的方式是比较流行也是初学者最好掌握的方式。首先确定一个蛇头的坐标,蛇头每移动一次,蛇头后的每一节为前一节的旧坐标。

2.定义结构体
  1. struct FOOD {
  2.   int x;
  3.   int y;
  4.   int yes;  
  5. };

  6. FOOD food = {25, 30, 1};

  7. struct SNAKE {
  8.   int x[200];
  9.   int y[200];
  10.   int node;
  11.   int dir;
  12.   int lefe;
  13. };

  14. SNAKE snake = {{9,5}, {30,30}, 2, RIGHT, 0};
复制代码


3.组成贪吃蛇的单位
  1. //组成单位,4X4像素点的方块。
  2. const uint8_t ele[] PROGMEM = {
  3.   0xf0, //B1111000
  4.   0xb0, //B1011000
  5.   0xd0, //B1101000
  6.   0xf0, //B1111000
  7. };

  8. //蛇
  9. void element(int x, int y) {
  10.   u8g.drawBitmapP(x,y, 1,4, ele);
  11. }
复制代码

■ ■ ■ ■ □ □ □ □  B11110000  0xF0
■ □ ■ ■ □ □ □ □  B10110000  0xB0
■ ■ □ ■ □ □ □ □  B11010000  0xD0
■ ■ ■ ■ □ □ □ □  B11110000  0xF0


这样一个4*4的方块为组成蛇的一个单位。

4.游戏的主界面
  1. void UI() {
  2.   u8g.drawFrame(0,1, 102,62);   //内边界
  3.   u8g.drawFrame(0,0, 102,64);   //外边界
  4.   u8g.setFont(u8g_font_5x7);    //设置字体
  5.   u8g.drawStr(104,12, "LEVEL"); //等级提示
  6.   u8g.drawStr(104,40, "SCORE"); //分数提示
  7. }
复制代码



5.按键的获取
  1. void setup() {
  2.   pinMode(2, INPUT);
  3.   pinMode(3, INPUT);
  4.   pinMode(4, INPUT);
  5.   pinMode(5, INPUT);
  6.   digitalWrite(2, HIGH);
  7.   digitalWrite(3, HIGH);
  8.   digitalWrite(4, HIGH);
  9.   digitalWrite(5, HIGH);
  10. }

  11. //按键判断
  12. void key() {
  13.   if(LOW == digitalRead(2)) {
  14.     snake.dir = DOWN;
  15.   }
  16.   if(LOW == digitalRead(3)) {
  17.     snake.dir = RIGHT;
  18.   }
  19.   if(LOW == digitalRead(4)) {
  20.     snake.dir = LEFT;
  21.   }
  22.   if(LOW == digitalRead(5)) {
  23.     snake.dir = UP;
  24.   }
  25. }
复制代码


6.蛇的移动
  1.   switch(snake.dir) {
  2.     case RIGHT:
  3.           snake.x[0] += 4;
  4.           if(snake.x[0]>=101) {
  5.             snake.x[0] = 1;
  6.           } break;
  7.     case UP:
  8.           snake.y[0] -= 4;
  9.           if(snake.y[0]<=1) {
  10.             snake.y[0] = 58;
  11.           } break;
  12.     case LEFT:
  13.           snake.x[0] -= 4;
  14.           if(snake.x[0]<=0) {
  15.             snake.x[0] = 97;
  16.           } break;
  17.     case DOWN:
  18.           snake.y[0] += 4;
  19.           if(snake.y[0]>=62) {
  20.             snake.y[0] = 2;
  21.           } break;
  22.   }

  23.   for(i=snake.node-1;i>0;i--) {
  24.     snake.x[i] = snake.x[i-1];
  25.     snake.y[i] = snake.y[i-1];
  26.   }
复制代码


7.吃到食物
    蛇头坐标与食物坐标相同,说明蛇吃到了食物。
  1.   if((snake.x[0] == food.x) && (snake.y[0] == food.y)) {
  2.     snake.x[0] = food.x;
  3.     snake.y[0] = food.y;
  4.    
  5.     snake.node++;
  6.     food.yes = 1;
  7.     score += 2;
  8.     level = score/10+1;
  9.   }
复制代码


8.画出图像
    在do-while循环中写入代码,画出整个界面
  1.   u8g.firstPage();
  2.   do {
  3.     UI(); //画主界面

  4.     //画蛇
  5.     for(i=0; i<snake.node;i++) {
  6.       element(snake.x[i], snake.y[i]);
  7.     }

  8.     //画食物
  9.     element(food.x, food.y);

  10.     //写分数   
  11.     printScore(109, 22, level);
  12.     printScore(109, 50, score);
  13.   }while(u8g.nextPage());
复制代码


    本人能力有限,如有错误,还望看官海涵轻喷指正。本教程抛砖引玉希望大家DIY出更好的作品。

源文件:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-8-4 07:30:17 | 显示全部楼层
很详细的教程,我喜欢
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2014-8-4 22:04:07 | 显示全部楼层
努力微笑 发表于 2014-8-4 07:30
很详细的教程,我喜欢

谢谢~
回复 支持 反对

使用道具 举报

发表于 2014-8-5 11:20:12 | 显示全部楼层
高阶U8GLIB库教程啊。
回复 支持 反对

使用道具 举报

发表于 2014-8-5 13:38:49 | 显示全部楼层
赞!赞!赞!赞!
回复 支持 反对

使用道具 举报

发表于 2015-5-26 14:35:59 | 显示全部楼层
附件 u8glib_arduino_v1.17.zip 最新的V1.17版本的库

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2016-10-18 16:32:05 | 显示全部楼层
6脚的oled没有cs接口能用这个程序吗?
回复 支持 反对

使用道具 举报

发表于 2017-4-7 23:02:02 | 显示全部楼层
請問有哪些要自己打的? 我執行程式有錯誤
回复 支持 反对

使用道具 举报

发表于 2017-10-7 00:33:58 来自手机 | 显示全部楼层
很好,就喜欢详细的,
回复 支持 反对

使用道具 举报

发表于 2018-1-25 20:51:58 | 显示全部楼层
最近研究oled 中,貌似新的ug8lib库会编译错误
回复 支持 反对

使用道具 举报

发表于 2020-1-11 09:10:14 | 显示全部楼层
请教一下IIC的屏程序怎么改
回复 支持 反对

使用道具 举报

发表于 2020-1-13 20:40:09 | 显示全部楼层
详细的教程
回复 支持 反对

使用道具 举报

发表于 2020-12-19 14:09:12 | 显示全部楼层
非常详尽的教程!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 23:03 , Processed in 0.049733 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表