一款适用于Android平台的俄罗斯方块

俄罗斯方块Tetris是一款很经典的益智游戏,之前就做了一款桌面版的java俄罗斯方块,这次就尝试着写了一款适用于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当中,即可获得如下效果:

在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种,每个方块下落时的初始坐标点亦如下所示:

如正方形方块有四个点,坐标分别为(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版俄罗斯方块

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现俄罗斯方块

    本文实例为大家分享了Android实现俄罗斯方块的具体代码,供大家参考,具体内容如下 思路: 首先要画出游戏背景墙: 其次,要有方块,以及方块单元: 方块的不同形状,颜色随机产生: 游戏的控制面板. 可能会出现的问题或者难点: 边界问题: ①处于边界的时候,方块不可以再左右移动: ②下降的时候,到达边界即底部,则不可继续下落,此时应该产生一个新的方块: 与其它方块接触问题: ①下落的时候,如果碰到其它的方块则停止下落: ②左右移动的时候,移动的过程中,如果接触到其他方快,则不可再继续左右移动:

  • java实现俄罗斯方块

    假期闲着无事,就用一周多的时间看了百度java吧的一位大神(alwing)发布的视频,学着用java写了一个俄罗斯方块,在此就以发布源代码以及必要讲解的形式来感谢他的帮助.当然我这里也是做了一些改动,做出来的程序界面以及功能没有和他的完全一样. 整个程序运行起来的界面如下所示: 程序包含的功能有: 俄罗斯方块本身基本的游戏元素 显示下一轮出现的方块.当前等级.分数.消行数等数值 以值槽形式显示当前等级到下一等级的距离 左上角头像以及背景图片会随着等级的升高而改变 循环播放背景音乐 一. 整个程序

  • Java 小游戏开发之俄罗斯方块

    Java项目 俄罗斯方块 一.心得 二.游戏实例 游戏截图 目录结构 三.代码 1.主界面 Tetris.java package com.fry.tetris; import java.util.Arrays; import java.util.Random; /** * 4格方块 */ public class Tetromino { protected Cell[] cells = new Cell[4]; /** 保存旋转的相对于轴位置状态 */ protected State[] st

  • Java俄罗斯方块小游戏

    去年就已经学了这个技术了,一直没去写,现在抽个时间写了个俄罗斯方块游戏. 只有简单的新游戏,暂停,继续,积分功能.简单的实现了俄罗斯的经典功能. 不介绍了,有兴趣的自己运行一下,后面贴出了图片. 代码: package cn.hncu; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.Act

  • Java游戏俄罗斯方块的实现实例

    Java游戏俄罗斯方块的实现实例 java小游戏主要理解应用java Swing,awt等基础组件的知识,通过本例应当掌握面向对象的知识. 实现代码: package cn.hncu.games; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import

  • 一款适用于Android平台的俄罗斯方块

    俄罗斯方块Tetris是一款很经典的益智游戏,之前就做了一款桌面版的java俄罗斯方块,这次就尝试着写了一款适用于Android平台的俄罗斯方块. 整个程序设计十分简洁,只是运用了两个类而已,最终做出的效果图如下所示: 首先,要考虑的自然是游戏应该如何布局的问题了.我的想法是将手机屏幕分为上下两部分,上边用来显示游戏者的名称.所得分数以及下一个方块,称为"文字区域",下边自然就是游戏区域了. 如图所示: 布局文件如下: <LinearLayout xmlns:android=&q

  • Android平台中实现数据存储的5种方式

    本文介绍Android中的5种数据存储方式,具体内容如下 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 下面将为大家一一详细介绍.  第一种:使用SharedPreferences存储数据 SharedPreferences是Android平台上一个轻量级的存储类,主要是保存一

  • packages思维及使用Java添加Android平台特定实现

    目录 packages思维 过程实现 Android平台代码 创建Flutter平台客户端 使用Java添加Android平台特定的实现 packages思维 即使软件包未在Pub.对于未用于公共发布的特殊插件或尚未准备好发布的软件包,可以使用其他依赖选项: dependencies: flutter: sdk: flutter 路径依赖性:Flutter应用程序可以通过文件系统依赖插件的路径依赖性.路径可以是相对路径,也可以是绝对路径. 例如,要依赖位于应用程序相邻目录中的插件“plugin1

  • Android平台基于Pull方式对XML文件解析与写入方法详解

    本文详细讲述了Android平台基于Pull方式对XML文件解析与写入方法.分享给大家供大家参考,具体如下: XML技术在跨平台的情况下的数据交互中得到了广泛的应用,假如我们需要开发一个Android应用程序,需要同服务器端进行数据交互,通过XML文件可以很方便的在Android平台和服务器之间进行数据传输,具体实现涉及到对XML文件进行解析及写入的技术.本文实现在Android平台上基于Pull方式对XML文件解析的技术. XmlPullParser是一个Java实现的开源API包(源码下载地

  • 解决Android平台中应用程序OOM异常的方法

    在Android平台上面,应用程序OOM异常永远都是值得关注的问题.通常这一块也是程序这中的重点之一.这下我就如何解决OOM作一点简单的介绍. 首先,OOM就是内存溢出,即Out Of Memory.也就是说内存占有量超过了VM所分配的最大. 怎么解决OOM,通常OOM都发生在需要用到大量内存的情况下(创建或解析Bitmap,分配特大的数组等),在这样的一种情况下,就可能出现OOM,据我现在了解到,多数OOM都是因为Bitmap太大.所以,这里我就专门针对如何解决Bitmap的OOM.其实最核发

  • 快速解决Android平台移植ffmpeg的一些问题

    IT行业是一个踩在巨人肩膀上前进的行业,否则做的事情不一定有意义,所以我也是基于havlenapetr移植的ffmpeg基础上做了些改进,他做的主要贡献有: 1. 移植了ffmpeg并将与媒体相关的结构体在java层重新进行了封装,方便应用程序在java层直接操作ffmpeg API,如各种媒体格式转码及播放,如图1所示 2. 模仿Android的MediaPlayer类实现了ffmpeg的播放接口,如setDataSource(),setDisplay(),start(), stop(),pa

  • 适用于Android开发的简单聊天软件

    适用于android 开发.是一个简单的聊天软件,包括知识点,各个控件的运用(ExpandableListView,ViewPager,Spinner,LinearLayout,RelativeLayot),自定义的ViaImageView(自定义xml属性),sql 的写入,读取等操作. 1. ViaImageView.java    package com.farina.farinaimagelib; import android.content.Context; import androi

  • Android平台下轻量级http网络传输库

    AsyncHttpHelp是一个android平台下基于httpclient开发的HTTP网络请求工具. 优点 功能齐全,提供常用的http网络访问接口. 轻量级,无任何第三方库依赖,库大小为90K左右. 定制化,自定义json解析库,支持请求参数,返回内容预处理. 易用性,简单易用,只需几行代码即可完成请求,可随意设置cookie.http头部等信息. 功能 1.普通get请求 2.普通post请求 3.Form表单提交数据 4.二进制数据传输 5.json格式内容传输(json字符串自动转j

  • Android平台预置GMS包后关机闹钟失效问题及解决方法

    1.介绍 关机闹钟为Android中默认支持的功能,实现起来则需要满足一定的条件:自动开机.开机后响铃.对于自动开机来说,自动关机可以在应用层通过设置alarm来实现,而自动开机需要底层rtc时钟的支持:开机后检查时间,到点响铃. 2.原理 一般智能手机的硬件架构都是分为RF,BB,AP这三个部分, RF射频部分的功能主要是接收和发射射频,大家不用关注这个.而AP部分就是应用程序处理器,其实也就是CPU模块:BB部分则是基带模块.通常手机关机都是AP模块完全断电,而BB虽然处在关机状态,但实际上

  • MTK Android平台开发流程

    本篇给大家详细讲解了MTKAndroid平台开发流程,大致分为44个步骤,我们把每个步骤的命令详细讲解了下,一起来学习下. 1.拷贝代码仓库从git@192.168.1.3:a89.git到work目录下: cbk@YCS:~/work$ll cbk@YCS:~/work$rm-rfa89/ cbk@YCS:~/work$cd.. cbk@YCS:~/work$gitclonegit@192.168.1.3:a89.git 2.修改xshell用户密码:passwd 3.Android查看源代码

随机推荐