国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

2020征文-開發(fā)板鴻蒙Hi3861之俄羅斯方塊小游戲(附源碼)

開發(fā)
文章由鴻蒙社區(qū)產(chǎn)出,想要了解更多內(nèi)容請前往:51CTO和華為官方戰(zhàn)略合作共建的鴻蒙技術(shù)社區(qū)https://harmonyos.51cto.com/#zz

[[357128]]

想了解更多內(nèi)容,請?jiān)L問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com/#zz

一、原理

俄羅斯方塊相信大家都玩過,首先把場景分成可移動(dòng)部分、和固定部分;


  1. unsigned short data_blk[16]; //游戲固定部分  
  2. unsigned short data_act[4]; //游戲移動(dòng)部分  
  3. unsigned char display_blk_data[53] = {0x40,0xff,0x55}; //游戲場景部分用于顯示  
  4. unsigned char display_nst_data[17] = {0x40}; //游戲顯示將出場的下一個(gè)方塊  
  5. unsigned char data_nst; //下一個(gè)方塊的內(nèi)容  
  6. unsigned int score = 0; //得分  
  7. unsigned int delay = 100000; //下降延時(shí)控制速度  
  8. char row_act = -1; //活動(dòng)方塊所在行數(shù)  
  9. hi_i2c_data display_blk; //用于顯示  
  10. hi_i2c_data display_nst; //用于顯示 

 固定場景部分大小為16x12, 用16個(gè)無符號short(16位)型表示,僅用到低12位;

可移動(dòng)部分大小為4x12, 用4個(gè)無符號short(16位)型表示,僅用到低12位;

所有的方塊(19種)有預(yù)定義為block[19][4],下一個(gè)預(yù)告用一個(gè)無符號char型(0-18)表示19個(gè)其中的一個(gè);

通過row_act(活動(dòng)方塊所在行數(shù))控制活動(dòng)方塊向下移動(dòng)。

二、顯示

  1. void display(void) 
  2.     //show the canvas 
  3.     unsigned short temp
  4.     for(unsigned char i=0;i<8;++i) 
  5.     { 
  6.         for(unsigned char j=0;j<12;++j) 
  7.         { 
  8.             for(unsigned char k=0;k<4;++k) 
  9.             { 
  10.                 display_blk_data[3+j*4+k] = 0x00; 
  11.                 temp = i*2>=row_act && i*2<row_act+4 ? data_blk[i*2]|data_act[i*2-row_act] : data_blk[i*2]; 
  12.                 display_blk_data[3+j*4+k] |= temp&1<<j ? img[k] : 0x00; 
  13.                 temp = i*2+1>=row_act && i*2<row_act+3 ? data_blk[i*2+1]|data_act[i*2+1-row_act] : data_blk[i*2+1]; 
  14.                 display_blk_data[3+j*4+k] |= temp&1<<j ? img[k]<<4 : 0x00; 
  15.             } 
  16.         } 
  17.         oled_write_data(0, i, &display_blk); 
  18.     } 
  19.     //show the nest block 
  20.     for(unsigned char i=0;i<2;++i) 
  21.     { 
  22.         for(unsigned char j=0;j<4;++j) 
  23.         { 
  24.             for(unsigned char k=0;k<4;++k) 
  25.             { 
  26.                 display_nst_data[j*4+k+1] = 0; 
  27.                 display_nst_data[j*4+k+1] |= block[data_nst][i*2]&0x10<<j ? img[k] : 0x00; 
  28.                 display_nst_data[j*4+k+1] |= block[data_nst][i*2+1]&0x10<<j ? img[k]<<4 : 0x00; 
  29.             } 
  30.         } 
  31.         oled_write_data(64, i+1, &display_nst); 
  32.     } 
  33.     //show the score 
  34.     oled_write_num(64, 7, score, 0); 

 顯示函數(shù)由三部分組成:游戲場景、下一塊預(yù)告、分?jǐn)?shù);

重點(diǎn)介紹一下游戲場景部分:

最外層i循環(huán)共8次,每次顯示16行中的兩行;

