如何在HarmonyOS手機上還原經典遊戲——俄羅斯方塊

2021-01-13 黑蘋果之家

【開發者說欄目】HarmonyOS開發者公眾號一直堅持海納百創的態度,致力於從不同角度,不同方面幫助開發者們更好更快地熟練HarmonyOS相關開發知識,同時為開發者們提供更好的展現自己、充分發揮自己特長的平臺,【開發者說】因此而生。

我們面向所有開發者們徵集HarmonyOS相關的技術洞察或見解,開發過程的心得和開發成果,同時也為大家展示開發者們的開發成果,經驗分享和心得。

本文作者:張詔添,深圳大學-信息與計算科學專業在讀學生

本期我們為大家帶來的是由開發者張詔添投稿的童年經典遊戲在HarmonyOS手機上的開發過程,簡單易上手的小遊戲demo,希望給你的HarmonyOS開發之旅多一點啟發。

俄羅斯方塊,一款經典的小遊戲,相信是很多人童年的回憶。

當然作為開發者而言,不僅要會玩遊戲,同樣要會做遊戲,秉承著這樣的開發理念,張詔添總結了一些開發俄羅斯方塊遊戲的要點訣竅,並在一步步開發中最終實現。

首先讓我們先來了解一下俄羅斯方塊遊戲開發的要點

繪製一些基礎組件:比如遊戲的方陣格局,左右移動,旋轉改變方塊的按鈕,重新開始的按鈕等等;設計不同方塊形狀:設定有7類不同的方塊,形狀如下:

還需根據方塊形狀不同設計不同的方塊變化樣式,並且這些方塊在遊戲中的出現是隨機的;

方塊的下落: 實現方塊的自動向下移動且再次任意一種方塊,當中涉及到時間的設置、方塊下移判斷及判斷方塊不能下移之後的新方塊產生;方塊左右移動:點擊左右移動鍵向相應方向移動一格,當左右有其他方塊或達到邊界時不能進行移動;改變方塊形狀;方塊消除:當有任一行全部方塊填滿時該行消除,該行上述的所有方塊均會向下移動一格;遊戲結束與重新開始:遊戲結束情況判定及頁面設計,重新開始清零啟動。

下面我們就正式進入項目開發環節,來看一下如何逐一攻破以上要點:

創建項目

成功下載安裝DevEco Studio之後,在創建新工程時,選擇Phone選項,選擇默認的模板(java版),將文件命名為不帶中文或特殊字符的項目(如此處的MyPhoneGame2),最後點擊Finish。

左右滑動查看更多

為了保障應用能以「俄羅斯方塊」的名字呈現,我們需要config.json文件中做一些小改動,找到代碼中的「label」:「MyPhoneGame2」,將其修改成"label": "俄羅斯方塊",這樣就可以實現將應用名稱修改為俄羅斯方塊了。

同時,在最下方"launchType":"standard"的後面添加以下代碼,可以實現去掉應用上方的標籤欄:

entry>src>main>config.json "launchType": "standard", "metaData": { "customizeData": [ { "name": "hwc-theme", "value": "androidhwext:style/Theme.Emui.Light.NoTitleBar", "extra": "" } ] } 左右滑動查看更多

繪製基礎組件

在這個要點中我們要繪製一個15*10的方陣和「←」按鈕、「→」按鈕、「變」按鈕、「重新開始」按鈕,方陣和按鈕的代碼在entry>src>main>java>com.example.myphoneapplication>slice>MainAbilitySlice中編寫:

方塊繪製實現

定義方格的邊長length為常量100,方格的間距interval為常量2,,定義一個位置布局layout和一個表示方格顏色的二維數組grids,創建函數initializeinitialize()分別對其初始化,布局layout初始化為線性布局DirectionalLayout,二維數組grids全部賦值為0,在onStart函數中調用函數initializeinitialize(),具體代碼為:

