Arduino小游戏集合(俄罗斯方块)
一:前期準備
用到的硬件材料Arduino Mega2560 + LCD4884 Joystick Shiled
屏幕分辨率為48*84
軟件平臺Arduino IDE, 需要用到的庫U8glib +MsTime2
二:設計思路
1:游戲整體界面
標準的俄羅斯方塊為行寬為10,列高為20,結合屏幕大小每個最小單位點設為2*2像素,共計七種方塊,19種形狀,使用[10][20]的二維數組存放方塊位置信息,需要顯示則將相應位置的數組值改為1,空白則為0。并在左側顯示下一個方塊形狀,右側顯示當前分數和等級
游戲界面如圖所示
2:方塊的產生、變換和移動
我沒有采用使用整體存放方塊圖形信息的方法,因為不知道怎么使用U8glib庫旋轉單個圖形,采用的是一種比較笨的方法。
每一種方塊選取一個中心點,圍繞這個中心點來繪制方塊,移動的時候也是直接移動中心點然后重新在中心點繪制方塊,總共有16種方塊圖形這里選取其中一種來做例子說明
(1)方塊的產生
例如Z形方塊
選取B為中心點,只需要獲取B的坐標信息,設為(x,y)那么其他幾個方塊的坐標也能相應求出來,然后將二維數組中的這幾個對應值設為1,循環繪制的時候就能顯示出方塊圖形了
(2)方塊的變換和移動
我們想要控制方塊旋轉的時候就需要重新獲取方塊生成的方式
在方塊移動和變換的時候在這之前都需要先在二維數組中清空原有的方塊信息,然后重新按照新的生成方式寫入數組里面
(3):方塊檢測
每一次在移動和和變換的過程中還需要判斷是否能夠移動和變換,需要檢測方塊周圍是否有足夠的空間
檢測方法如下
由于方塊無法向上移動,所以上部不需要判斷,我們只知道B的坐標,1-7號坐標可以根據B的坐標推斷出來
當我們需要右移動的時候就需要判斷 2、4、6號位置是否已有方塊阻擋或者到達邊界,同理下移則需判斷5、7號位置
三:詳細設計
1:按鍵檢測
LCD4884 Joystick Shiled帶有一個搖桿按鍵,并且和A0腳連接,所以讀取A0引腳值即可。
void Control()
{
switchVoltage = analogRead(0);
if ( switchVoltage > 600 && switchVoltage < 800 ) //上
dir = 1 ;
else if ( switchVoltage > 180 && switchVoltage < 400 ) //下
dir = 3;
else if ( switchVoltage == 0 ) //左
dir = 4;
else if ( switchVoltage > 400 && switchVoltage < 600 ) //右
dir = 2;
else if ( switchVoltage > 0 && switchVoltage < 180 ) //確認
dir = 5;
}
為了防止按鍵粘連,使用了MsTime2庫定時掃描
MsTimer2::set(100, Control); /*定時器中斷按鍵的掃描*/
MsTimer2::start();
2:初始化
在游戲運行之前,初始化屏幕亮度、游戲等級、隨機數種子(防止每一次方塊出現次數都相同、清空數組值以及方塊中心點位置,
randomSeed(analogRead(1)); /*隨機產生隨機數序列以免方塊的順序為固定的*/
block_num = random(1, 20); /*生成第一個方塊信息
block_num_next = random(1, 20) ; /*生成第二個方塊
x = 5 , y = 2;
block_state_right = 0 ;
block_state_left = 0;
block_state_down = 0;
level_now = 300;
light_value = 50; /*設置背光亮度*/
pinMode(LCD_BACKLIGHT_PIN , OUTPUT);
analogWrite(LCD_BACKLIGHT_PIN, light_value);
3:繪制游戲界面背景
顯示當前等級和分數,以及下一個方塊形狀,游戲的等級設置的是每次自動向下移動時延時的毫秒數,move_speed越小等級越高,方塊向下移動也越來越快
void interface()
{
u8g.setFont(u8g_font_timR08);
u8g.drawStr(57, 10, "Score");
u8g.drawStr(57, 30, "Grade");
u8g.drawStr(0, 10, "Next");
u8g.setPrintPos(70, 20);
/*顯示分數*/
u8g.print(score);
/*顯示等級*/
if ( move_speed <= 300)
u8g.drawBox(60, 42, 3, 6);
if ( move_speed <= 250)
u8g.drawBox(65, 39, 3, 9);
if ( move_speed <= 200)
u8g.drawBox(70, 36, 3, 12);
if ( move_speed <= 150)
u8g.drawBox(75, 33, 3, 15);
if (move_speed <= 100)
u8g.drawBox(80, 30, 3, 18);
/*顯示下一個方塊*/
create_box_next(1);
for (int m = 0 ; m < 5 ; m++)
for (int n = 0 ; n < 5 ; n++)
{
if ( block_next[m][n] == 1)
u8g.drawBox(3 * m + 5, 3 * n + 15, 3, 3);
}
create_box_next(0);
}
4:方塊的生成
形狀太多,代碼復用率太高只截取部分,每次移動或者變換的時候都需要調用這個函數來清除上一個方塊的位置信息
void create_box(int a ) /*調整block數組中的值,參數為0的時候清除,參數為1時寫入*/
{
switch (block_num)
{
case 1:
block[x][y + 1] = a;
block[x][y - 1] = a;
block[x - 1][y] = a;
block[x][y] = a;
break ;
}
}
5:方塊的移動和變換
每次移動和變換之前都得判斷方塊能否移動,能夠移動還需要在移動之前清空原有的,不能移動的時候需要產生新的方塊,這時候方塊的中心點需要重置,并且當前形狀的標號改為block_num_next的值,再重新隨機生成一個數給block_num_next
void block_go() /*方塊的移動和變形*/
{
block_fixed();
if (block_state_down == 1 ) /*方塊不能下降的時候生成新的方塊*/
{
for (int m = 0; m < 10; m++)
{
if (block[m][3] == 1) /*判斷游戲是否結束*/
{
game_over();
break;
}
}
x = 5 , y = 2; /*設置初始中心點位置*/
block_num = block_num_next ;
block_num_next = random(1, 20) ;
block_state_right = 0 ;
block_state_left = 0;
block_state_down = 0;
create_box(0);
}}
變換方塊形狀,需要注意的是方塊標號是連續的,每次變換的時候實際只是更改了當前方塊的標號,為了防止從一個類型調到另一個類型需要做一些判斷來限制標號更改的范圍
switch (dir)
{
case 1: /*變換方塊形狀*/
create_box(0);
if ( block_num >= 1 && block_num <= 4) /*防止變換的時候方塊形狀發生變換*/
{
block_num++;
if (block_num > 4)
block_num = 1;
}
}
6:判斷方塊能否移動
每一種方塊的判斷方法都不同,需要根據當前方塊標號做出不同的判斷,判斷結束會返回三個狀態,block_state_left、block_state_down、block_state_right,這三個值為0的時候是可以向這個方向移動的
void block_fixed() /*判斷方塊是否能夠移動*/
{
switch (block_num)
{
case 1:
if (block[x - 2][y] == 1 || block[x - 1][y - 1] == 1 || block[x - 1][y + 1] == 1 || x <= 1)
block_state_left = 1;
else
block_state_left = 0;
if (block[x + 1][y] == 1 || block[x + 1][y - 1] == 1 || block[x + 1][y + 1] == 1 || x >= 9)
block_state_right = 1;
else
block_state_right = 0;
if (block[x - 1][y + 1] == 1 || block[x][y + 2] == 1 || y >= 18)
block_state_down = 1;
else
block_state_down = 0;
break;
}
}
7:繪制方塊
遍歷二維數組,當值為1的時候則顯示最小像素點
void draw_block() /*繪制方塊*/
{
int block_x , block_y;
for (block_x = 0 ; block_x < 10 ; block_x ++)
for (block_y = 0 ; block_y < 20 ; block_y ++)
{
if (block[block_x][block_y] == 1)
u8g.drawBox(2 * block_x + 28 , 2 * block_y + 4 , 2 , 2);
}
}
8:計算得分
遍歷整個二維數組,判斷有多少行全為1,然后再將數組中每一行都往下挪多少行
void remove_block()
{
int sum = 0, m, n, i = 0 , h; /*i:需要消除的行數,h:記錄是哪一行需要消除*/
/*判斷有多少行需要消除*/
for ( m = 19 ; m > 4; m--)
{
for ( n = 0 ; n < 10 ; n++)
sum += block[n][m];
if (sum == 10)
{
i++;
score += 10;
h = m;
block_state_down = 1 ;
}
else
sum = 0;
}
/*當存在消行的情況下數組每一行都向下移動i個單位*/
for (i; i > 0; i--)
for ( m = h; m >= 3; m--)
for ( n = 0; n < 10; n++)
block[n][m] = block[n][m - 1];
}
四:結語
這個游戲是在一年前完成的,到今天很多細節忘得差不多了,只能憑借印象來大致的說明一下主要的流程和思路,代碼中有很大一部分重用導致看起來很臃腫現在也懶得改了,有想折騰的可以嘗試完善完善,另外其他的屏幕也是能適用的,只需要更改按鍵控制那個函數和u8glib那個頭文件即可,但是分辨率就沒辦法了
源碼連接,喜歡的還請賞個Star
https://github.com/FanMLei/Arduino_Games
試玩視頻
http://v.youku.com/v_show/id_XMzM5NjA0NjY2OA==.html?spm=a2h3j.8428770.3416059.1
努力成為一名GEEK!
總結
以上是生活随笔為你收集整理的Arduino小游戏集合(俄罗斯方块)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell 获取命令执行结果_java高
- 下一篇: python和php可以一起用吗_Apa