欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一款適用于Android平臺(tái)的俄羅斯方塊

 更新時(shí)間:2020年03月27日 14:59:56   作者:葉應(yīng)是葉  
這篇文章主要為大家詳細(xì)介紹了一款適用于Android平臺(tái)的俄羅斯方塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

俄羅斯方塊Tetris是一款很經(jīng)典的益智游戲,之前就做了一款桌面版的java俄羅斯方塊,這次就嘗試著寫了一款適用于Android平臺(tái)的俄羅斯方塊。

整個(gè)程序設(shè)計(jì)十分簡(jiǎn)潔,只是運(yùn)用了兩個(gè)類而已,最終做出的效果圖如下所示:

首先,要考慮的自然是游戲應(yīng)該如何布局的問題了。我的想法是將手機(jī)屏幕分為上下兩部分,上邊用來顯示游戲者的名稱、所得分?jǐn)?shù)以及下一個(gè)方塊,稱為“文字區(qū)域”,下邊自然就是游戲區(qū)域了。
如圖所示:

布局文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/linear"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@drawable/three"
 android:orientation="vertical"
 android:padding="25px" >
 <TextView
 android:id="@+id/text1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@drawable/hh"/>
 <TextView
 android:id="@+id/text2"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:height="30px" />
 <FrameLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </FrameLayout>
</LinearLayout>

為了讓游戲能夠更好地適配Android眾多大小不一的屏幕,需要對(duì)布局進(jìn)行動(dòng)態(tài)規(guī)劃。在xml文件中,android:padding=”25px”,text1代表的是上方的文字區(qū)域,txet1的背景是一張半透明的圖片,在運(yùn)行程序時(shí)會(huì)根據(jù)手機(jī)屏幕大小動(dòng)態(tài)規(guī)劃其高度。text2是文字區(qū)域以及游戲區(qū)域之間的間距,我將它的高度定為固定值“30px”。而游戲區(qū)域的高度亦是會(huì)動(dòng)態(tài)規(guī)劃的,自定義的view將會(huì)添加在FrameLayout當(dāng)中。

自定義的view組件代碼如下,用來繪制并顯示所有的方塊:

public class Brick extends View {

 // 要繪制的方塊的坐標(biāo)集
 private boolean[][] map;
 //保存每個(gè)坐標(biāo)點(diǎn)在屏幕中的坐標(biāo)
 private Point[][] Points;

 private int PADDING = 3;
 //方塊的寬度
 private float BRICK_WIDTH;

 private Paint paint = new Paint();

 private RectF rectf;

 public Brick(Context context, boolean[][] map, float BRICK_WIDTH) {
 super(context);
 this.map = map;
 this.BRICK_WIDTH = BRICK_WIDTH;
 setBackgroundResource(R.drawable.one);
 }
 public void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 Points = new Point[10][15];
 for (int j = 0; j < 15; j++) {
 for (int i = 0; i < 10; i++) {
 Points[i][j] = new Point(i * (int) BRICK_WIDTH, j* (int) BRICK_WIDTH);
 }
 }
 for (int j = 0; j < 15; j++) {
 for (int i = 0; i < 10; i++) {
 if (map[i][j]) { 
 paint.setColor(Color.parseColor("#f7faf3"));
  float x = Points[i][j].x;
  float y = Points[i][j].y;
  rectf = new RectF(x, y, x + BRICK_WIDTH, y + BRICK_WIDTH);
  canvas.drawRect(rectf, paint);
 paint.setColor(Color.parseColor("#4c8e0b"));
 rectf = new RectF(x + PADDING, y + PADDING, x + BRICK_WIDTH- PADDING, y + BRICK_WIDTH - PADDING);
 canvas.drawRect(rectf, paint);
 }
 }
 }
 }
}

當(dāng)中,map是一個(gè)boolean類型的二維數(shù)組,因?yàn)槲覍⒂螒騾^(qū)域的比例設(shè)為10乘15,所以map的大小即為map[10][15],map[0][0]即為游戲區(qū)域的左上角,map[9][14]為游戲區(qū)域的右下角。如果方塊落在了某個(gè)坐標(biāo)點(diǎn),則該坐標(biāo)值設(shè)為true,否則為false。則當(dāng)方塊不斷下落時(shí),通過計(jì)算方塊的新的坐標(biāo)點(diǎn)并重新構(gòu)建新的map,即可獲得新的view對(duì)象。
BRICK_WIDTH為每個(gè)方塊的寬度,在構(gòu)造函數(shù)中獲得。
因此,如果new一個(gè)Brick對(duì)象,且map的值均設(shè)為true,將之添加到FrameLayout當(dāng)中,即可獲得如下效果:

在Activity類中,通過如下代碼可獲得屏幕信息:

//獲取屏幕的寬度和高度
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
SCREEN_WIDTH = metric.widthPixels;
SCREEN_HIGHT = metric.heightPixels;