public class MainAbilitySlice extends AbilitySlice { private DirectionalLayout layout; private static final int length=100; private static final int interval=2; private int[][] grids; public void onStart(Intent intent) { super.onStart(intent); initialize(); } public void initialize(){ layout = new DirectionalLayout(this); grids = new int[15][10]; for(int row = 0; row < 15; row++) for(int column = 0; column < 10; column++) grids[row][column] = 0; } 左右滑動查看更多

然後創建函數drawGrids(int[][]grids)用於繪製15*10的方陣:

public void drawGrids(){ layout.setLayoutConfig((new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,ComponentContainer.LayoutConfig.MATCH_PARENT))); Component.DrawTask task=new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.BLACK); RectFloat rect=new RectFloat(30-20,250-20,length*10+interval*9+30+20,length*15+interval*14+250+20); canvas.drawRect(rect,paint); 左右滑動查看更多

因為有七種顏色的方塊,所以分別用0到7代表一種顏色,顏色可以有不同選擇,這裡僅提供一類色系作為參考:

for(int row = 0; row < 15; row++){//0表示灰色,1代表紅色,2代表綠色,3代表藍綠色,4代表品紅色,5代表藍色,6代表白色,7代表黃色 for(int column = 0; column < 10; column++){ if(grids[row][column] == 0) paint.setColor(Color.GRAY); else if(grids[row][column] == 1) paint.setColor(Color.RED); else if(grids[row][column] == 7) paint.setColor(Color.YELLOW); 左右滑動查看更多

四個按鈕創建

創建完方陣後要開始繪製上面的四個按鈕,這裡創建函數drawButton():

public void drawButton(){ ShapeElement background = new ShapeElement(); background.setRgbColor(new RgbColor(174, 158, 143));//按鈕的背景色 background.setCornerRadius(100); 左右滑動查看更多

繪製按鈕涉及創建按鈕變量,按鈕包含的文字信息,文字位置,文字顏色,字號,按鈕在屏幕中顯示的位置,點擊呈現的效果,代碼結構基本一致,只是參數有所變化,這裡就只以向左的「←」按鈕的繪製為例,其餘表示向右的「→」,表示旋轉變化的「變」,表示「重新開始」的按鈕創建方式大家可以在完整代碼中獲取:以向左的「←」按鈕的繪製:

Button button1 = new Button(this); button1.setText("←"); button1.setTextAlignment(TextAlignment.CENTER); button1.setTextColor(Color.WHITE); button1.setTextSize(100); button1.setMarginTop(1800); button1.setMarginLeft(160); button1.setPadding(10,0,10,0); button1.setBackground(background); button1.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { leftShift(); } }); layout.addComponent(button1); 左右滑動查看更多

最後實現的效果為:

最後在initialize()函數中調用drawButton()函數和drawGrids()函數

至此我們完成基本的方陣和按鈕繪製,接下來進入方塊的生成。

隨機產生方塊

這個部分我們要攻破兩個點,一個是如何形成方塊,另一個是如何實現隨機。

在這個應用中,我們將採取常量二維數組來儲存不同顏色的不同形狀所在的位置,比如{{0,3},{0,4},{0,5},{0,6}};代表:

其中{0,3}就表示該方塊的第一個方格在grids[0][3]的位置,{0,4}就表示該方塊的第二個方格在grids[0][4]的位置,以此類推,這樣連起來就可以得到一種顏色的一種形狀的方塊了。

由於這段代碼數量眾多,大家可以在完整代碼中找到,這裡主要講述設置方法。

然後定義各種表示方塊的常量二維數組,定義方塊所佔方格的數量grids_number為常量4,二維數組NowGrids表示當前方塊的形狀,row_number表示方塊的總行數,column_number表示方塊的總列數,Grids表示方塊的顏色,column_start表示方塊第一個方格所在二維數組grids的列數:

private static final int grids_number=4; private int[][] NowGrids; private int row_number; private int column_number; private int Grids; private int column_start; 左右滑動查看更多

