1、一、 绪论1.1. 项目背景本题目将设计一个俄罗斯方块(Tetris, 俄文:)。它是一款风靡全球的电视游戏机和掌上游戏机游戏,由俄罗斯人阿列克谢帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。1.2. 开发平台 此项目基于android 环境进行开发,使用的编程工具为eclipse,它是以android语言作为其基本语言的一种可视化编程工具。Android 是Google开发的基于Linux平台的开源手机操作系统. Android四大基本组件分别是Activity,
2、Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器。应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。你的应用可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice 来响应它们收到的信息,或者用NotificationManager 来通知用户。一个Service 是一段长生命周期的,没有用户界面的程序
3、,可以用来开发如监控类程序。android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。注:Activity生命周期二、 项目规则及设计思路1.2.2.1. 项目规则 玩家通过点触虚拟键盘,左右控制方块左右移动,按上代表旋转,按下代表加速向下移动,每满一行消除,获得相应积分100,积分每增长2000,等级加1,游戏速度加快2.2. 实现思路1.2.2.1.2.2.2.2.1. 界面设计游戏菜单界面游戏结束界面游戏运行界面排行榜界面帮助界面 注:游戏界面中,利用二维数组进行保存,其值为1代表该点有方块占用,值为0代表空白,根据值绘制整张游戏窗口。2.2.
4、2. 功能设计 从游戏的基本玩法出发,主要算法在于俄罗斯方块的形状和旋转。在游戏设计中,方块采用最基本的7种造型,包括长条型,正方型,正S型,反S型,正7型,反7型,T型,每种造型又可以通过逆时针旋转变化出4种形状,因此利用三维数组保存28种方块形状,并且编号为KK+3(K=0,17)的四个形状为一组。方块采用4*4的二维数组的数据结构,以此在界面中根据其数组对应值进行方块绘制。在旋转过程进行之前,先判断在该位置能否进行旋转,若能,则将其在三维数组中的编号K,编号为K+(K+1)%4的形状即为旋转结果。 游戏过程中,利用随机函数在一个预览窗体中提前展示形状供用户参考,然后将展示的形状复制到游戏
5、窗体中进行摆放,在游戏窗体中用户就可以使用键盘的方向键来控制方块的运动,然后对每一行进行判断,如果有某行的方块是满的,则消除这行的方块,并且使上面的方块自由下落,其中,方块向下的速度通过调用函数进行控制。同时用户也可以使用向下键加快下落速度,定义一个变量,对消除的行数进行记录,最后得出用户的分数,用条件语句对分数进行判断,达到一定的积分就可以升级到下一个等级。三、 程序流程图1.2.3.3.1. 总流程到达底部部到底游戏结束到达底部部结束销行操作生成下一个下坠物将新生的下坠物代替旧的“下一个下坠物“将旧的“下一个下坠物”用作当前 下坠物销行操作游戏结束处理下降一个单位开始3.2. 底部到达的判
6、断与销行的实现:是否堆积方块,判断接触面状态及是否得分2.统计分数判断是否过关关数增加,游戏速度将变快。开始新的一关,继续游戏游戏窗口重绘1.判断行满、处理销行、堆积方块向下移动 将新的下坠物放置到游戏区域中去,这时可能出现马上到达底部的情况,因此需要对它进行判断,如果是到达底部,则进行销行处理,并且修改相应的数据状态。而判断是否已经到达了底部,可以通过当前下坠物件所对应的接触面的方块位置为被占用状态来确定。 统计分数:在消行处理里面有一个专门用来统计消行数的变量,然后根据变量的值决定分数的多少。如果总分数达到过关条件就过关,改变游戏速度,开启新的一关,然后再加载方块。没有达到过关分数或者没有
7、满行,则加载下一个方块继续游戏。是否是否否是是否接上图1点底行判断当前行是否为空判断当前行是否为满判断是否有满行判断移动行方块是否为空当前行向上推动一行将要移动行所有数据移至当前行将当前行的所有数据初始化统计连续几行为满如果有销行,则刷新游戏区域。接上图2点4.5.5.1.5.2.5.3. 随机方块的产生是否7654321随机抽取一个数随机数一字形田字形L 形J 形T 形S 形Z字形型游戏是否结束保存当前方块坐标显示方块于屏幕上游戏结束保存信息关数初始化返回开始界面四、 部分截图5.1初始界面5.2游戏界面 5.3帮助界面5.4排行界面1.2.3.4.5. 五、 关键代码1.2.3.4.5.6
8、.6.1. ActivityGame.javapackage com.HDU.tetris;import android.app.Activity;import android.app.AlertDialog;import android.app.Dialog;import android.app.AlertDialog.Builder;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.Window;public class ActivityGam
9、e extends Activity /总游戏窗口private static final String TAG = ActivityGame;TetrisView mTetrisView = null;/处理游戏进程的类public void onCreate(Bundle saved)/创建活动super.onCreate(saved);/启动窗体的拓展特性requestWindowFeature(Window.FEATURE_NO_TITLE);init();private void init()mTetrisView = new TetrisView(this);Intent inte
10、nt = getIntent();/得到当前的intent/获取额外信息等级int level = intent.getIntExtra(ActivityMain.LEVEL,1);mTetrisView.setLevel(level);/设置等级int flag = intent.getFlags();/得到当前intent的标记符if(flag = ActivityMain.FLAG_CONTINUE_LAST_GAME)/当遇到继续上次游戏事件mTetrisView.restoreGame();/恢复上次游戏/得到当前声音设置boolean isVoice = intent.getBoo
11、leanExtra(ActivityMain.VOICE,true);mTetrisView.setVoice(isVoice);/设置声音setContentView(mTetrisView);/设定当前使用的视图public void onPause()/暂停活动mTetrisView.onPause();super.onPause();public void onResume()/执行活动super.onResume();mTetrisView.onResume();public void onStop()/停止活动super.onStop();mTetrisView.saveGame(
12、);/保存游戏mTetrisView.freeResources();/释放游戏占用的资源6.2. ActivityHelp.javapackage com.HDU.tetris;import android.app.Activity;import android.os.Bundle;public class ActivityHelp extends Activity /帮助窗口public void onCreate(Bundle saved) /开始super.onCreate(saved);setContentView(R.layout.help);/初始化帮助窗口的界面6.3. Act
13、ivityMain.javapackage com.HDU.tetris;/ Author: HDU/ 2010.3import android.app.Activity;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.TextView;pu
14、blic class ActivityMain extends Activity public static final int FLAG_NEW_GAME = 0;/开始新游戏public static final int FLAG_CONTINUE_LAST_GAME = 1;/继续上一次的游戏public static final String FILENAME = settingInfo; /文件名public static final String LEVEL = level;/游戏级别public static final String VOICE = voice;/游戏声音pri
15、vate int mLevel = 1;/当前游戏等级private Button btNewgame = null;/新游戏按钮private Button btContinue = null;/继续游戏按钮private Button btHelp = null;/帮助按钮private Button btRank = null;/排名按钮private Button btPre = null;/等级下降按钮private Button btNext = null;/等级上升按钮private Button btExit = null;/退出按钮private TextView tvLev
16、el = null;/等级编辑框private CheckBox cbVoice = null;/声音选项 /* Called when the activity is first created. */ Override public void onCreate(Bundle savedInstanceState) /创建,程序执行时的第一步 super.onCreate(savedInstanceState); setContentView(R.layout.menu);/设置开始界面的菜单 btNewgame = (Button)findViewById(R.id.bt_new); /通
17、过ID查找新游戏按钮在VIEW子控件 btContinue = (Button)findViewById(R.id.bt_continue);/继续游戏按钮控件 btHelp = (Button)findViewById(R.id.bt_help);/帮助按钮控件 btRank = (Button)findViewById(R.id.bt_rank);/排名按钮控件 btPre = (Button)findViewById(R.id.bt_pre);/等级下降按钮控件 btNext = (Button)findViewById(R.id.bt_next);/等级上升 按钮控件 btExit =
18、 (Button)findViewById(R.id.bt_exit);/退出按钮控件 tvLevel = (TextView)findViewById(R.id.tv_speed);/等级编辑框控件 cbVoice = (CheckBox)findViewById(R.id.cb_voice);/声音选项框控件 btNewgame.setOnClickListener(buttonListener); / 在新游戏按钮上设置点击监听器 btContinue.setOnClickListener(buttonListener);/ 在继续游戏按钮上设置点击监听器 btHelp.setOnCli
19、ckListener(buttonListener);/ 在帮助按钮上设置点击监听器 btRank.setOnClickListener(buttonListener);/ 在排名按钮上设置点击监听器 btPre.setOnClickListener(buttonListener);/ 在等级下降按钮设置点击监听器 btNext.setOnClickListener(buttonListener);/ 在等级上升按钮上设置点击监听器 btExit.setOnClickListener(buttonListener);/ 在退出按钮上设置点击监听器 restoreSettings();/恢复初始
20、设置 private Button.OnClickListener buttonListener = new Button.OnClickListener() /按钮上的点击监听器类Overridepublic void onClick(View v) /按钮点击时的处理程序if(v = btNewgame)/当被点击的按钮为新游戏按钮时Intent intent = new Intent(ActivityMain.this,ActivityGame.class);/在两个Activity类之间传输数据intent.setFlags(FLAG_NEW_GAME);/设置标记符intent.pu
21、tExtra(VOICE,cbVoice.isChecked();/添加声音的附加信息intent.putExtra(LEVEL,mLevel);/添加等级的附加信息startActivity(intent);/将此intent类传入相应的Activity中return;if(v = btContinue)/继续游戏按钮处理程序Intent intent = new Intent(ActivityMain.this,ActivityGame.class);/建立intent类intent.setFlags(FLAG_CONTINUE_LAST_GAME); /设置标记符intent.putEx
22、tra(VOICE,cbVoice.isChecked();/添加声音选项的附加信息startActivity(intent);/将此intent类传入相应的Activity中return;if(v = btHelp)/帮助按钮的处理程序Intent intent = new Intent(ActivityMain.this,ActivityHelp.class);/建立intent类startActivity(intent);/将此intent类传入相应的Activity中return;if(v = btRank)/排名按钮的处理程序Intent intent = new Intent(Ac
23、tivityMain.this,ActivityRank.class);/建立intent类startActivity(intent);/将此intent类传入相应的Activity中return;if(v = btPre)/等级下降按钮的才护理程序btPre.setBackgroundColor(0xffc0c0c0); /设置背景颜色String s = tvLevel.getText().toString();/从等级编辑框中获取信息,传入字符串中int level = Integer.parseInt(s);/将获取的字符串转化为数字-level;/等级减1level = (level
24、-1+TetrisView.MAX_LEVEL) % TetrisView.MAX_LEVEL;/避免等级益处标准范围,形成循环设置+level;/等级加1,从05 改为标准的16s = String.valueOf(level);/将数字转化为字符串,传回tvLevel.setText(s); /等级编辑框的内容显示为新的等级数mLevel = level; /当前等级改为设置的等级btPre.setBackgroundColor(0x80cfcfcf);/设置背景颜色return;if(v = btNext)/等级上升按钮的处理程序btNext.setBackgroundColor(0xf
25、fc0c0c0); /设置背景颜色String s = tvLevel.getText().toString();/从等级编辑框中获取信息,传入字符串中int level = Integer.parseInt(s);/将获取的字符串转化为数字-level;/等级减1level = (level+1) % TetrisView.MAX_LEVEL;/避免等级益处标准范围,形成循环设置+level;/等级加1,从05 改为标准的16s = String.valueOf(level);/将数字转化为字符串,传回tvLevel.setText(s);/等级编辑框的内容显示为新的等级数mLevel =
26、level;/当前等级改为设置的等级btNext.setBackgroundColor(0x80cfcfcf);/设置背景颜色return;if(v = btExit)/退出按钮的处理程序ActivityMain.this.finish();/结束该活动 ; private void saveSettings()/保存设置方法 /SharedPreferences是轻量级的存储类,主要是保存一些常用的配置 SharedPreferences settings = getSharedPreferences(FILENAME,0);/得到当前设置信息 settings.edit() .putInt
27、(LEVEL,mLevel) .putBoolean(VOICE,cbVoice.isChecked() .commit();/将各种信息保存如settings中,完成更新设置 private void restoreSettings()/恢复初始设置 SharedPreferences settings = getSharedPreferences(FILENAME,0);/得到当前设置信息 mLevel = settings.getInt(LEVEL,1);/等级恢复为1 boolean hasVoice = settings.getBoolean(VOICE,true); tvLevel
28、.setText(String.valueOf(mLevel);/显示初始等级到等级编辑框中 cbVoice.setChecked(hasVoice);/声音设置为开启 public void onStop()/活动停止方法 super.onStop(); saveSettings();/保存当前设置 6.4. ActivityRank.javapackage com.HDU.tetris;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;import android.widg
29、et.SimpleAdapter;import android.widget.SimpleCursorAdapter;public class ActivityRank extends Activity /排名窗口private RankDatabase mDatabase = null;/数据库信息/通过ListView控件,可将项目组成带有或不带有列标头的列,并显示伴随的图标和文本。private ListView mListView = null;public void onCreate(Bundle saved)/创建该活动super.onCreate(saved);setTitle(
30、排行榜);/显示标题setContentView(R.layout.rank);/设置窗口初始化信息6.5. Court.javapackage com.HDU.tetris;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;public class Court /游戏窗口public final static int COURT_WIDTH = 11; /窗口的宽度public final stati
31、c int COURT_HEIGHT = 23+4;/窗口的高度public final static int BLOCK_WIDTH = 20;/每个格子的宽度public final static int BLOCK_HEIGHT = 20;/每个格子的高度public final static int ABOVE_VISIBLE_TOP = 4;/允许显示的最高点public final static int BEGIN_DRAW_X = 0;/开始画图的坐标public final static int BEGIN_DRAW_Y = TetrisView.SCREEN_HEIGHT -
32、 Court.BLOCK_WIDTH * Court.COURT_HEIGHT;private int mCourt = new intCOURT_WIDTHCOURT_HEIGHT; /保存窗口信息的数组private Context mContext = null;/context的作用,就是android应用连接service的桥梁。private ResourceStore mRs = null; /应用环境中的资源信息public Court(Context context)mContext = context;/保存应用环境全局信息mRs = new ResourceStore(c
33、ontext);/获取应用环境中的资源信息clearCourt();/清空游戏窗口public void clearCourt()/清除窗口信息int i,j;for(i=0;iCOURT_WIDTH;i+)/遍历窗口所有的点for(j=0;jCOURT_HEIGHT;j+)mCourtij = 0; /将相应数组信息清空public boolean isGameOver()/判断游戏是否结束for(int i=0;iCOURT_WIDTH;i+)/其中某一行的方块到达可允许显示的最高点,则游戏结束if(mCourtiABOVE_VISIBLE_TOP != 0) return true;re
34、turn false;public boolean isSpace(int posX,int posY) /判断该点是否为空if (posX = COURT_WIDTH) /超出行边界线出错return false;if (posY = COURT_HEIGHT) /超出列边界线出错return false;if(0 = mCourtposXposY) /对应数组的值为0 ,即为空return true;return false;public boolean availableForTile(int tile,int x,int y) /判断该格子能否放方块for (int i = 0; i
35、4; i+) /遍历所有点for (int j = 0; j 4; j+) if (tileij != 0) if (!isSpace(x + i, y + j) /该点已经有方块占据return false;return true;public void placeTile(TileView tile) /放置方块int i,j;for (i = 0; i 4; i+)for (j = 0; j 0)/存在可消除的行eliminateRows(high,lineCount);/消除找到的可消除的行return lineCount;/返回消除的行数return 0;private void e
36、liminateRows(int highRow,int rowAmount)/消除已完成的行上的方块int i,j;for(i = highRow+rowAmount-1;i = rowAmount;i-)for(j = 0;j COURT_WIDTH;j+)/将待消除行上方的方块整体向下移动,覆盖待消除的行mCourtji = mCourtji-rowAmount;private int highestFullRowIndex() /查找已完成行的最高行数int result = 0;boolean removeable = true;/标记是否可以消除int i,j;for(i = 0;
37、i COURT_HEIGHT;i+)/从上往下遍历removeable = true;for(j = 0;j= 0;i-)/从下往上遍历removeable = true;for(j = 0;jCOURT_WIDTH & removeable;j+)if(isSpace(j,i) )/该点上没有方块result-;removeable = false;/标记该行不可消除if(removeable)/可消除,则找到结果,退出break;return result;private void removeSingleLine(int lineIndex,int time) /消除单行int t,i,
38、j;for(t = 0;t 0; i-)/将待消除行上方的方块全部向下移动一行for (j = 0; j COURT_WIDTH; j+)mCourtji = mCourtji - 1;/上一行覆盖下一行public void paintCourt(Canvas canvas)/根据画布信息画游戏窗口/Paint 中包含了很多方法对其属性进行设置,绘制时所使用的画笔Paint paint = new Paint();paint.setAlpha(0x60);/ 设置Alpha值/对图片添加透明效果canvas.drawBitmap(mRs.getCourtBackground(),0, 0, paint);paint.setAlpha(0x