/**********************************************************************************************************
實現功能:
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(); //游戲重新開始;
}
|