接著需要創建函數「create+Color+Grids」為各種顏色各種形狀的方塊賦予對應的NowGrids、row_number、column_numbr、Grids、column_start的值,下面以

為例。

public void createRedGrids1(){ NowGrids=RedGrids1; row_number=2; column_number=3; Grids=1; column_start=3;

接下來解決另一個問題,隨機生成的問題,創建函數createGrids()隨機調用「create+Color+Grids」函數,再將存儲不同顏色的不同形狀的方塊所在的位置賦予對應的Grids值。

最後在initialize()函數中直接調用createGrids()函數。

方塊自動下落

這個部分我們要實現方塊能自動向下移動並且再次產生一種形狀的方塊。

首先需要定義一個時間變量timer,緊接著定義當前下落的行數Nowrow,當前左右移動的列數Nowcolumn,在函數createGrids()中對Nowrow和Nowcolumn賦值為0。

創建函數down()判斷方塊能否再次下移,判斷方法為當方塊下移到下邊界時或方塊下方有其他方塊時,則不能繼續下移了,返回false,否則返回true:

public boolean down(){ boolean k; if(Nowrow + row_number == 15){ return false; } for(int row = 0; row < grids_number; row++){ k = true; for(int i = 0; i < grids_number; i++){ if(NowGrids[row][0] + 1 == NowGrids[i][0] && NowGrids[row][1] == NowGrids[i][1]){ k = false; }} if(k){ if(grids[NowGrids[row][0] + Nowrow + 1][NowGrids[row][1] + Nowcolumn] != 0) return false; } } return true; } 左右滑動查看更多

創建函數run(),初始化timer,增加時間事件,判斷當方塊能繼續下移時則清除當前方塊,Nowrow加1,再在下一格的位置繪製剛才的方塊,實現方塊的下移,當方塊不能下移時則產生新的方塊。

public void run(){ timer=new Timer(); timer.schedule(new TimerTask() { @Override public void run() { getUITaskDispatcher().asyncDispatch(()->{ if(down()){ for(int row = 0; row < grids_number; row++){ grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] = 0; } Nowrow++; for(int row = 0; row < grids_number; row++){ grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] = Grids; } } else{ createGrids(); } drawGrids(); }); } },0,750); } 左右滑動查看更多

最後在函數onStart(Intent intent)中調用函數run()

最終實現效果如下:

方塊左右移動

通過點擊 「←」或「→」方塊來控制方向朝相應方向移動的效果。

由於向左向右的代碼結構類似,這裡我們都以左移作為示例:

首先我們需要創建函數left()判斷方塊能否再次左移,判斷方法為當方塊左移到左邊界時或方塊左方有其他方塊時,則不能繼續左移了,返回false,否則返回true

然後創建函數leftShift(),判斷當方塊能繼續左移時則清除當前方塊,Nowcolumn減1,再在左一格的位置繪製剛才的方塊,實現方塊的左移,可以參考以下代碼:

public void leftShift(){ if(left()){ for(int row = 0; row < grids_number; row++){ grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] = 0; } Nowcolumn--; for(int row = 0; row < grids_number; row++){ grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] = Grids; } } drawGrids(); } 左右滑動查看更多

最後在函數drawButton()中的"←"按鈕和"→"按鈕增加點擊事件,分別調用上述的函數。

改變方塊形狀

這個部分主要實現點擊「變」將會切換成該方塊其他形狀的效果。

首先創建函數"chang+Color+Grids"用於調用新方塊的"create+Color+Grids"函數,實現在同一種顏色的方塊中變換到其他形狀的方塊,小正方形的方塊不需要實現這種變化。

然後創建函數changGrids()用於判斷當前方塊的顏色,接著調用對應的改變方塊形狀的"chang+Color+Grids"函數

最後在函數drawButton()中的"變"按鈕增加點擊事件,調用函數changGrids()。

方塊消除

當有任一行全部填滿方塊時該行便會消除,該行上述的所有方塊均會向下移動一格