第二層j循環(huán)共12次,每次處理一行中的一個(gè)像素;

第三層k循環(huán)把第個(gè)游戲像素?fù)Q算成用于顯示的4x4個(gè)像素

  1. temp = i*2>=row_act && i*2<row_act+4 ? data_blk[i*2]|data_act[i*2-row_act] : data_blk[i*2]; 

 temp = 行數(shù)遇到可移動(dòng)部分 ? 背景+前景 : 背景;

  1. display_blk_data[3+j*4+k] |= temp&1<<j ? img[k] : 0x00; 

用于顯示的像素?cái)?shù)據(jù) |= 顯性像素? img中的一列 : 不顯示;

下一塊預(yù)告部分與上面類似,相信能舉一反三的理解一下;

再簡單介紹一下顯示分?jǐn)?shù)的部分“void oled_write_num(hi_u8 x, hi_u8 y, unsigned int n, hi_bool zero)"

x y 是要顯示的數(shù)值所在的坐標(biāo),n是要顯示的數(shù)值,zero是否顯示前面的0;

  1. void oled_write_num(hi_u8 x, hi_u8 y, unsigned int n, hi_bool zero)  
  2.  
  3. unsigned int number = n;  
  4. unsigned char str_num[9];  
  5. for(unsigned char i=0;i<8;++i) 
  6.  
  7.  
  8. str_num[7-i] = num[number%10];  
  9. number /= 10;  
  10.  
  11. str_num[8] = 0;  
  12. if(zero) 
  13.  
  14.  
  15. oled_write_string_57(x, y, (hi_u8 *)str_num);  
  16.  
  17. else 
  18.  
  19.  
  20. hi_u8 *p = str_num;  
  21. for(;*p=='0';++p);  
  22. oled_write_string_57(x, y, p);  
  23.  

 這部分比較簡單相信大家都能理解,把int型按位轉(zhuǎn)換成字符串顯示,

如果去除前面的0直接將字符串的起始地址向后移動(dòng),直到有非0數(shù)字。

如果想仔細(xì)研究顯示原理請下載附件顯示驅(qū)動(dòng)芯片數(shù)據(jù)手冊

三、方塊移動(dòng)

  1. void block_left(void)  
  2.  
  3. //限制移動(dòng)代碼  
  4. //move to right on screen left  
  5. for(unsigned char i=0;i<4;++i) 
  6.  
  7.  
  8. data_act[i]>>=1;  
  9.  

 直接把活動(dòng)方塊進(jìn)行移動(dòng)操作即可,左右原理一樣;

就這么簡單? 當(dāng)然不是!

在移動(dòng)前還要加一些限制:到邊界了不能再移動(dòng)、有固定方塊阻擋不能移動(dòng)

下面就是限制移動(dòng)代碼,如果觸發(fā)限制移動(dòng)條件,直接返回,不進(jìn)行移動(dòng)操作

  1. //if close to edge give up move  
  2. for(unsigned char i=0;i<4;++i) 
  3.  
  4.  
  5. if(data_act[i]&0x0001)  
  6.  
  7. return 
  8.  
  9. if((data_act[i]>>1) & data_blk[row_act+i])  
  10.  
  11. return 
  12.  

 這個(gè)最燒腦的就是方塊的旋轉(zhuǎn)了,發(fā)視頻前就差旋轉(zhuǎn)函數(shù)沒有寫了,直到昨天才調(diào)到合適,

先看一下基礎(chǔ)代碼: 

  1. static void block_turn(char* arg) 
  2.  
  3.  
  4. (void)arg; 
  5.  
  6. unsigned short turned[4]={0, 0, 0, 0}; 
  7.  
  8. unsigned char i; 
  9.  
  10. for(i=0;i<12;++i) 
  11.  
  12.  
  13.  
  14.  
  15. break; 
  16.  
  17.  
  18.  
  19. for(unsigned char j=0;j<4;++j) 
  20.  
  21.  
  22. for(unsigned char k=0;k<4;++k) 
  23.  
  24.  
  25. turned[3-j] |= data_act[k]&1<<(i+j) ? 1<<(i+k) : 0; 
  26.  
  27.  
  28.  
  29. for(unsigned char j=0;j<4;++j) 
  30.  
  31.  
  32. data_act[j] = turned[j]; 
  33.  
  34.  

 首先是聲明一個(gè)"turned[4]"用于存放旋轉(zhuǎn)后的方塊,為什么不直接在原圖旋轉(zhuǎn)呢?

