IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> arduinoNano实现2048小游戏 -> 正文阅读

[游戏开发]arduinoNano实现2048小游戏

一、元器件清单

元器件数量
LCD12864(驱动芯片为ST7920)1
arduino nano1
长面包板1
短面包板1
10K电阻4
轻触按钮4
100nF电容4
10K电位器1
导线若干
聪慧的大脑1
灵巧的手2

二、制作教程

搭建电路

首先按照原理图搭建电路:

image-20210817150718789

此处的10K电位器用于调节LCD12864的对比度,10K定值电阻用于下拉,100nF电容用于消抖。

LCD12864上的E、R/W和RS管脚与arduinoSPI接口的对应关系如下:

LCD12864ArduinoSPI接口
ESCK(对于arduino nano和uno来说,接口为13)
R/WMOSI(同上,接口为11)
RSCS(这个可自由指定,此处选择10号接口)

搭建完成后(未理线,较丑):

QQ图片20210817153908

烧录程序

新建名为arduino2048的文件夹,

在其中新建两个文件,写入以下内容:

arduino2048.ino

#include <time.h>
#include <U8g2lib.h>

//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);  //OLED

U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R2, /* CS=*/10, /* reset=*/12); //LCD12864
#include "Number.h"

/*Pins of Buttons*/
#define Up 4
#define Down 5
#define Left 6
#define Right 7

//#define CHEAT  //开局生成两个1024以作弊
//#define TEST_MODE //开启数字块显示测试

inline int getRand(int a, int b)
{
  return rand() % (b - a + 1) + a;
}

enum DIRECTION
{
  LEFT,
  RIGHT,
  UP,
  DOWN
};
class board
{
  private:
    int map[4][4];
    long score;
    using PtrToMemberFunc = bool (board::*)(int);                                                   //指向成员函数的指针
    PtrToMemberFunc Moves[4] = {&board::LeftOne, &board::RightOne, &board::UpOne, &board::DownOne}; //把四个方向移动的方法组织成一个数组
    bool changed;

  public:
    void init();
    void summon(bool noFour = false);
    bool isOver();
    bool isWon();
    bool isChanged() {
      return changed;
    }
    int getScore() {
      return score;
    }
    bool LeftOne(int ro);
    bool RightOne(int ro);
    bool UpOne(int ro);
    bool DownOne(int ro);
    void move(DIRECTION di);
    void updateDisplay();
    void setNum(int a, int b);
};

void board::init()
{

  memset(map, 0, sizeof(map));
  summon();
  summon(true);
#ifdef CHEAT
  map[0][0] = 1024;
  map[1][0] = 1024;
#endif
#ifdef TEST_MODE
  map[0][0] = 2;
  map[0][1] = 4;
  map[0][2] = 8;
  map[0][3] = 16;
  map[1][0] = 32;
  map[1][1] = 64;
  map[1][2] = 128;
  map[1][3] = 256;
  map[2][0] = 512;
  map[2][1] = 1024;
  map[2][2] = 2048;
#endif
  changed = true;
  score = 0;
}
void board::summon(bool noFour)
{
  struct block
  {
    int x;
    int y;
  } blanks[16];
  memset(blanks, 0, sizeof(blanks));

  int ptr = 0;
  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < 4; ++j)
      if (map[i][j] == 0) //遍历棋盘,寻找空格,放入队列
        blanks[ptr++] = {i, j};
  block &sele = blanks[getRand(0, ptr - 1)]; //从队列里随机选择一个空格
  if (noFour)
    map[sele.x][sele.y] = 2;
  else
    map[sele.x][sele.y] = getRand(1, 10) > 3 ? 2 : 4;
}