首先創建函數eliminateGrids()用於判斷是否有任一行全部填滿方塊,當存在時則消除該行,並且該行上述的所有方塊均會向下移動一格:

public void eliminateGrids() { boolean k; for (int row = 14; row >= 0; row--) { k = true; for (int column = 0; column < 10; column++) { if (grids[row][column] == 0) k = false; } if (k) { for (int i = row - 1; i >= 0; i--) { for (int j = 0; j < 10; j++) { grids[i + 1][j] = grids[i][j]; } } for (int n = 0; n < 10; n++) { grids[0][n] = 0; } } } drawGrids(); } 左右滑動查看更多

最後在函數createGrids()中調用函數eliminateGrids()

實現效果如下:

遊戲結束與重新開始

關於遊戲結束其實需要操刀兩部分事情,一個是遊戲結束的文本,一個是如何判定遊戲結束。

創建函數drawText()用於繪製遊戲結束文本,這個部分比較簡單,只需在頁面上創建文本即可。

那麼進入下一步,如何判斷遊戲是否結束,答案是判斷能否再次產生新的方塊。

因此我們需要創建函數gameover()用於判斷能否再次產生新的方塊,判斷方法為當產生新的方塊原有的位置存在不為0的數字則無法產生新的方塊,返回true

public boolean gameover(){ for(int row = 0; row < grids_number; row++){ if(grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] != 0){ return true; } } return false; } 左右滑動查看更多

再在函數createGrids()中增加判斷,當遊戲未有結束時繼續產生新的方塊,當遊戲結束時停止時間和調用函數drawText()用於顯示遊戲結束文本:

