您好,欢迎来到刀刀网。
搜索
您的当前位置:首页安卓大作业—围住神经猫小游戏

安卓大作业—围住神经猫小游戏

来源:刀刀网


《移动终端应用开发》

大 作 业 报 告 书

题 目: 围住神经猫小游戏 专 业: 计算机科学与技术 学 号: 学生姓名: × × 指导教师: 叉叉叉 完成日期: 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 available = new Vector();//avaliable容器记录可用点

Vector direct = new Vector();;//positive容器记录这个方向上可以直接到达屏幕边缘的路径

HashMap hash = new HashMap();//pl容器记录方向

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

本站由北京市万商天勤律师事务所王兴未律师提供法律服务