湖南科技大学本科生毕业设计(论文)
} } } LevelItem item = new LevelItem();//定义单个LevelItem结构 item.setNumber(curNum); item.setIconId(R.drawable.passed); items.add(item);//将item添加到当前页面 pages.add(items);//将当前页面添加到整个页面 if(breakFlag) break; 6.LevelItem类定义了一个关卡的数据结构,主要包括两个属性:一是当前关卡的关卡数值,二是当前关卡的图片。同时定义了相应属性的set(),get()方法。
4.5游戏谜题的存储与导入
在关卡选择模块中,当玩家点击了相应的关卡,将点击的关卡数值经过处理传入Intent组件,通过Intent启动GameActivity.java文件,开始游戏。
GameActivity类的onCreate()方法首先从Intent对象中提取表示关卡数值的数字。本游戏采用 java.util.Properties 类读取存储数独谜题的 puzzle.properties 文件。puzzle.properties片段代码如下:
关卡数值处理规则:获取选择的难度级别值i,(i+10)*100+关卡选择的位置,即为谜题关卡的key,通过key就可以获得玩家选择的谜题。
通过获得的关卡数值导入数独谜题,如果关卡数值大于0表示玩家选择了新游戏按钮,否则表示玩家选择了继续游戏按钮。
-22-
湖南科技大学本科生毕业设计(论文)
private int[] getPuzzle(int diff) { } String puz; if(diff >= 0 ){ } else { } …… //如果是继续游戏,则恢复保存的数据 try { InputStream inputStream = getResources().openRawResource(R.raw.puzzle); prop.loadFromXML(inputStream); //从输入流中获取properties键值对 //如果是新游戏,则读取对应数据 Properties prop = new Properties(); } catch (Exception e) { e.printStackTrace(); } return fromPuzzleString(puz); //将数独谜题转换成Int[]类型返回 puz = prop.getProperty(diff +\ //获得字符表示的数独谜题 4.6游戏状态存储与恢复
Android程序中的每个活动在其存在期间都会处于多种状态中的某一种状态,当用户可以开始与活动进行交互时会调用onResume()方法[9]。当GameActivity调用该方法时,保存游戏状态,当GameActivity获得的关卡数组为负数时,恢复游戏状态。在Android几种保存状态的方法中,这里我们选择getPreferences()方法来保存,恢复状态。
getPreferences()方法属于SharedPreferences数据保存方式。SharedPreferences是一种轻量级的数据保存方式。通过SharedPreferences可以将NVP(Name/Value Pair,名称/值对)保存在Android的文件系统中,它只能存储基本数据类型。实际上SharedPreferences是采用XML格式将数据存储到设备中,在DDMS中的File Explorer中的/data/data/
getPreferences()方法与getSharedPreferences()方法的功能基本相同,只是getPreferences()方法默认使用当前Activity命名存储XML文件,而不能指定存储XML文件的名称。getPreferences()使用方法为:
-23-
湖南科技大学本科生毕业设计(论文)
//保存状态数值 getPreferences(int mode).edit().putString(String key, String defValue).commit(); //获取状态数值 getPreferences(int mode).getString(String key, String defValue); 本游戏中需要保存与恢复的状态值有:未完成的数独谜题,原始数独谜题对应的标记数组,上次游戏所用时间,上次游戏填入数字次数,上次游戏的数独谜题关卡数组。
4.7游戏界面绘制与逻辑实现
当从Intent对象中提前到数独谜题后,我们创建PuzzleView类的一个实例,用Puzzleview类作为新的视图内容。这是一个完全自定义的视图,因此使用代码实现比XML实现更容易。接下来,具体讲述PuzzleView类的创建。
自定义View的第一步,构造函数的实现。我们引用GameActivity类,并通过设置选项允许用户在视图中输入。 this.game=(GameActivity)context; setFocusable(true); setFocusableInTouchMode(true); 通过实现onSizeChanged()方法,来计算屏幕上每个单元格的大小,其宽度和高度分别等于整个视图高度和宽度的1/9。该方法在视图被创建并且Android确定了视图大小以后被调用[9]。
每次需要更新视图的任何部分时,Android就会调用视图的onDraw()方法。onDraw()方法的内容如下:
protected void onDraw(Canvas canvas) { Paint background = new Paint(); background.setColor(getResources().getColor(R.color.puzzle_background)); canvas.drawRect(0, 0, getWidth(), getHeight(),background); //画每一格的网格线 for(int i = 0; i < 9; i++){ //画背景图 //画网格线 //使用方法public void drawLine(float startX, float startY, float //stopX, float stopY, Paint paint) {} ……
} //画小宫格框的网格线 -24-
湖南科技大学本科生毕业设计(论文)
} for(int i = 0; i < 9; i+=3){ } //画数字 //将数字画在格子的正中间 FontMetrics fm = foreground.getFontMetrics(); float X = width / 2; //确定Y方向时,使单元格的中点与数字的中点对齐 float Y = height / 2 - (fm.ascent + fm.descent) / 2; for(int i = 0; i < 9; i++){ for(int j = 0; j < 9; j++){ } } canvas.drawText(this.game.getTileString(i, j), ……. //而不是与数字的基线对齐 i * width + X, j * height + Y, foreground); //定义和更新选定区域 Paint selected = new Paint(); selected.setColor(getResources().getColor(R.color.puzzle_selected)); canvas.drawRect(selRect, selected); } super.onDraw(canvas); 界面绘制完成后,我们只需要处理点击时间,定义一个KeyPad类,继承自Dialog //定义一个颜色数组,分别显示可用数字数目不同的颜色 //遍历所有单元格,通过计算出来的不可用数字的数组 if(Prefs.getHints(getContext())){ //如果玩家设定了颜色提示 //计算当前格可用数字的个数,根据计算的值设定不同的颜色 类,监听整个PuzzleView,当有点击或者触摸操作时,根据玩家设定是否选择键盘提示的选项,显示键盘,具体控制详见4.2.8节。游戏界面绘制完成后的效果图如图4.10所示。
-25-
湖南科技大学本科生毕业设计(论文)
图4.10 游戏界面效果图
4.8游戏结束检测与信息提示
若玩家未开启键盘辅助提示或者在开启键盘辅助而且当前选择数字合理的情况下,每次玩家填入数字时,程序都会检测游戏是否结束,判断结束的方法为isGameOver(),下面来分析该方法的实现。
private int isGameOver(int[] puz){ //传入当前数独谜题
for(int i = 0; i < 9; i++){ } for(int j = 0; j < 9; j++){ } if(getTile(i, j) == 0) //还有未填入的空时 return 0; //返回0,表示数字未填满 int c[]; for(int i = 0; i < 9; i++){ c = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0}; for(int j = 0; j < 9; j++){ -26-