public void createGrids(){//部分代碼沒有貼出,歡迎自行下載附件查看原始碼 if(gameover() == false){ for(int row = 0; row < grids_number; row++){ grids[NowGrids[row][0] + Nowrow][NowGrids[row][1] + Nowcolumn] = Grids; } } else{ timer.cancel(); drawText(); } } 左右滑動查看更多

實現如下效果:

最後在函數drawButton()中的"重新開始"按鈕增加點擊事件,調用函數initialize()和函數run()。

到此,我們已經完成了俄羅斯方塊手機應用的開發啦!

回顧整個開發過程,難點在於用於遊戲的不同俄羅斯方塊的繪製生成,系統如何隨機產生方塊,如何判定方塊下落的位置,實現消除等幾個方面,但實現並不困難。

相關焦點

  • 經典遊戲《俄羅斯方塊》變身桌遊
    【中外玩具網 · 潮流新品】經久不衰的經典遊戲《俄羅斯方塊》是我們最熟悉和喜愛的小遊戲之一。日前,英國玩具商——傳統的棋盤公司John Adams將其變成了雙人桌面棋盤遊戲並有望在今年內發售。  這款名為《俄羅斯方塊連接(Tetris Link)》的雙人桌遊規則與我們平時玩的《俄羅斯方塊》不太一樣。
  • 漢字版俄羅斯方塊是什麼遊戲 方塊上的字組成一個字
    漢字版俄羅斯方塊是什麼遊戲 方塊上的字組成一個字 漢字版俄羅斯方塊是什麼遊戲?
  • 俄羅斯方塊經典如何誕生 Tetris的起源
    《俄羅斯方塊》原本是前蘇聯科學家阿列克謝·帕基特諾夫在1984年6月利用空閒時間所編寫的遊戲程序,據說遊戲的作者最喜歡網球(Tennis) 運動,於是
  • 經典遊戲《俄羅斯方塊》36年成長進化史
    經典遊戲《俄羅斯方塊》36年成長進化史 2020-03-05作者:angle307來源:網絡 從1984年誕生,到2020年,36年期間,《俄羅斯方塊》收穫了無數玩家
  • 這個公寓樓酷似經典遊戲俄羅斯方塊
    俄羅斯有這樣一個方塊公寓,作為一個社交住宅,它的外觀酷似俄羅斯方塊。顏色搭配看起來完全就是經典的俄羅斯方塊遊戲啊。據悉,這套俄羅斯方塊公寓高4層,擁有650套房間。每間公寓均享有朝向自己陽臺的獨特景致,同時兼具私密性。
  • 俄羅斯方塊知多少?經典遊戲背後啟示多
    FC遊戲數千種,再忠實的FC發燒友,也不能玩遍全部。只因每個人的興趣點不同,或專注RPG類,或喜好射擊飛行類,或獨愛回合戰棋類。然而,一些小遊戲,如FC俄羅斯方塊,人人都玩過,不分玩家偏好,以其獨特的風格,成為經典。
  • 【遊俠導讀】全新製作設計的經典遊戲《俄羅斯方塊》,現在與EA一同...
    全新製作設計的經典遊戲《俄羅斯方塊》,現在與EA一同來到了玩家面前。不一樣的玩法,將會給玩家來帶不一樣的俄羅斯方塊體驗。  此次EA重新製作設計的《俄羅斯方塊》,在畫面上與之前同樣是EA所推出的俄羅斯方塊相比,有著很大的變化。
  • 當之無愧的經典 正版《俄羅斯方塊》手遊預約開啟
    曾創下9項世界紀錄,最多平臺上運行的遊戲,被移植次數最多的遊戲,遊戲史上系列銷量最高等光輝頭銜的《俄羅斯方塊》已來到中國,這款幾乎存在於所有人童年的遊戲被定名《俄羅斯方塊環遊記》,並將於1月10日開啟首次安卓測試,TAPTAP預約現已開啟,想體驗這款經典遊戲的玩家,現在就可以前往TAPTAP搜索「俄羅斯方塊
  • 國內正版授權《俄羅斯方塊》手遊今日限量測試
    還原經典,爽快競技,36年經典IP俄羅斯方塊正版手遊來了!作為中國正版TETRIS手遊,《俄羅斯方塊環遊記》即將於3月24日迎來啟程限號測試。享譽全球的經典IP,終於以正版的名義帶來經典消除玩法,同時全新賦能,以更優質的畫面表現,打造全新競技對抗、全新闖關模式等遊戲體驗。遊戲自曝光以來便備受玩家期待,如今,《俄羅斯方塊環遊記》啟程測試即將拉開大幕,期待更多玩家前來感受。
  • 俄羅斯方塊_俄羅斯方塊新聞_3DM新聞
    經典遊戲《俄羅斯方塊》將登陸PS4與Xbox One平臺  在遊戲市場如此發達的今天,要找一款滿足不同玩家需求的遊戲還是非常容易。
  • EA的手機版《俄羅斯方塊》涼了
    隨著數字遊戲大行其道,關於數字遊戲的所有權/使用權的爭論和擔心已經開始應驗了,用戶買到的只是使用授權,說不定哪天就會失效。曾經的實體遊戲其實也是使用授權,但廠商方面是不能反悔的,只要斷開網絡就必然能夠離線使用光碟中的內容。
  • EA推出免費版手機遊戲《俄羅斯方塊》
    雖然目前EA公司在移動領域內的實力無法與像Gameloft這樣的老牌公司相抗衡,但EA移動部門似乎正通過一系列遊戲的推出來提高公司在移動領域內的表現力以及擴大公司的移動用戶群。  繼推出免費版本的Scrabble《拼字遊戲》後,EA於近日又推出了一款免費版本的遊戲Tetris《俄羅斯方塊》。
  • 永無止境的俄羅斯方塊
    當然就得依靠天分極高、玩心也盛的程式設計師們自己編寫的各種小程序了,既然如此,某些小程序同時又表現出一定的遊戲性,也就不足為奇了。4月份新電腦剛入手,5月份,帕基特諾夫就開始將自己最心愛的多格骨牌遊戲往電腦上搬了。當時,花上1盧布,就能在商店裡買到3副五格骨牌。不過,12種組合旋轉起來還是有點太複雜了,那麼,如何在保證趣味性的前提下刪繁就簡呢?
  • 俄羅斯方塊懷舊版下載_俄羅斯方塊懷舊版手機版下載【官方安卓版...
    俄羅斯方塊懷舊版 休閒益智 大小: 0.35M
  • 經典遊戲《俄羅斯方塊》中每種方塊出現的概率是否相等?
    最後發現壘得太高了的時候不得不改變策略,用其他方塊來填充,但一個運氣不好就被活活拖死了?因此,你問我方塊出現的概率是不是相等,絕對不是。至少當年我們玩到的紅白機就不是這麼出的。另外,紅白機上面出現的方塊全都是固定出現的,小編嘗試使用1P和2P同時進行,出現的方塊完全是一模一樣的。
  • 遊戲史上最成功遊戲排名:第三名俄羅斯方塊背後的故事
    近日遊戲雜誌Game Informer為慶祝雜誌發布的第300期,列出了遊戲史上最成功的300款遊戲,其中不乏上世紀的經典街機遊戲,也有當下熱門的單機遊戲。(文末附上300款最成功遊戲的完整排行榜~)排名前三的分別是《塞爾達傳說:眾神的三角力量》、《超級馬裡奧兄弟3》、《俄羅斯方塊》,這些遊戲都是童年的回憶了,但是遊戲背後的故事卻是鮮為人知,今天就來講講排名第三的《俄羅斯方塊》背後的故事吧~上圖是高級玩家Neubauer不到兩分鐘就打破30萬分的世界紀錄!
  • 趣羅斯:不朽的經典 – 俄羅斯方塊
    1984年6月6日,蘇聯科學院院士阿列克謝·帕基特諾夫(Алексей Пажитнов)利用工餘時間編出一個遊戲程序,用來測試計算機性能。他從拼圖中獲得靈感,製作出後來聲名大噪的俄羅斯方塊。關於俄羅斯方塊的趣味事實從未叫過它的「真名」俄羅斯方塊並不是遊戲名稱,而遊戲名稱本身沒有實際意思。
  • 《俄羅斯方塊》手遊開啟限量測試 經典IP正版授權
    俄羅斯方塊想必是不少玩家的童年了,作為聞名全球的一個經典IP,多少年少時光都沉浸在了那個熟悉的方塊世界中。現在就有一款正版授權的《俄羅斯方塊》手遊——《俄羅斯方塊環遊記》於3月24日開啟限量測試。根據官方介紹,《俄羅斯方塊環遊記》是國內首款獲得TETRIS公司正版授權的俄羅斯方塊手遊,延續了大家所熟知的經典消除玩法,玩家將可以再次重溫旋轉移動下落消除一整行或者多行的快樂。除了經典的規則玩法,遊戲還加入了儲存方塊、T旋轉等諸多新規則以及對戰模式、馬拉松模式等新模式。
  • 俄羅斯方塊 iPhone遊戲tetris blitz
    《俄羅斯方塊》各位用戶一定知道,今天小編在iTunes上找到一款科技感十足的的俄羅斯方塊遊戲。該款遊戲名為tetris blitz,在玩法上與傳統的俄羅斯有一定的差別。那麼這款遊戲表現怎樣呢?一起來看看吧!
  • 《Slidey: Block Puzzle》評測:另類的俄羅斯方塊
    [摘要]俄羅斯方塊是每個人都熟悉的遊戲,而今天小編將為大家帶來一款不能變形的「俄羅斯方塊」!神奇的巫師呀,快來用消除拯救精靈們吧!【騰訊遊戲頻道出品,轉載請註明!】說起俄羅斯方塊,想必大夥都不會感到陌生。因為它不僅創造了9 項金氏世界紀錄,而且不經意間已經陪伴我們玩家走過了30多年的歷程,簡直可以用「一直被模仿,從未被超越」來形容。不過即便如此,依舊有不少的遊戲開發商以它作為創作的靈感,通過自己的腦洞,以及新鮮元素的加入,讓這種另類的俄羅斯方塊,玩起來獨具特色。