第一個(gè)循環(huán)從低到高到位掃描找到方塊所在列,

第二個(gè)循環(huán)從找到方塊的列取4X4進(jìn)行行列轉(zhuǎn)置,

第三個(gè)循環(huán)把旋轉(zhuǎn)后的方塊更新到當(dāng)前活動(dòng)方塊。


重點(diǎn):前面講了這是一個(gè)基礎(chǔ)代碼,功能實(shí)現(xiàn)了,但有一個(gè)問題不得不考慮:旋轉(zhuǎn)后干涉嗎?干涉怎么辦?

解析:除了上面不會(huì)干涉,下左右都可能因?yàn)樾D(zhuǎn)干涉,干涉我就不轉(zhuǎn)了唄。

如圖旋轉(zhuǎn)會(huì)造成方塊下移:

  1. for(unsigned char j=0;turned[0]==0&&j<2;++j) 
  2.    { 
  3.        turned[0] = turned[1]; 
  4.        turned[1] = turned[2]; 
  5.        turned[2] = turned[3]; 
  6.        turned[3] = 0; 
  7.    } 

 如果己經(jīng)在邊上了,可能會(huì)造成出界:


  1. for(;turned[0]&1<<12 || turned[1]&1<<12 || turned[2]&1<<12 || turned[3]&1<<12;) 
  2.    { 
  3.        for(unsigned char j=0;j<4;++j) 
  4.        { 
  5.            turned[j] >>= 1; 
  6.        }    
  7.    } 

 因?yàn)槭亲髮R的,所以左邊不會(huì)存在這個(gè)情況,且只有右邊有富裕空間剛好利用一下。

最近再檢測一下是否與固定方塊干涉:

  1. for(unsigned j=0;j<4;++j) 
  2.     if(turned[j] & data_blk[row_act+j]) 
  3.     { 
  4.         return
  5.     } 

 以上條件都滿足了,才能執(zhí)行最后的更新到當(dāng)前活動(dòng)方塊,否則放棄旋轉(zhuǎn)。

這也是為什么要事先聲明一個(gè)“turned[4]“,如果在原圖旋轉(zhuǎn)萬一干涉了還要轉(zhuǎn)回去!

四、按鍵的實(shí)現(xiàn)(重點(diǎn))

按鍵用到了兩個(gè)接口分別是GPIO5和GPIO8,

  1. void init_key(void) 
  2.  
  3.  
  4. GpioInit(); 
  5.  
  6. IoSetFunc(WIFI_IOT_IO_NAME_GPIO_5, WIFI_IOT_IO_FUNC_GPIO_5_GPIO); 
  7.  
  8. GpioSetDir(WIFI_IOT_IO_NAME_GPIO_5, WIFI_IOT_GPIO_DIR_IN); 
  9.  
  10. IoSetPull(WIFI_IOT_IO_NAME_GPIO_5, WIFI_IOT_IO_PULL_NONE); 
  11.  
  12. GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_5, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, key_press, NULL); 
  13.  
  14. IoSetFunc(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_IO_FUNC_GPIO_8_GPIO); 
  15.  
  16. GpioSetDir(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_GPIO_DIR_IN); 
  17.  
  18. IoSetPull(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_IO_PULL_UP); 
  19.  
  20. GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, block_turn, NULL); 
  21.  

 這兩個(gè)接口還是有區(qū)別的,5#口上接了三個(gè)按鍵,8#口上一個(gè)按鍵,分別指定了中斷服務(wù)函數(shù):