bool board::LeftOne(int ro)
{
  bool fail = true;
  int c = 0;
  while (c < 4)
  {
    int nextc = c + 1;
    while (nextc < 4 && map[ro][nextc] == 0)
      nextc++;
    if (nextc >= 4)
      break;
    if (map[ro][c] == 0)
    {
      fail = false;
      map[ro][c] = map[ro][nextc];
      map[ro][nextc] = 0;
      continue;
    }
    else if (map[ro][c] == map[ro][nextc])
    {
      fail = false;
      map[ro][c] *= 2;
      score += map[ro][c];
      map[ro][nextc] = 0;
    }
    ++c;
  }
  return fail;
}
bool board::RightOne(int ro)
{
  bool fail = true;
  int c = 3;
  while (c >= 0)
  {
    int nextc = c - 1;
    while (nextc >= 0 && map[ro][nextc] == 0)
      nextc--;
    if (nextc < 0)
      break;
    if (map[ro][c] == 0)
    {
      fail = false;
      map[ro][c] = map[ro][nextc];
      map[ro][nextc] = 0;
      continue;
    }
    else if (map[ro][c] == map[ro][nextc])
    {
      fail = false;
      map[ro][c] *= 2;
      score += map[ro][c];
      map[ro][nextc] = 0;
    }
    --c;
  }
  return fail;
}
bool board::UpOne(int ro)
{
  bool fail = true;

  int c = 0;
  while (c < 4)
  {
    int nextc = c + 1;
    while (nextc < 4 && map[nextc][ro] == 0)
      nextc++;
    if (nextc >= 4)
      break;
    if (map[c][ro] == 0)
    {
      fail = false;
      map[c][ro] = map[nextc][ro];
      map[nextc][ro] = 0;
      continue;
    }
    else if (map[c][ro] == map[nextc][ro])
    {
      fail = false;
      map[c][ro] *= 2;
      score += map[c][ro];
      map[nextc][ro] = 0;
    }
    ++c;
  }
  return fail;
}
bool board::DownOne(int ro)
{
  bool fail = true;

  int c = 3;
  while (c >= 0)
  {
    int nextc = c - 1;
    while (nextc >= 0 && map[nextc][ro] == 0)
      nextc--;
    if (nextc < 0)
      break;
    if (map[c][ro] == 0)
    {
      fail = false;
      map[c][ro] = map[nextc][ro];
      map[nextc][ro] = 0;
      continue;
    }
    else if (map[c][ro] == map[nextc][ro])
    {
      fail = false;
      map[c][ro] *= 2;
      score += map[c][ro];
      map[nextc][ro] = 0;
    }
    --c;
  }
  return fail;
}
void board::move(DIRECTION di)
{
  bool fail = true;
  for (int i = 0; i < 4; ++i)
  {
    bool tmp = (this->*Moves[di])(i);
    fail &= tmp;
  }
  changed = !fail;
  if (!fail)
    summon();
}
bool board::isOver()
{
  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < 4; ++j)
    {
      if (map[i][j] == 0)
        return false;
      if (j < 3 && map[i][j] == map[i][j + 1])
      {
        return false;
      }
      if (i < 3 && map[i][j] == map[i + 1][j])
      {
        return false;
      }
    }
  return true;
}
bool board::isWon()
{
  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < 4; ++j)
    {
      if (map[i][j] >= 2048)
        return true;
    }
  return false;
}

void board::updateDisplay()
{
  u8g2.clearBuffer();

  u8g2.drawFrame(0, 0, 61, 61);
  u8g2.drawHLine(0, 15, 61);
  u8g2.drawHLine(0, 30, 61);
  u8g2.drawHLine(0, 45, 61);
  u8g2.drawVLine(15, 0, 61);
  u8g2.drawVLine(30, 0, 61);
  u8g2.drawVLine(45, 0, 61);
  u8g2.setFont(u8g2_font_crox4t_tr);
  u8g2.drawStr(65, 28, "Score:");
  char score_str[6];
  itoa(score, score_str, 10);
  u8g2.drawStr(65, 48, score_str);

  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < 4; ++j)
      if (map[i][j] != 0)
        setNum(i, j);
  u8g2.sendBuffer();
}
void board::setNum(int a, int b)
{
  int num = map[a][b];
  u8g2.drawXBMP(1 + a * 15, 1 + b * 15, 14, 14, GET_NUM_DATA(num));
}

char getKey()
{
  while (!(digitalRead(Up) || digitalRead(Down) || digitalRead(Left) || digitalRead(Right)))
    ;
  bool U = digitalRead(Up);
  bool D = digitalRead(Down);
  bool L = digitalRead(Left);
  bool R = digitalRead(Right);
  while (digitalRead(Up) || digitalRead(Down) || digitalRead(Left) || digitalRead(Right))
    ;
  if (U)
    return 'a';
  if (D)
    return 'd';
  if (L)
    return 'w';
  if (R)
    return 's';
  return 'x';
}

board Game;
void setup()
{
  srand((unsigned)time(NULL) + analogRead(A0));
  u8g2.begin();

}

void loop()
{
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_maniac_tr);
  u8g2.drawStr(30, 24, "2048");
  u8g2.setFont(u8g2_font_7x14B_mr);
  u8g2.drawStr(48, 48, "Start");
  u8g2.drawFrame(45, 36, 40, 15);
  u8g2.sendBuffer();
  getKey();
  Game.init();
#ifdef TEST_MODE
  Game.updateDisplay();
  for (;;);