SCREEN_WIDTH 是屏幕寬度,SCREEN_HIGHT 是屏幕高度,則SCREEN_WIDTH 減去兩倍PADDING,再除以十后,就可以得到方塊的寬度BRICK_WIDTH,而BRICK_WIDTH乘以十五后,即游戲區(qū)域的高度了,這樣就可以算出文字區(qū)域的高度了

BRICK_WIDTH = (SCREEN_WIDTH - 2 * PADDING) / 10;
GAME_HIGHT = 15 * BRICK_WIDTH;
TEXT_HIGHT = SCREEN_HIGHT - 2 * PADDING - 30 - GAME_HIGHT;
text = (TextView) findViewById(R.id.text1);
frame = (FrameLayout) findViewById(R.id.frame);
text.setHeight((int) TEXT_HIGHT);

下落方法的基本形狀有如下6種,每個(gè)方塊下落時(shí)的初始坐標(biāo)點(diǎn)亦如下所示:

如正方形方塊有四個(gè)點(diǎn),坐標(biāo)分別為(4,0)(5,0)(4,1)(5,1)。用List< Point[] >類型的listPoints來保存坐標(biāo)集合。注意:每個(gè)下落方塊的第一個(gè)坐標(biāo)點(diǎn)均是有特殊作用的,這個(gè)后邊會(huì)說到。

private static List<Point[]> listPoints;
 static {
 listPoints = new ArrayList<Point[]>(6);
 listPoints.add(new Point[] { new Point(4, 0), new Point(5, 0),
 new Point(4, 1), new Point(5, 1) });
 listPoints.add(new Point[] { new Point(4, 1), new Point(4, 0),
 new Point(4, 2), new Point(4, 3) });
 listPoints.add(new Point[] { new Point(4, 1), new Point(5, 0),
 new Point(4, 0), new Point(4, 2) });
 listPoints.add(new Point[] { new Point(5, 1), new Point(5, 0),
 new Point(4, 0), new Point(5, 2) });
 listPoints.add(new Point[] { new Point(5, 1), new Point(5, 0),
 new Point(4, 1), new Point(5, 2) });
 listPoints.add(new Point[] { new Point(4, 1), new Point(4, 0),
 new Point(5, 1), new Point(5, 2) });
 }

在程序中,我的想法是new兩個(gè)map對(duì)象,map1用來保存所有固定不動(dòng)的方塊坐標(biāo)點(diǎn),map2用來保存還在下落的方塊的坐標(biāo)點(diǎn),這樣就能夠new兩個(gè)Brick對(duì)象,然后通過覆蓋的方法來使之同時(shí)顯示在同個(gè)區(qū)域內(nèi)。這也是我將它們添加到FrameLayout布局的原因。

下落方塊的移動(dòng)算法如下,適用于左移還有右移

//移動(dòng)
 public void move(int moveX, int moveY) {
 for (int i = 0; i < point.length; i++) {
 int newX = point[i].x + moveX;
 int newY = point[i].y + moveY;
 if (newX < 0 || newX > 9 || newY > 14 || map1[newX][newY]) {
 return;
 }
 }
 for (int k = 0; k < 15; k++) {
 for (int t = 0; t < 10; t++) {
 map2[t][k] = false;
 }
 }
 for (int j = 0; j < point.length; j++) {
 point[j].x = point[j].x + moveX;
 point[j].y = point[j].y + moveY;
 }
 for (int j = 0; j < point.length; j++) {
 int x = point[j].x;
 int y = point[j].y;
 map2[x][y] = true;
 }
 frame.removeView(brick2);
 brick2 = new Brick(this, map2, BRICK_WIDTH);
 frame.addView(brick2);
 }

則要左移和右移時(shí)只要分別為move(int moveX, int moveY)函數(shù)傳入不同參數(shù)即可實(shí)現(xiàn)對(duì)應(yīng)操作:

 // 左移
 public void leftBrick(View view) {
 move(-1, 0);
 }

 // 右移
 public void rightBrick(View view) {
 move(1, 0);
 }

變形操作我在我的另一篇博文中也寫到過:用Java寫俄羅斯方塊,需要下落方塊有一個(gè)固定的旋轉(zhuǎn)點(diǎn),這個(gè)旋轉(zhuǎn)點(diǎn)我設(shè)為下落方塊的第一個(gè)坐標(biāo)點(diǎn),這也是我前邊所說的第一個(gè)坐標(biāo)點(diǎn)的特殊作用。

// 變形
 public void changeBrick(View view) {

 if (point[0].x + 1 == point[1].x && point[2].x + 1 == point[3].x
 && point[0].y + 1 == point[2].y) {
 return;
 }
 for (int i = 0; i < point.length; i++) {
 int newX = point[0].y + point[0].x - point[i].y;
 int newY = point[0].y - point[0].x + point[i].x;
 if (newX < 0 || newX > 9 || newY > 14 || map1[newX][newY]) {
 return;
 }
 }
 for (int i = 0; i < point.length; i++) {
 int newX = point[0].y + point[0].x - point[i].y;
 int newY = point[0].y - point[0].x + point[i].x;
 point[i].x = newX;
 point[i].y = newY;
 }
 for (int k = 0; k < 15; k++) {
 for (int t = 0; t < 10; t++) {
 map2[t][k] = false;
 }
 }
 for (int j = 0; j < point.length; j++) {
 int x = point[j].x;
 int y = point[j].y;
 map2[x][y] = true;
 }
 frame.removeView(brick2);
 brick2 = new Brick(this, map2, BRICK_WIDTH);
 frame.addView(brick2);
 }