8#比較簡單檢測到下降沿進(jìn)行中斷服務(wù)程序(方塊旋轉(zhuǎn))即前面講到的“block_turn()”;

5#稍復(fù)雜一點(diǎn),進(jìn)行中斷服務(wù)程序后再進(jìn)行AD轉(zhuǎn)換,通過AD轉(zhuǎn)換檢出是哪一個(gè)按鍵被按下,再進(jìn)行不同的操作


當(dāng)不同的按鍵按下時(shí),會(huì)通過AD檢測到不同的采樣值,可以通過計(jì)算得到,也可以通過實(shí)際采集得到:

讀取端口的模擬量值:

  1. hi_u16 read_key(void) 
  2.     hi_u16 data=0; 
  3.     hi_adc_read(HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 10); 
  4.     return data; 

 用到了自帶的“hi_adc_read”,參數(shù)分別是(要讀取的端口、接收數(shù)據(jù)的變量、取N次采樣平均結(jié)果、基準(zhǔn)電壓、采樣間隔)

這里讀的是端口2(見原理圖)取4次平均值,自動(dòng)基準(zhǔn)電壓,10us間隔,

可以是方法還沒有完全掌握,更改基準(zhǔn)電壓沒有影響檢測值,而且當(dāng)沒有按鍵按下時(shí)應(yīng)該讀到3.3V的電壓,卻只讀到了1.8V的電壓。

后面再仔細(xì)研究后更新一下。

這里提供計(jì)算方法供參考:

當(dāng)S1按下 采集電壓 = 3.3 * 1 / (1+4.7) = 0.578947368V

采集到的值 = 4096 * 1 / (1+4.7) = 718

當(dāng)S2按下 采集電壓 = 3.3 * (1+1) / (1+1+4.7) = 0.985074627

采集到的值 = 4096 * (1+1) / (1+1+4.7) = 1223

以下參考值來源實(shí)際采集!

  1. static void key_press(char* arg) 
  2.     (void)arg; 
  3.     unsigned int ret = read_key(); 
  4.     usleep(500); 
  5.     if (abs(ret - read_key()) > 30) 
  6.     { 
  7.         return
  8.     } 
  9.     if(ret>300 && ret<360) 
  10.     { 
  11.         block_left(); 
  12.         return
  13.     } 
  14.     if(ret>530 && ret<590) 
  15.     { 
  16.         block_right(); 
  17.         return
  18.     } 

 五、自然下降

向下移動(dòng)就簡單多了,直接進(jìn)行++就OK了。

  1. row_act++; 

但是在加之前也有附加條件,是不是到底了?到底了是不是有滿足消除條件的行了?會(huì)不會(huì)已經(jīng)到頂行了?

  1. char flag = 0; 
  2.    for(unsigned char i=0;i<4;++i) 
  3.    { 
  4.        if(data_blk[row_act+i+1] & data_act[i]) 
  5.        { 
  6.            flag = 1; 
  7.            break; 
  8.        } 
  9.    } 
  10.    if(flag || (row_act>11 && data_act[15-row_act]!=0)) 
  11.    { 
  12.        for(unsigned char i=0;i<4;++i) 
  13.        { 
  14.            data_blk[row_act+i] |= data_act[i]; 
  15.            data_act[i] = block[data_nst][i]; 
  16.        } 
  17.        remove_full(); 
  18.        row_act = -1; 
  19.        data_nst = get_next(); 
  20.        //Game over 
  21.        if(data_blk[0]) 
  22.        { 
  23.            oled_write_string_16(20, 3, (hi_u8 *)"Game over!"); 
  24.            while(1) 
  25.            { 
  26.                usleep(5000); 
  27.            } 
  28.        } 
  29.    } 

 如果到底了(不管是到游戲場景的底部,還是遇到固定的方塊)當(dāng)前活動(dòng)方法結(jié)束

當(dāng)前活動(dòng)劃到固定方塊,重新在頂部生成新的方塊;

一個(gè)方塊落定后要判斷是否有滿足可消除的行,如果有消除;

如果最頂行都被固定方塊填充的時(shí)候判定“Game over!”。

