找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4940|回复: 3
打印 上一主题 下一主题
收起左侧

arduino制作打砖块的小游戏

[复制链接]
跳转到指定楼层
楼主
ID:387981 发表于 2018-8-20 01:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/**********************************************************************************************************
实现功能:
OLED 屏幕显示温湿度值;

实现思路:
程序的整体思路为:上电后,OLED 屏幕上实时显示温湿度传感器返回的温度值和湿度值;

实验接线:
OLED 屏幕接A4,A5口
摇杆模块接到A0,A1
**********************************************************************************************************/
#include "U8glib.h"//引用U8G头文件
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);//设置设备名称:I2C-SSD1306-128*64(OLED)
/*=========================================================
                      自定义摇杆和相关变量
  =========================================================*/

#define Direction 14           //定义摇杆水平方向上的引脚;(控制下方的木板左右移动)
#define Direction_RMB 15       //定义摇杆垂直方向上的引脚;(向上是用来选择关卡的【也可以说是快捷控制胜利的按键】,向下是复位按键)//由于该引脚控制很强大,故定义该引脚的名字时任性一下,RMB:俗称人民币玩家;
#define Data_of_left 300       //定义摇杆水平方向的数值,摇杆向左摆动时,其传感器触发的数值(该数值要看实际情况而定);
#define Data_of_right 650      //定义摇杆水平方向的数值,摇杆向右摆动时,其传感器触发的数值(该数值要看实际情况而定);
#define Data_of_up 200         //定义摇杆垂直方向的数值,摇杆向上摆动时,其传感器触发的数值(该数值要看实际情况而定);
#define Data_of_down 750       //定义摇杆垂直方向的数值,摇杆向下摆动时,其传感器触发的数值(该数值要看实际情况而定);
int muban = 1;                 //该变量用来判断砖块是否碰到木板;
int Atmp;                      //缓存
int Btmp;                      //缓存(Atmp 和 Btmp这两个变量用于存储当砖块碰到墙时,砖块所在的位置。记录该值,主要用于程序后面砖块碰到墙,墙消失,实际上记录的是要消失的墙的位置;
byte DF = 1;                   //难度 1-3(即该游戏总共有三个关卡);
int WX;                        //木板宽度
byte WL;                       //木板长度
float BX, BY;                  //球的坐标
boolean MAP[16][8];            //砖块位置  0为空气  1为砖块
float AX, AY;                  //小球速度
boolean WIN;                   //该布尔值主要判断是否胜利;
int Data_of_sensor = 0;        //定义一个存储摇杆水平方向数据的变量;
int Data_of_sensor_RMB = 0;    //定义一个存储摇杆垂直方向数据的变量;
/*======================================================================================================================================================================================================*
|                     只循环一次                                                                                                                                                                       |
* ======================================================================================================================================================================================================*/
void setup() {
  //串口通讯波特率设置
  Serial.begin(9600);                 //设定波特率为9600;
  pinMode(Direction,INPUT);            //设置摇杆为输入模式;
  pinMode(Direction_RMB,INPUT);        //设置摇杆为输出模式;
  start();                             //游戏开始;
}
/*======================================================================================================================================================================================================*
|                     不停循环                                                                                                                                                                         |
* ======================================================================================================================================================================================================*/
void loop() {
  muban = 1;                                       
  Data_of_sensor = analogRead(Direction);               //读取摇杆水平方向的数据;
  Data_of_sensor_RMB = analogRead(Direction_RMB);       //读取摇杆垂直方向的数据;
  if( Data_of_sensor <= Data_of_left)  { WX -= 5; }     //如果摇杆向左摆动,OLED 屏幕里的木板向左移动(速度是一次向左移动5个像素);
  if( Data_of_sensor >= Data_of_right) { WX += 5; }     //如果摇杆向右摆动,OLED 屏幕里的木板向右移动(速度是一次向右移动5个像素);
  if( Data_of_sensor_RMB <= Data_of_up) { win(); }      //如果摇杆向上摆动时,自动选择下一关;
  if( Data_of_sensor_RMB >= Data_of_down) { Reset(); }  //如果摇杆向下摆动时,程序复位(即游戏重新开始);
  else { delay(1); }                                    //这里的否则也就是不对摇杆进行操作;


  /*=========================================================
                  计算
    =========================================================*/
  if (WIN == true) win();
  if (WX < -(WL / 2)) WX = -(WL / 2);           //防止溢出
  if (WX > 128 - (WL / 2)) WX = 128 - (WL / 2); //防止溢出
  //小球位移
  BX += AX;
  BY += AY;
  /*=========================================================
                  砖块边缘反弹
    =========================================================*/
  if (BX > 125) {
    BX = 125;
    AX = -AX;
  }
  if (BX < 0) {
    BX = 0;
    AX = -AX;
  }
  if (BY >= 61) {            //如果砖块没有被木板接住,muban=0,说明失败了;
    BY = 61;
    muban = 0;
    draw();
    AY = -AY;
  }
  if (BY < 0) {
    BY = 0;
    AY = -AY;
  }
  /*=========================================================
                  砖块与木板
    =========================================================*/
  if (BX >= WX && BX <= WX + WL)   {
    if (BY >= 56 - 3 && BY <= 57 - 3) {
      //接触到木板上下部分
      AX = -(((WX + (WL / 2)) - BX) / (WL / 2));
      AX *= 1.8;
      AY = -AY;
    }
  }

  /*=========================================================
                砖块与墙
    =========================================================*/
  if (int(BX / 8) + 1 <= 16 && int(BY / 4) + 1 <= 8) {
    Atmp = BX / 8;
    Btmp = BY / 4;
    if (MAP[Atmp][Btmp] == 1) {
      //碰到砖头
      MAP[Atmp][Btmp] = 0;
      //反弹代码 分类讨论 分为上下和左右
      if (BY - 2 <= Btmp * 4 || BY >= Btmp * 4 + 4) {
        //上和下边缘
        AY = -AY;
      } else
      {
        AX = -AX;
      }
    }
  }
  /*=========================================================
                    显示
    =========================================================*/
  u8g.firstPage();
  do {
    draw();
  } while ( u8g.nextPage() );
}