消行操作需要在每次下落方塊無法再下落時(shí)檢查是否需要實(shí)行,所以檢查是從第十五行開始直到第一行:

// 消行
 public void MoveLine() {
 for (int j = 14; j >= 0; j--) {
 int n = 0;
 for (int i = 0; i < 10; i++) {
 if (map1[i][j]) {
  n++;
 }
 }
 if (n == 10) {
 for (int k = j; k > 0; k--) {
  for (int i = 0; i < 10; i++) {
  map1[i][k] = map1[i][k - 1];
  }
 }
 j = j + 1;
 }
 }
 }

注意當(dāng)中的j = j + 1語句,因?yàn)楫?dāng)?shù)趈行消行后上方區(qū)域需要整個(gè)“下沉”一行,所以原來的第j-1行就變成了第j行,所以還需要再從現(xiàn)在的第j行檢查起,加一的原因是在for循環(huán)中j會(huì)減一,所以這里先加一。

下移操作是整個(gè)程序設(shè)計(jì)中的難點(diǎn),在這里面要實(shí)現(xiàn)消行檢查,map1和map2的數(shù)據(jù)更新,以便刷新新的界面,這里代碼就不再貼出了。

此外,我原本是打算用手勢(shì)操作來控制方塊的移動(dòng)的,可因?yàn)楦鶕?jù)手指滑動(dòng)來判斷方向會(huì)有很大誤差,所以我最終還是采用Button來實(shí)現(xiàn)控制操作,可以看到效果圖當(dāng)中有三個(gè)不同形狀的圖片,分別對(duì)應(yīng)左移,變形和右移,且該三個(gè)Button組件是在Brick之后添加到布局文件當(dāng)中的,這樣才能使按鈕圖片是覆蓋在方塊表面。

源代碼下載:Android版俄羅斯方塊

更多關(guān)于俄羅斯方塊的文章,請(qǐng)點(diǎn)擊查看專題:《俄羅斯方塊》

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android NavigationBar問題處理的方法

    Android NavigationBar問題處理的方法

    本篇文章主要介紹了Android NavigationBar問題處理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Flutter多項(xiàng)選擇彈窗實(shí)現(xiàn)詳解

    Flutter多項(xiàng)選擇彈窗實(shí)現(xiàn)詳解

    這篇文章介紹了Flutter多項(xiàng)選擇彈窗實(shí)現(xiàn)詳解,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>
    2021-11-11
  • Android即時(shí)通訊設(shè)計(jì)(騰訊IM接入和WebSocket接入)

    Android即時(shí)通訊設(shè)計(jì)(騰訊IM接入和WebSocket接入)

    本文主要介紹了Android即時(shí)通訊設(shè)計(jì)(騰訊IM接入和WebSocket接入),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法

    Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法,結(jié)合實(shí)例形式詳細(xì)分析了自定義分享列表功能的步驟與具體操作技巧,需要的朋友可以參考下
    2017-02-02
  • Android 中的 XRecyclerview的使用案例

    Android 中的 XRecyclerview的使用案例

    這篇文章主要介紹了Android 中的 XRecyclerview的使用案例,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • Kotlin基本數(shù)據(jù)類型詳解

    Kotlin基本數(shù)據(jù)類型詳解

    大家好,本篇文章主要講的是Kotlin基本數(shù)據(jù)類型詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 一看就懂的Android APP開發(fā)入門教程

    一看就懂的Android APP開發(fā)入門教程

    這篇文章主要介紹了Android APP開發(fā)入門教程,從SDK下載、開發(fā)環(huán)境搭建、代碼編寫、APP打包等步驟一一講解,非常簡(jiǎn)明的一個(gè)Android APP開發(fā)入門教程,需要的朋友可以參考下
    2014-05-05
  • Android實(shí)現(xiàn)上傳文件功能的方法

    Android實(shí)現(xiàn)上傳文件功能的方法

    這篇文章主要介紹了Android實(shí)現(xiàn)上傳文件功能的方法,對(duì)Android初學(xué)者有一定的借鑒價(jià)值,需要的朋友可以參考下
    2014-07-07
  • Android 反射注解與動(dòng)態(tài)代理綜合使用詳解

    Android 反射注解與動(dòng)態(tài)代理綜合使用詳解

    本篇文章主要介紹了Android 反射注解與動(dòng)態(tài)代理綜合使用詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android ListView用EditText實(shí)現(xiàn)搜索功能效果

    Android ListView用EditText實(shí)現(xiàn)搜索功能效果

    本篇文章主要介紹了Android ListView用EditText實(shí)現(xiàn)搜索功能效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03

最新評(píng)論