《移动终端应用开发》
大 作 业 报 告 书
题 目: 围住神经猫小游戏 专 业: 计算机科学与技术 学 号: 学生姓名: × × 指导教师: 叉叉叉 完成日期: 2016-5-31
目 录
一、 需求分析 ---------------------------- 错误!未定义书签。 二、 系统功能描述 ------------------------ 错误!未定义书签。 三、 系统概要设计 ---------------------------------------- 2 3.1功能模块设计 -------------------------------------- 2 3.1.1程序流程图 ----------------------------------- 2 3.1.2程序模块设计 --------------------------------- 2 3.1.3界面功能详细设计------------------------------ 3 四、 系统主要代码 ---------------------------------------- 4 五、 总结 ----------------------------------------------- 17 5.1开发中遇到的问题 --------------------------------- 17 5.2系统有待实现的功能 ------------------------------- 17 5.3收获总结 ----------------------------------------- 18 六、 参考文献 ------------------------------------------- 18
一 需求分析
安卓游戏已经是大势所趋,开发安卓游戏也将是游戏开发者的重中之重,所以我选择试做一个安卓小游戏来作为我的android课程大作业。围住神经猫是一款益智类的小游戏,它可以在人们生活烦躁工作无聊之时提高一种新的打发时间、舒缓压力的休闲方式,也可以锻炼人的逻辑思维能力、判断力和观察力。
首先我们从游戏界面开始分析,一开始是游戏欢迎界面,点击“开始游戏”,就可以切换到游戏界面,开始玩游戏了。在游戏界面中,有游戏背景,还有神经猫在移动时的样式,并把神经猫可移动的范围以坐标的方式分为若干个点。游戏结束时会对玩家进行提示,若玩家成功围住神经猫则显示玩家所用的步数。
然后是对神经猫这个游戏控制的分析,神经猫可移动的范围是9×9,我设置神经猫的初始位置是固定的,但是系统在游戏一开始生成的路障是随机的,一共是16个路障,之后玩家将根据游戏的情况对神经猫进行堵截,当玩家每选择一个点作为自己想设置的路障时,那个点将改变为橘色,而神经猫将根据可选择的路径自动移动到下一个地点,当神经猫移动到任意一个边缘时,游戏会提示玩家失败,当玩家成功围住神经猫时,游戏会提示玩家成功且会显示出玩家所用的步数。
这个游戏要用到二维数组,把神经猫可以移动的范围进行记录,还必须要对神经猫的移动方式进行设置,还有每个点不同状态的转换,路障的自动生成,还有对玩家所用步数的统计,这个游戏所要用到的主要软件是Eclipse、ADT,它的主要语言是java,操作系统是windows7.
二 系统功能设计
项目具体功能描述如下:
1) 游戏开始界面 :有比较搞笑的背景图来吸引玩家,然后点击开始游戏,
切换到游戏界面
2) 游戏界面:神经猫一开始在游戏的正中间,平且还有系统随机生成的16 个路障,范围是9×9的空间里,并且把它分成了点,玩家在
点上设置好路障后,神经猫会在看选取的路径中随机选取一
1
条,并移动到下一个点,直至游戏结束。
3) 游戏结束界面:当神经猫移动到任意边缘时,会显示通关失败的提示;
但玩家成功围住神经猫时,则显示成功通关页面,并且统计了玩家所用的步数。
三 项目概要设计
3.1功能模块设计
(1)程序流程图
根据用户需求,本软件程序流程图如下: 启动程序 游戏开始界面
游戏界面 成功 通关失败 通关 通关失败界面 通关界面 图1.程序流程图
(2)程序模块设计
2
再来一次 为了提高代码的重复利用率,程序设计时自定义了以下几个类:
① 自定义坐标类 (Dot):每一个点都是一个抽象的对象,需要把每一个点抽象为一个类,然后让每一个圆圈继承于这个类。
② 自定义绘制布局类(playground):继承surfaceview,将制定的绘图呈现在surfaceview上,界面的响应和绘制都在surfaceview上完成的。
③ 自定义实现接口(OnTouchListener):为了界面的点击做出响应。
(3)界面功能详细设计
各界面功能详尽介绍如下:
1) 游戏开始界面(图1:homepage):打开程序首先显示游戏开始界面,通过点击开始游戏,马上自动跳转到游戏界面图(homepage2)
图1:homepage
2) 游戏界面(图2:homepage2):进入到游戏界面以后,就可以正式开始游戏啦玩家开始对神经猫进行围追截堵
3
图2:homepage2
3)游戏结束界面(图3:homepage3、图4:homepage4):若玩家成功围住神经猫则显示图3,若失败则显示图4
图3:homepage3 图4:homepage4
4
四 项目主要代码
系统实现相应功能的主要代码如下:
记录每个场景中的元素它的X,Y坐标点的状态:
package com.example.crazycat;
public class Dot {//记录每个场景中的元素它的X,Y坐标点的状态。并不会直接参与界面的响应和界面的绘制
private int x, y;
private int status;//记录这个点的状态
public static final int STATUS_OFF = -1;//代表可走的路径
public static final int STATUS_IN = 0;//猫的当前位置
public static final int STATUS_ON = 1;//已经设置的路障
//指定x,y的坐标
public Dot(int x, int y) { this.x = x; this.y = y;
this.status = STATUS_OFF; }
//指定geter和sette方法 public int getX() { return x; }
public void setX(int x) { this.x = x; }
public int getY() { return y; }
public void setY(int y) {
5
}
this.y = y; }
public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }
//同时设置x。y的方法
public void setXY(int x, int y) { this.x = x; this.y = y; }
Playground类的实现:
package com.example.crazycat;
import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; import java.util.Vector;
import android.annotation.SuppressLint; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.content.Context;
import android.content.DialogInterface; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF;
import android.graphics.drawable.Drawable; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View;
import android.view.View.OnClickListener;
6
import android.view.View.OnTouchListener; import android.widget.Toast;
public class PlayGround extends SurfaceView implements OnTouchListener {
//界面的响应和界面的绘制在SurfaceView完成,触摸事件的响应通过OnTouchListener接口实现 // 行数
private static final int ROW = 9; // 列数
private static final int COL = 9; // 障碍的数量
private static final int BOCKS = COL * ROW / 5; // 屏幕宽度去
private int SCREEN_WIDTH; // 每个通道的宽度 private int WIDTH;
// 奇数行和偶数行通道间的位置偏差量 private int DISTANCE;
// 屏幕顶端和通道最顶端间的距离 private int OFFSET;
// 整个通道与屏幕两端间的距离 private int length;
// 做成神经猫动态图效果的单张图片 private Drawable cat_drawable; // 背景图
private Drawable background; // 神经猫动态图的索引 private int index = 0;
private Dot[][] matrix;
private Dot cat;
private Timer timer = null;
private TimerTask timerttask = null;
private Context context;
private int steps;
private int[] images = { R.drawable.cat1, R.drawable.cat2, R.drawable.cat3,
7
R.drawable.cat4, R.drawable.cat5, R.drawable.cat6, R.drawable.cat7,
R.drawable.cat8, R.drawable.cat9, R.drawable.cat10, R.drawable.cat11, R.drawable.cat12, R.drawable.cat13, R.drawable.cat14, R.drawable.cat15, R.drawable.cat16 };
@SuppressLint(\"ClickableViewAccessibility\") public PlayGround(Context context) {
super(context);//使用Context创建当前类构造函数
matrix = new Dot[ROW][COL];//将行高,列宽传递进去,指定数组大小 cat_drawable = getResources().getDrawable(images[index]); background = getResources().getDrawable(R.drawable.bg); this.context = context; initGame();//调用游戏初始化
getHolder().addCallback(callback);//将Callback对象指定给getholder
setOnTouchListener(this);//设定为自己的触摸 this.setFocusable(true);
this.setFocusableInTouchMode(true); }
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { stopTimer(); }
return super.onKeyDown(keyCode, event); }
// 初始化游戏:分别对可走路径位置,猫的位置和路障位置进行初始化 private void initGame() { steps=0;
for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) {
matrix[i][j] = new Dot(j, i);/*X,Y坐标值和行列值是相反的。
即通过查找列值获得X坐标,查找行值获得Y坐标*/
} }
for (int i = 0; i < ROW; i++) {//用for循环将所有点设置为STATUS_OFF,即可用状态
for (int j = 0; j < COL; j++) {
matrix[i][j].setStatus(Dot.STATUS_OFF);
8
} }
cat = new Dot(COL / 2 - 1, ROW / 2 - 1);//设置猫的起始点
getDot(cat.getX(), cat.getY()).setStatus(Dot.STATUS_IN);//把猫的起始点的状态设置为STATUS_IN,才能记录猫的位置
for (int i = 0; i < BOCKS;) {//用for循环随机的指定16个点的坐标作为路障
int x = (int) ((Math.random() * 1000) % COL);
int y = (int) ((Math.random() * 1000) % ROW);//随机获取1对坐标点
if (getDot(x, y).getStatus() == Dot.STATUS_OFF) {//对当前可用路径点进行选择
getDot(x, y).setStatus(Dot.STATUS_ON);//把这个点设置成路障
i++; } } }
//实现界面绘制,在redraw方法中将所有元素以图形化显示出来,也就是将它绘制在Canvas对象上
private void redraw() {
Canvas canvas = getHolder().lockCanvas();//锁定画布 canvas.drawColor(Color.GRAY);//设置颜色为浅灰色 Paint paint = new Paint();//创建Paint对象
paint.setFlags(Paint.ANTI_ALIAS_FLAG);//开启抗锯齿,优化视频质量
//用两个For循环嵌套将所有的点显示到界面中来 for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { DISTANCE = 0;//引入偏移量 if (i % 2 != 0) {
DISTANCE = (int) WIDTH / 2;//对偶数行进行缩进 }
Dot dot = getDot(j, i);//将坐标赋值给内部变量one switch (dot.getStatus()) {//由于每个点对应的三种状态颜色不一样,要用一个switch语句
case Dot.STATUS_IN:
paint.setColor(0XFFEEEEEE);//STATUS_IN状态时设置颜色为浅灰
break;
case Dot.STATUS_ON:
paint.setColor(0XFFFFAA00);//STATUS_ON状态时设置颜
9
色为橙色
break;
case Dot.STATUS_OFF:
paint.setColor(0X74000000);//STATUS_OFF状态时设置颜色为黑色
break; default: break; }
canvas.drawOval(new RectF(dot.getX() * WIDTH + DISTANCE + length, dot.getY() * WIDTH + OFFSET, (dot.getX() + 1)
* WIDTH + DISTANCE + length, (dot.getY() + 1) * WIDTH + OFFSET), paint);
/*在Canvas画布上画椭圆并界定它的上下左右边界宽度且有错位*/
} }
int left = 0; int top = 0;
if (cat.getY() % 2 == 0) { left = cat.getX() * WIDTH; top = cat.getY() * WIDTH; } else {
left = (int) (WIDTH / 2) + cat.getX() * WIDTH; top = cat.getY() * WIDTH; }
// 此处神经猫图片的位置是根据效果图来调整的
cat_drawable.setBounds(left - WIDTH / 6 + length, top - WIDTH / 2
+ OFFSET, left + WIDTH + length, top + WIDTH + OFFSET); cat_drawable.draw(canvas);
background.setBounds(0, 0, SCREEN_WIDTH, OFFSET); background.draw(canvas);
getHolder().unlockCanvasAndPost(canvas);;//取消Canvas的锁定,把绘图内容更新到界面上 }
//为Surfaceview添加Callback
Callback callback = new Callback() {//声明并实例化一个Callback接口 public void surfaceCreated(SurfaceHolder holder) {
redraw();//执行redraw函数,在界面第一次显示时将指定的内容显示到界面上
10
startTimer(); }
//使用surfaceChanged方法来适配不同的屏幕尺寸
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
WIDTH = width / (COL + 1);
OFFSET = height - WIDTH * ROW - 2 * WIDTH; length = WIDTH / 3; SCREEN_WIDTH = width; }
public void surfaceDestroyed(SurfaceHolder holder) { stopTimer(); } };
// 开启定时任务
private void startTimer() { timer = new Timer();
timerttask = new TimerTask() { public void run() { gifImage(); } };
timer.schedule(timerttask, 50, 65); }
// 停止定时任务
public void stopTimer() { timer.cancel(); timer.purge(); }
// 动态图
private void gifImage() { index++;
if (index > images.length - 1) { index = 0; }
cat_drawable = getResources().getDrawable(images[index]); redraw();
11
}
// 获取通道对象
private Dot getDot(int x, int y) { return matrix[y][x]; }
// 判断神经猫是否处于边界
private boolean inEdge(Dot dot) {
if (dot.getX() * dot.getY() == 0 || dot.getX() + 1 == COL || dot.getY() + 1 == ROW) {
return true;//当前点的坐标无论是x或y为0,或x或y值是定义的游戏场景最大值时都处于边界 }
return false; }
// 移动cat至指定点
private void moveTo(Dot dot) {
dot.setStatus(Dot.STATUS_IN);//dot的状态设置为猫所处的点 getDot(cat.getX(), cat.getY()).setStatus(Dot.STATUS_OFF);//将猫当前点的状态复位
cat.setXY(dot.getX(), dot.getY());//将猫移动到新的点 }
// 获取one在方向dir上的可移动距离,中心点6个方向距离的判断与获取。路径结束点为路障用负数表示,为场景边缘用正数表示 private int getDistance(Dot one, int dir) { int distance = 0; if (inEdge(one)) {
return 1;//如果下一个点已在屏幕边缘,无需再判断 }
Dot ori = one;//定义ori和next,ori指定为当前函数传入的one Dot next;
while (true) {
next = getNeighbour(ori, dir);
if (next.getStatus() == Dot.STATUS_ON) {
return distance * -1;//下一个点为路障的话,直接返回距离0 }
if (inEdge(next)) { distance++;
return distance;//下一个点为场景边缘时,距离+1并返回 }
distance++;
12
ori = next; } }
// 获取dot的相邻点,返回其对象
private Dot getNeighbour(Dot dot, int dir) {//每个点都有6个相邻点 switch (dir) { case 1:
return getDot(dot.getX() - 1, dot.getY());//获得中心点左边相邻点
case 2:
if (dot.getY() % 2 == 0) {
return getDot(dot.getX() - 1, dot.getY() - 1);//奇数行获得中心点左上相邻点:x-1,y-1 } else {
return getDot(dot.getX(), dot.getY() - 1);//偶数行获得中心点左上相邻点:y-1 } case 3:
if (dot.getY() % 2 == 0) {
return getDot(dot.getX(), dot.getY() - 1);//奇数行获得中心点右上相邻点:y-1 } else {
return getDot(dot.getX() + 1, dot.getY() - 1);//偶数行获得中心点右上相邻点:x+1,y-1 } case 4:
return getDot(dot.getX() + 1, dot.getY());//获得中心点右边相邻点
case 5:
if (dot.getY() % 2 == 0) {
return getDot(dot.getX(), dot.getY() + 1);//奇数行获得中心点右下相邻点:y+1 } else {
return getDot(dot.getX() + 1, dot.getY() + 1);//偶数行获得中心点右下相邻点:x+1,y+1 } case 6:
if (dot.getY() % 2 == 0) {
return getDot(dot.getX() - 1, dot.getY() + 1);//奇数行获得中心点左下相邻点:x-1,y+1 } else {
return getDot(dot.getX(), dot.getY() + 1);//偶数行获得中心点左下相邻点:y+1
13
} }
return null; }
// cat的移动算法
private void move() { if (inEdge(cat)) { failure();
return;//猫处于游戏边缘,失败 }
Vector Vector HashMap for (int i = 1; i < 7; i++) {//如果当前猫被6个邻点围住 Dot n = getNeighbour(cat, i); if (n.getStatus() == Dot.STATUS_OFF) { available.add(n);//如果相邻点可用,把它添加到avaliable记录器中 hash.put(n, i);//为pl传入方向i if (getDistance(n, i) > 0) { direct.add(n);//当它有一个路径可以直接到达屏幕边缘,把n传递进positive中 } } } //移动算法的优化 if (available.size() == 0) { win();//周围的6个点都不可走,没有可用点,成功围住猫 } else if (available.size() == 1) { moveTo(available.get(0));//只有一个方向可走,可用点有一个,移动到这个可用点上 } else {//有多个方向可走 Dot best = null; if (direct.size() != 0) {//存在可以直接到达屏幕边缘的走向 int min = 20; for (int i = 0; i < direct.size(); i++) { if (inEdge(direct.get(i))) { best = direct.get(i); break; } else { 14 int t = getDistance(direct.get(i), hash.get(direct.get(i))); if (t < min) { min = t;//把最短路径长度传给min best = direct.get(i);//选出拥有最短路径的点 } } } } else {//所有方向都存在路障 int max = 1; for (int i = 0; i < available.size(); i++) { int k = getDistance(available.get(i), hash.get(available.get(i))); if (k < max) {//所有方向都存在路障,距离k为负数 max = k; best = available.get(i);//选出拥有最短路径的点 } } } moveTo(best);//移动到最短路径的下一点 } // redraw(); if (inEdge(cat)) { failure(); } } // 通关失败 private void failure() { AlertDialog.Builder dialog = new Builder(context); dialog.setTitle(\"通关失败\"); dialog.setMessage(\"你让神经猫逃出精神院啦(ˉ▽ˉ;)...\"); dialog.setCancelable(false); dialog.setNegativeButton(\"再玩一次\", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { initGame(); } }); dialog.setPositiveButton(\"取消\", null); dialog.show(); } // 通关成功 15 private void win() { AlertDialog.Builder dialog = new Builder(context); dialog.setTitle(\"通关成功\"); dialog.setMessage(\"你用\" + (steps + 1) + \"步捕捉到了神经猫耶( •̀ ω •́ )y\"); dialog.setCancelable(false); dialog.setNegativeButton(\"再玩一次\", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { initGame(); } }); dialog.setPositiveButton(\"取消\", null); dialog.show(); } // 触屏事件 @SuppressLint(\"ClickableViewAccessibility\") public boolean onTouch(View v, MotionEvent event) { //将屏幕的坐标转换为游戏的坐标 int x, y; if (event.getAction() == MotionEvent.ACTION_UP) {//当用户触摸之后手离开屏幕释放的瞬间才对事件进行响应 if (event.getY() <= OFFSET) { return true; } y = (int) ((event.getY() - OFFSET) / WIDTH);//横向状态下,奇、偶数行有坐标偏移,而纵向的Y值是不变的,将y进行转换 if (y % 2 == 0) { if (event.getX() <= length || event.getX() >= length + WIDTH * COL) { return true; } x = (int) ((event.getX() - length) / WIDTH); } else { if (event.getX() <= (length + WIDTH / 2) || event.getX() > (length + WIDTH / 2 + WIDTH * COL)) { return true; } x = (int) ((event.getX() - WIDTH / 2 - length) / WIDTH); } 16 if (x + 1 > COL || y + 1 > ROW) { initGame();//触摸超出边界时初始化游戏 } else if (inEdge(cat)) { return true; } else if (getDot(x, y).getStatus() == Dot.STATUS_OFF) { getDot(x, y).setStatus(Dot.STATUS_ON);//当这个点可用时被点击之后设定为路障状态 move(); steps++; } redraw();//将改变更新到界面 } return true; } } 五 总结 5.1开发中遇到的问题 1)界面响应的问题:在我点击屏幕来给神经猫设置路障时画面完全没有响应。 解决方案:为Surfaceview添加Callback,并且添加redraw(),在界面第一次显示时将指定的内容显示到界面上。 2)神经猫移动路线问题:神经猫是根据设置的路障情况,在可移动的范围内选择一条可移动的路径,但是如何移动,有些没有头绪。 解决方案:将神经猫移动的路线分为这么几种情况,周围的6个点都不可走,没有可用点,成功围住猫,如果只有一个方向可走,可用点有一个,移动到这个可用点上;如果有多个方向可走,存在可以直接到达屏幕边缘的走向,选出拥有最短路径的点,神经猫将移动到那个点;如果所有方向都存在路障,选出拥有最短路径的点,移动到最短路径的下一点 5.2项目有待实现的功能 1)游戏难度系数低,需要实现可分类。 2)分数比较:可以建立个数据库,记录每位玩家的分数,然后在游戏结束时,跟全国的玩家进行对比,来进行排名。 3)游戏分享功能:可以通过微信QQ等工具分享给好友。 17 5.3收获总结 在整个软件的开发过程中可以说遇到了许许多多千奇百怪的错误,有些错误很快能想到解决办法,但是有些错误往往是直接盯着代码看了几个小时,测试了N遍之后才恍然大悟,原来自己真的真的很粗心。虽然说耗费了很长时间来完成这个项目,但也学到了很多的经验,对软件的掌握程度,对调试代码方法的掌握,对各种文件的操作等都有了很大的提高。本次的项目我也是本着将以前所学的知识合理应用的目的,用了很多种不同的方法来实现同一种功能,以此来考察自己的能力,因此软件设计,代码书写的时候没有特别的计较时间空间的复杂度等问题,这也是以后需要注意到的问题。 同时,这次是以团队的形式来开发这一项目的,不论结果如何,不论成绩如何,我们团队的两个个人都尽自己的所能,将自己所用到项目的开发中来。这也考验了我们的团队协作能力,以及整个项目的规划问题。总之,这次项目的实践受益匪浅,而且也深深的认识到了自己的不足,能力有待提高,知识面太过狭窄,了解的技术也很少。在以后的学习过程中仍然要努力的学习相关的知识。 六 参考文献 李刚.《疯狂Android讲义》 电子工业出版社 李刚 .《疯狂Java讲义》. 电子工业出版社 佘志龙.陈小凤等.《Android SDK开发范例大全》第3版 .人民邮电出版社 陈璟,陈平华,李文亮. Android内核分析[J] . 广东工业大学计算机学院 实践 与经验,2009:112-115 赵亮,张维. 基于Android技术的界面设计与研究[D] . 徐州:徐州建筑职业 技术学院, 2001 陈炜,张晓蕾,侯燕萍等.Java软件开发技术.北京:人民邮电出版社,2005 18 《移动终端软件开发》考核评分标准 项目名称: 程序代码量极其少,程序无法运行 程序运行情况 程序运行中存在bug,经现场调试未解决 程序运行中存在bug,经现场调试解决 程序整个运行过程正常 完成项目最基本的功能模块 在以上基础上,模块设计合理,功能全面 功能模块 在以上基础上,能熟练灵活使用MVC模式 在以上基础上,使用合理的模式进行模块划分,解决较复杂的编程问题。 具有一般的用户界面 系统界面设计 在以上基础上,用户界面功能全面 在以上基础上,用户界面美观,操作便捷,良好交互 在以上基础上,功能设计实现上有创新 使用课程所讲知识实现项目的功能 在以上基础上,自学知识: 创新部分 简单完成设计报告,符合最低要求 项目设计报告 设计报告能简要的介绍系统功能 报告内容比较完整,格式清晰,语句较通顺 报告内容完整,图表使用准确,描述详细,反映系统开发过程 教师签字: 成绩: 学号: 19 20
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务