/*====================================================================================================================================*
|               初始化游戏                                                                                                           |
* ===================================================================================================================================*/
void start() {
  WL = 32;
  for (byte i = 1; i < DF; i++) {
    WL = WL / 2;                       //递进计算木板长度(这里的for语句就是玩家完成一个难度时,跳入下一个难度的部分)
  }
  WX = 64 - (WL / 2);                  //计算木板初始所在的中间线横坐标
  for (byte x = 0; x < 16; x++) {
    for (byte y = 0; y < 8; y++) {
      MAP[x][y] = 1;                   //该for语句主要和后面的void draw()函数呼应,告诉void draw()这个函数相应的位置是存在墙的;
    }                                  //也就是告诉后面的void draw()函数,各个位置可以添加墙。
  }
  BX = 64;                             
  BY = 52;                             //定义初始的小砖块所在的位置;即在OLED 屏幕的(64,52);
  AX = 2;                              //初始小球加速度
  AY = -2;
  loop();                 //虽然程序会先执行void setup(),再执行void loop();但对于比较冗长的程序,为了保险起见,再次调用loop();
}


/*====================================================================================================================================*
|               渲染游戏画面                                                                                                         |
* ===================================================================================================================================*/
void draw() {
  if(muban == 0)
  {
    fail();               //如果砖块碰到木板,程序进入fail();(即如果砖块下降过程时,最终木板没有接住砖块,则失败;
  }

  if (muban == 1)
  {
    no_fail();           //如果砖块最终被木板接住,砖块继续被木板反弹;
  }
}
/*------------------------------------------------------------------------------------------------------*
其显示砖块的实心矩形的样式为:                                                                          |
(0, 0, 7, 3);       (8, 0, 7, 3);       (16, 0, 7, 3);     (24, 0, 7, 3);        ... (120, 0, 7, 3);    |
(0, 4, 7, 3);       (8, 4, 7, 3);       (16, 4, 7, 3);     (24, 4, 7, 3);        ... (120, 4, 7, 3);    |
(0, 8, 7, 3);       (8, 8, 7, 3);           ...                   ...                      ...          |
(0, 12, 7, 3);      (8, 12, 7, 3);          ...                   ...                      ...          |
   ...                                                                                     ...          |
   ...                                                                                     ...          |
(0, 28, 7, 3);     (8, 28, 7, 3);     (16, 28, 7, 3);              ...                (120, 28, 7, 3);  |
------------------------------------------------------------------------------------------------------*/
/*==========================================================================================================================================**
|                失败                                                                                                                       |
* ==========================================================================================================================================*/
void fail()                           
{
for(int i=0;i<3;i++)                  //这里的for语句在OLED 屏幕上显示的效果为:先显示“Game Over”,延时500毫秒后,接着“Game Over”不显示(即
{                                     //先前显示的“Game Over”消失,延时500毫秒,将这一套动作看做为一个动作,则,这个动作执行3次;
  u8g.firstPage();                     //开始加载OLED 屏幕的界面
  do {
       no_fail();
       u8g.setFont(u8g_font_courB12);  //接下来要显示的字体的字号为u8g_font_courB12号;
       u8g.setColorIndex(0);           //不显示,透明
       u8g.drawBox(20, 12, 88, 40);    //画一个空心矩形,该矩形从(20,12)这个点开始(也就是矩形左上角的坐标),矩形的宽为88个像素,高为40个像素。
                                       //由于该句之前显示的样式为透明&&不显示,所以这里的矩形是透明的(在OLED 屏幕上这个矩形区域是黑的);
       u8g.setColorIndex(1);           //显示,不透明;
       u8g.setPrintPos(20, 30);        //设置该句之后的print();要显示内容的位置;
       u8g.print("Game Over");         //在(20,30)这个位置显示 Game Over;
  } while ( u8g.nextPage() );          //关闭OLED 屏幕界面
  delay(500);

  u8g.firstPage();
  do {
       no_fail();
       u8g.setFont(u8g_font_courB12);  //接下来要显示的字体的字号为u8g_font_courB12号;
       u8g.setColorIndex(0);           //不显示,透明
       u8g.drawBox(20, 12, 88, 40);    //画一个空心矩形,该矩形从(3,12)这个点开始(也就是矩形左上角的坐标),矩形的宽为88个像素,高为40个像素。
                                       //由于该句之前显示的样式为透明&&不显示,所以这里的矩形是透明的(在OLED 屏幕上这个矩形区域是黑的);
       u8g.setColorIndex(1);           //显示,不透明;
       u8g.setPrintPos(20, 30);        //设置该句之后的print();要显示内容的位置;
       u8g.print("");                  //在(30,30)这个位置什么都不显示;
  } while ( u8g.nextPage() );
  delay(500);

}
  start();     
}