#endif
  while (!(Game.isOver() || Game.isWon()))
  {
    if (Game.isChanged())
      Game.updateDisplay();
    char cmd = getKey();
    switch (cmd)
    {
      case 'w':
        Game.move(UP);
        break;
      case 'a':
        Game.move(LEFT);
        break;
      case 's':
        Game.move(DOWN);
        break;
      case 'd':
        Game.move(RIGHT);
        break;
      default:
        break;
    }
  }
  Game.updateDisplay();
  delay(2000);
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_maniac_tr);
  if (Game.isWon())
  {
    u8g2.drawStr(23, 24, "You");
    u8g2.drawStr(23, 53, "Win!");
  }
  else
  {
    u8g2.drawStr(23, 24, "Game");
    u8g2.drawStr(23, 53, "Over");
  }
  u8g2.sendBuffer();
  delay(1500);
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_crox4t_tr);
  char score_str[6];
  itoa(Game.getScore(), score_str, 10);
  u8g2.drawStr(20, 28, "Your score:");
  u8g2.drawStr(20, 48, score_str);
  u8g2.sendBuffer();
  delay(2500);
}

Number.h

#ifndef _NUMBER_H
#define _NUMBER_H
// width: 14, height: 14
const unsigned char NUMs[][28] U8X8_PROGMEM = {
  {0xff, 0x3f, 0x03, 0x30, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0x03, 0x30, 0xf3, 0x3f, 0xf3, 0x3f, 0xf3, 0x3f, 0xf3, 0x3f, 0xf3, 0x3f, 0x03, 0x30, 0xff, 0x3f},
  {0xff, 0x3f, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0x03, 0x30, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0xff, 0x33, 0xff, 0x3f},
  {0xff, 0x3f, 0x03, 0x30, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0x03, 0x30, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0xf3, 0x33, 0x03, 0x30, 0xff, 0x3f},
  {0xff, 0x3f, 0x33, 0x30, 0x33, 0x3f, 0x33, 0x3f, 0x33, 0x3f, 0x33, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0xff, 0x3f},
  {0xff, 0x3f, 0xc1, 0x20, 0xc1, 0x20, 0xdf, 0x2f, 0xdf, 0x2f, 0xdf, 0x2f, 0xc1, 0x20, 0xc1, 0x20, 0xdf, 0x3e, 0xdf, 0x3e, 0xdf, 0x3e, 0xc1, 0x20, 0xc1, 0x20, 0xff, 0x3f},
  {0xff, 0x3f, 0xc1, 0x2e, 0xc1, 0x2e, 0xfd, 0x2e, 0xfd, 0x2e, 0xfd, 0x2e, 0xc1, 0x20, 0xc1, 0x20, 0xdd, 0x2f, 0xdd, 0x2f, 0xdd, 0x2f, 0xc1, 0x2f, 0xc1, 0x2f, 0xff, 0x3f},
  {0xff, 0x3f, 0x19, 0x21, 0x19, 0x21, 0x7b, 0x2d, 0x7b, 0x2d, 0x7b, 0x2d, 0x1b, 0x21, 0x1b, 0x21, 0xdb, 0x2d, 0xdb, 0x2d, 0xdb, 0x2d, 0x11, 0x21, 0x11, 0x21, 0xff, 0x3f},
  {0xff, 0x3f, 0x11, 0x21, 0x11, 0x21, 0xd7, 0x3d, 0xd7, 0x3d, 0xd7, 0x3d, 0x11, 0x21, 0x11, 0x21, 0x7d, 0x2d, 0x7d, 0x2d, 0x7d, 0x2d, 0x11, 0x21, 0x11, 0x21, 0xff, 0x3f},
  {0xff, 0x3f, 0x31, 0x23, 0x31, 0x23, 0x7d, 0x2f, 0x7d, 0x2f, 0x7d, 0x2f, 0x71, 0x23, 0x71, 0x23, 0x77, 0x3b, 0x77, 0x3b, 0x77, 0x3b, 0x31, 0x22, 0x31, 0x22, 0xff, 0x3f},
  {0xff, 0x3f, 0xe3, 0x30, 0xe3, 0x36, 0xe7, 0x36, 0xe7, 0x36, 0xc3, 0x30, 0xff, 0x3f, 0xff, 0x3f, 0xc3, 0x36, 0xdf, 0x36, 0xc3, 0x30, 0xfb, 0x37, 0xc3, 0x37, 0xff, 0x3f},
  {0xff, 0x3f, 0xc3, 0x30, 0xdf, 0x36, 0xc3, 0x36, 0xfb, 0x36, 0xc3, 0x30, 0xff, 0x3f, 0xff, 0x3f, 0xdb, 0x30, 0xdb, 0x36, 0xc3, 0x30, 0xdf, 0x36, 0xdf, 0x30, 0xff, 0x3f}
};

#define GET_NUM_DATA(num) (NUMs[__builtin_ctz(num) - 1])

#endif // _NUMBER_H

使用arduinoIDE打开arduino2048.ino,在选择了正确的端口、开发板之后,将电脑连接arduino nano,按Ctrl+U上传程序。

至此,基于Arduino nano在LCD12864上实现的2048小游戏已制作完成。

源代码解析和运行原理分析(超详细):点我

已开源于github:点我

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 13:01:39  更:2021-08-18 13:01:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 20:04:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码