中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

一款適用于Android平臺的俄羅斯方塊

發布時間:2020-09-06 21:52:29 來源:腳本之家 閱讀:202 作者:葉應是葉 欄目:移動開發

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

整個程序設計十分簡潔,只是運用了兩個類而已,最終做出的效果圖如下所示:

一款適用于Android平臺的俄羅斯方塊

首先,要考慮的自然是游戲應該如何布局的問題了。我的想法是將手機屏幕分為上下兩部分,上邊用來顯示游戲者的名稱、所得分數以及下一個方塊,稱為“文字區域”,下邊自然就是游戲區域了。
如圖所示:

一款適用于Android平臺的俄羅斯方塊

布局文件如下:

<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眾多大小不一的屏幕,需要對布局進行動態規劃。在xml文件中,android:padding=”25px”,text1代表的是上方的文字區域,txet1的背景是一張半透明的圖片,在運行程序時會根據手機屏幕大小動態規劃其高度。text2是文字區域以及游戲區域之間的間距,我將它的高度定為固定值“30px”。而游戲區域的高度亦是會動態規劃的,自定義的view將會添加在FrameLayout當中。

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

public class Brick extends View {

 // 要繪制的方塊的坐標集
 private boolean[][] map;
 //保存每個坐標點在屏幕中的坐標
 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);
 }
 }
 }
 }
}

當中,map是一個boolean類型的二維數組,因為我將游戲區域的比例設為10乘15,所以map的大小即為map[10][15],map[0][0]即為游戲區域的左上角,map[9][14]為游戲區域的右下角。如果方塊落在了某個坐標點,則該坐標值設為true,否則為false。則當方塊不斷下落時,通過計算方塊的新的坐標點并重新構建新的map,即可獲得新的view對象。
BRICK_WIDTH為每個方塊的寬度,在構造函數中獲得。
因此,如果new一個Brick對象,且map的值均設為true,將之添加到FrameLayout當中,即可獲得如下效果:

一款適用于Android平臺的俄羅斯方塊

在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乘以十五后,即游戲區域的高度了,這樣就可以算出文字區域的高度了

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種,每個方塊下落時的初始坐標點亦如下所示:

一款適用于Android平臺的俄羅斯方塊

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

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兩個map對象,map1用來保存所有固定不動的方塊坐標點,map2用來保存還在下落的方塊的坐標點,這樣就能夠new兩個Brick對象,然后通過覆蓋的方法來使之同時顯示在同個區域內。這也是我將它們添加到FrameLayout布局的原因。

下落方塊的移動算法如下,適用于左移還有右移

//移動
 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);
 }

則要左移和右移時只要分別為move(int moveX, int moveY)函數傳入不同參數即可實現對應操作:

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

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

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

// 變形
 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);
 }

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

// 消行
 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;
 }
 }
 }

注意當中的j = j + 1語句,因為當第j行消行后上方區域需要整個“下沉”一行,所以原來的第j-1行就變成了第j行,所以還需要再從現在的第j行檢查起,加一的原因是在for循環中j會減一,所以這里先加一。

下移操作是整個程序設計中的難點,在這里面要實現消行檢查,map1和map2的數據更新,以便刷新新的界面,這里代碼就不再貼出了。

此外,我原本是打算用手勢操作來控制方塊的移動的,可因為根據手指滑動來判斷方向會有很大誤差,所以我最終還是采用Button來實現控制操作,可以看到效果圖當中有三個不同形狀的圖片,分別對應左移,變形和右移,且該三個Button組件是在Brick之后添加到布局文件當中的,這樣才能使按鈕圖片是覆蓋在方塊表面。

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

更多關于俄羅斯方塊的文章,請點擊查看專題:《俄羅斯方塊》

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

聂拉木县| 沈阳市| 旌德县| 宜川县| 宁河县| 怀柔区| 高清| 韶关市| 安仁县| 慈溪市| 和顺县| 鲁甸县| 调兵山市| 仁寿县| 邵武市| 湾仔区| 杨浦区| 乐山市| 尼木县| 葫芦岛市| 乐昌市| 龙陵县| 中西区| 藁城市| 彰化市| 阿拉善右旗| 鄂托克前旗| 普安县| 茂名市| 南召县| 冷水江市| 邓州市| 浙江省| 伊金霍洛旗| 休宁县| 五常市| 夏河县| 方城县| 怀柔区| 永州市| 福海县|