void no_fail()
{
  WIN = true;
  u8g.drawBox(WX, 56, WL, 3);                           //显示底下木板           
  u8g.drawBox(int(BX), int(BY), 3, 3);                  //显示砖块(砖块的初始位置在OLED 屏幕的(64,52),且砖块的宽为3,高为3;
  for (byte x = 0; x < 16; x++) {
    for (byte y = 0; y < 8; y++) {
      if (MAP[x][y] == 1) {
        WIN = false;
        //存在墙
        u8g.drawBox(x * 8, y * 4, 7, 3);                //按照下面说明的“砖块的实心矩形的样式”来一个一个显示墙
      }
    }
  }   
}
/*==========================================================================================================================================**
|                通关                                                                                                                       |
* ==========================================================================================================================================*/
void win() {
  u8g.firstPage();
  do {
    draw();
    u8g.setFont(u8g_font_courB12);  //接下来要显示的字体的字号为u8g_font_courB12号;
    u8g.setColorIndex(0);           //不显示,透明
    u8g.drawBox(20, 12, 88, 40);    //画一个空心矩形,该矩形从(3,12)这个点开始(也就是矩形左上角的坐标),矩形的宽为88个像素,高为40个像素。
                                    //由于该句之前显示的样式为透明&&不显示,所以这里的矩形是透明的(在OLED 屏幕上这个矩形区域是黑的);
    u8g.setColorIndex(1);           //显示,不透明;
    u8g.setPrintPos(30, 30);        //设置该句之后的print();要显示内容的位置;
    u8g.print("You Win");           //在(30,30)这个位置显示 You Win;
  } while ( u8g.nextPage() );
  delay (2000);
  if (DF < 3) {                     //该for语句就是当玩家通过一个简单的模式时,
    DF++;                           //会自动进入下一个难度(即木板会变短),
  } else {                          //该游戏主要有三个难度等级,如果三个难度
    DF = 1;                         //等级都通过后,游戏会重新开始;
  }
  start();                          //完成一个难度等级后,游戏自动开始,进入下一个等级;
}

/*==========================================================================================================================================**
|                复位                                                                                                                       |
* ==========================================================================================================================================*/
void Reset() {                         //游戏复位键;
  u8g.firstPage();
  do {
       u8g.setFont(u8g_font_courB12);  //接下来要显示的字体的字号为u8g_font_courB12号;
       u8g.setColorIndex(1);           //显示,不透明;
       u8g.setPrintPos(40, 30);        //设置该句之后的print();要显示内容的位置;
       u8g.print("Reset");             //在(40,30)这个位置显示 You Win;
     } while ( u8g.nextPage() );
  delay (1500);
  start();                             //游戏重新开始;
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:387981 发表于 2018-8-20 01:17 | 只看该作者
代码的注释超级详细,希望能帮到各位
回复

使用道具 举报

板凳
ID:1 发表于 2018-8-20 01:36 | 只看该作者
好东东 希望有原理图与介绍
回复

使用道具 举报

地板
ID:656339 发表于 2019-12-4 22:14 | 只看该作者
你好,这个有完整接线图码
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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