本帖最后由 韋編弎絕 于 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的库之后,需要建立一个对象,并定义好引脚。 - U8GLIB_SSD1306_128X64 u8g(10, 9, 12, 11, 13); //SCK = 10, MOSI = 9 , CS = 12, A0 = 11, RES = 13
复制代码
1.u8g.drawBitmapP();
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)例子- const uint8_t rook_bitmap[] U8G_PROGMEM = {
- 0x00, // 00000000
- 0x55, // 01010101
- 0x7f, // 01111111
- 0x3e, // 00111110
- 0x3e, // 00111110
- 0x3e, // 00111110
- 0x3e, // 00111110
- 0x7f // 01111111
- };
- ...
- u8g.drawBitmapP(0,0, 1, 8, rook_bitmap);
复制代码
2.u8g.drawFrame();
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)例子- u8g.drawFrame(10, 12, 30, 20); // 方框的长宽包括了边框所在的像素点
复制代码
3.u8g.setFont();
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)方法定义- u8g_uint_t U8GLIB::drawStr(u8g_uint_t x, u8g_uint_t y, const char *s)
复制代码 2)功能
显示字符
3)参数
x:字符左下角的横坐标
y:字符左下角的纵坐标
*s:要显示的字符
4)例子- U8GLIB u8g(...)
- ...
- u8g.setFont(u8g_font_osb18);
- u8g.drawStr(0, 20, "ABC");
复制代码
5.u8g.setPrintPos();
1)方法定义- void U8GLIB::setPrintPos(u8g_uint_t x, u8g_uint_t y)
复制代码 2)功能
设置下文中print()的显示位置
3)参数
x:横坐标
y:纵坐标
6.u8g.print();
1)方法定义 2)功能
打印要显示的字符,包括变量值、字符串等。使用前需要使用setPrintPos()函数设置位置
7.u8g.firstPage();
1)方法定义- void U8GLIB::firstPage(void)
复制代码 2)功能
调用此过程,标志着图像循环的开始
8.u8g.nextPage();
1)方法定义- uint8_t U8GLIB::nextPage(void)
复制代码 2)功能
调用此过程,标志着图像循环的结束
若要使图像正常显示,u8glib库提供了如下的代码格式- void loop() {
- u8g.firstPage();
- do {
- //draw
- }while(u8g.nextPage());
- }
复制代码
=========================教程========================
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.定义结构体- struct FOOD {
- int x;
- int y;
- int yes;
- };
- FOOD food = {25, 30, 1};
- struct SNAKE {
- int x[200];
- int y[200];
- int node;
- int dir;
- int lefe;
- };
- SNAKE snake = {{9,5}, {30,30}, 2, RIGHT, 0};
复制代码
3.组成贪吃蛇的单位- //组成单位,4X4像素点的方块。
- const uint8_t ele[] PROGMEM = {
- 0xf0, //B1111000
- 0xb0, //B1011000
- 0xd0, //B1101000
- 0xf0, //B1111000
- };
- //蛇
- void element(int x, int y) {
- u8g.drawBitmapP(x,y, 1,4, ele);
- }
复制代码
■ ■ ■ ■ □ □ □ □ B11110000 0xF0
■ □ ■ ■ □ □ □ □ B10110000 0xB0
■ ■ □ ■ □ □ □ □ B11010000 0xD0
■ ■ ■ ■ □ □ □ □ B11110000 0xF0
这样一个4*4的方块为组成蛇的一个单位。
4.游戏的主界面- void UI() {
- u8g.drawFrame(0,1, 102,62); //内边界
- u8g.drawFrame(0,0, 102,64); //外边界
- u8g.setFont(u8g_font_5x7); //设置字体
- u8g.drawStr(104,12, "LEVEL"); //等级提示
- u8g.drawStr(104,40, "SCORE"); //分数提示
- }
复制代码
5.按键的获取- void setup() {
- pinMode(2, INPUT);
- pinMode(3, INPUT);
- pinMode(4, INPUT);
- pinMode(5, INPUT);
- digitalWrite(2, HIGH);
- digitalWrite(3, HIGH);
- digitalWrite(4, HIGH);
- digitalWrite(5, HIGH);
- }
- //按键判断
- void key() {
- if(LOW == digitalRead(2)) {
- snake.dir = DOWN;
- }
- if(LOW == digitalRead(3)) {
- snake.dir = RIGHT;
- }
- if(LOW == digitalRead(4)) {
- snake.dir = LEFT;
- }
- if(LOW == digitalRead(5)) {
- snake.dir = UP;
- }
- }
复制代码
6.蛇的移动- switch(snake.dir) {
- case RIGHT:
- snake.x[0] += 4;
- if(snake.x[0]>=101) {
- snake.x[0] = 1;
- } break;
- case UP:
- snake.y[0] -= 4;
- if(snake.y[0]<=1) {
- snake.y[0] = 58;
- } break;
- case LEFT:
- snake.x[0] -= 4;
- if(snake.x[0]<=0) {
- snake.x[0] = 97;
- } break;
- case DOWN:
- snake.y[0] += 4;
- if(snake.y[0]>=62) {
- snake.y[0] = 2;
- } break;
- }
- for(i=snake.node-1;i>0;i--) {
- snake.x[i] = snake.x[i-1];
- snake.y[i] = snake.y[i-1];
- }
复制代码
7.吃到食物
蛇头坐标与食物坐标相同,说明蛇吃到了食物。- if((snake.x[0] == food.x) && (snake.y[0] == food.y)) {
- snake.x[0] = food.x;
- snake.y[0] = food.y;
-
- snake.node++;
- food.yes = 1;
- score += 2;
- level = score/10+1;
- }
复制代码
8.画出图像
在do-while循环中写入代码,画出整个界面- u8g.firstPage();
- do {
- UI(); //画主界面
- //画蛇
- for(i=0; i<snake.node;i++) {
- element(snake.x[i], snake.y[i]);
- }
- //画食物
- element(food.x, food.y);
- //写分数
- printScore(109, 22, level);
- printScore(109, 50, score);
- }while(u8g.nextPage());
复制代码
本人能力有限,如有错误,还望看官海涵轻喷指正。本教程抛砖引玉希望大家DIY出更好的作品。
源文件: |