如果有人還沒有配置好開發(fā)環(huán)境,也可以下載我編譯好的,直接用HiBurn燒進(jìn)行去可以玩了! 

想了解更多內(nèi)容,請?jiān)L問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com/#zz 

 

責(zé)任編輯:jianghua 來源: 鴻蒙社區(qū)
相關(guān)推薦

2020-12-17 10:02:16

鴻蒙Hi3861開發(fā)板

2021-01-12 12:16:55

鴻蒙HarmonyOS游戲

2015-01-22 15:36:46

游戲源碼

2011-06-13 18:21:12

2014-10-08 10:04:14

代碼解釋俄羅斯方塊

2020-12-15 11:57:49

Hi3861 HarmonyOS開發(fā)板

2023-09-25 12:35:27

Python

2020-12-29 09:59:01

鴻蒙HarmonyOS智能家居

2014-05-26 10:07:18

Javascript俄羅斯方塊

2020-12-16 10:05:48

鴻蒙開發(fā)板Onenet平臺

2015-04-28 09:21:28

JSJS俄羅斯方塊游戲帝國

2020-05-19 17:26:21

Python俄羅斯方塊游戲開發(fā)

2020-02-27 13:43:14

Emacs俄羅斯方塊應(yīng)用

2021-12-29 11:56:16

Linux俄羅斯方塊

2020-11-06 10:15:16

HiBurn

2023-09-26 08:51:29

PygamePython語言

2011-11-17 16:14:25

Jscex

2023-10-17 10:20:53

VueReact

2020-10-14 09:37:03

HiBurn鴻蒙.bin文件

2016-06-13 10:21:49

二維碼條形碼二進(jìn)制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

