【开发者说栏目】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 = 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()。
到此,我们已经完成了俄罗斯方块手机应用的开发啦!
回顾整个开发过程,难点在于用于游戏的不同俄罗斯方块的绘制生成,系统如何随机产生方块,如何判定方块下落的位置,实现消除等几个方面,但实现并不困难。
相信大家看完内容之后已经跃跃欲试,同时对于完整代码也充满期待,我们将在【阅读原文】中为你带来完整的代码,欢迎大家查看下载。
同时也欢迎更多开发者们与我们共享开发成果,分享技术解读与经验心得!
【声明】本文内容由原作者提供,HarmonyOS开发者【开发者说】栏目首发,文章技术实现内容及源码信息仅代表原作者观点。
END
●扫码关注欢迎留言投稿●
投稿邮箱:harmonysupport@huawei.com
戳菜单栏-
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。