亚洲午夜精品国产| 精品欧美一区二区三区在线观看 | 黄色成人精品网站| www.色在线| 亚洲成人男人天堂| 成人白浆超碰人人人人| 国产三级精品网站| 欧美不卡视频一区发布| 国产女人在线视频| 日本一区二区动态图| 亚洲欧洲精品一区| 欧美一级精品片在线看| 伊人伊成久久人综合网小说| 国产精品一卡二卡三卡| 国产毛片久久久| 日韩欧美色综合| 亚洲大胆精品| 亚洲精品久久久蜜桃| 日本精品裸体写真集在线观看| 久久99蜜桃精品| 国产毛片精品视频| 在线播放中文一区| 久久免费视频3| 777电影在线观看| 国产欧美一区在线| 最近2019中文免费高清视频观看www99| 日韩av卡一卡二| 免费黄网站在线| 蜜臀av一区二区在线免费观看| 日韩精品在线私人| 国产乱xxⅹxx国语对白| 成av人片一区二区| 日本久久亚洲电影| 亚洲一区二区蜜桃| 国产九九在线视频| 在这里有精品| 不卡毛片在线看| 亚洲欧洲三级| 中文字幕一区免费| 蜜桃视频m3u8在线观看| 琪琪一区二区三区| 国产精品亚洲一区二区三区妖精| 久久久国产精品x99av| 激情视频免费网站| 日韩国产欧美一区二区| 日韩av电影国产| 中文字幕在线视频网站| 欧美日韩蜜桃| 日本伊人精品一区二区三区介绍 | 亚洲熟妇无码另类久久久| 日韩欧美亚洲一区二区| 日韩av一区二区三区| 久久一卡二卡| 亚洲色成人www永久在线观看| 一区二区三区黄色| 久久久久国产免费免费| 成人午夜精品| 色狠狠久久aa北条麻妃| 亚洲天堂av资源在线观看| 午夜精品久久久久久久男人的天堂 | 91精品精品| 国产成人精品一区二区三区| 蜜桃视频成人m3u8| 欧美日韩大陆在线| 欧美xxxx免费虐| 久久在线视频在线| 欧美韩日亚洲| 久久99久久亚洲国产| 香蕉一区二区| 成人网站免费观看入口| 精品国产aⅴ麻豆| 2019中文在线观看| 日韩av在线看| jizz一区二区| 中文字幕在线直播| 国产精品亚洲天堂| 亚洲一区二区黄| 亚洲一卡二卡三卡四卡五卡| 日韩丝袜视频| 欧美女同网站| 欧美男人的天堂| 久久久久久网址| 91国内揄拍国内精品对白| 欧美美女直播网站| 日韩久久一区二区| 亚洲天天做日日做天天谢日日欢| 亚洲尤物av| 国产精品高清乱码在线观看| 最新在线你懂的| **亚洲第一综合导航网站| xvideos.蜜桃一区二区| 男女猛烈激情xx00免费视频| 日韩精品一区二区三区色偷偷| 日韩精品免费观看视频| 亚洲永久免费观看| 亚洲国内精品在线| 精品久久久91| 69视频在线播放| 国产精品精品久久久久久| 国产av熟女一区二区三区| 91久久精品国产91久久性色tv| 午夜精品久久久久久久男人的天堂| 精品中文视频在线| 亲子乱一区二区三区电影| 亚洲日本免费电影| 国产激情美女久久久久久吹潮| 国产精品久久久久久久久久久久久| 先锋影音欧美| 日韩精品伦理第一区| 色播视频在线观看| bbw在线视频| 伪装者免费全集在线观看| 亚洲高清999| 末成年女av片一区二区下载| 国产九一视频| 99热99在线| 欧美少妇一区二区三区| 欧美成人精品一区| 亚洲激情六月丁香| 色呦呦网站入口| 国精品一区二区| 欧美精品一区二区三区视频| 国产精品久久久久久久久久新婚| 久久夜精品va视频免费观看| 精品欧美不卡一区二区在线观看 | 久久久久久久久久久亚洲| 午夜视频在线免费| 亚洲国产成人精品电影| 一级片免费看| 99riav久久精品riav| 高清日韩欧美| 国产免费成人| yellow视频在线观看一区二区 | 国产精品白丝jk白祙喷水网站| 国产精品爽黄69天堂a| 久操成人av| 国产视频在线观看一区| 欧美第十八页| 国产一区欧美二区三区| 视频在线在亚洲| 一区二区精品在线观看| 久久女同互慰一区二区三区| 在线观看成人免费| 日韩精品欧美| 国产一区高清视频| 热久久一区二区| 天堂av一区二区| 欧美激情日韩| 日本欧美色综合网站免费| 中文字幕一区二区在线观看| 福利精品一区| 精品国产一区二区三区久久久狼| 国产视频一区免费看| 99久久国产综合精品五月天喷水| 亚洲视频第一页| 中文字幕中文字幕在线一区| 欧美性videosxxxxx| 欧美一级视频精品观看| 国产有码一区二区| 成人h视频在线观看播放| 久久综合给合久久狠狠色| 欧美日韩一区在线播放| 国产欧美在线播放| 91人成网站www| 久久精品国产一区| 亚洲激情在线观看视频免费| 日韩高清有码在线| 麻豆av一区二区三区久久| 日本免费视频在线观看| 成年人福利视频| 精品久久久亚洲| 粉嫩av一区二区三区免费野| 国产女主播一区二区| 美女网站视频在线| 99精品久久免费看蜜臀剧情介绍| 久久久久五月天| 先锋av资源在线| 免费国产亚洲视频| 久久久久www| 在线看av的网址| 91麻豆精品视频| 久久久综合亚洲91久久98| 欧美激情第六页| 激情小说激情视频| 亚洲欧美国内爽妇网| 国产精品白丝jk白祙喷水网站| 亚洲国产一区二区a毛片| 欧美精品久久久| 亚洲色图欧美偷拍| 日韩精品在线看片z| 国产一区二区高清在线| 一级特黄特色的免费大片| 亚洲午夜精品一区二区三区| 97久久伊人激情网| 亚洲国产精品久久久久秋霞蜜臀 | 国产成人精品免费久久久久| 日韩欧美亚洲国产精品字幕久久久 | www.亚洲男人天堂| 91福利小视频| 国产精品乱码一区二区三区软件 |