《android创新实验报告.docx》由会员分享,可在线阅读,更多相关《android创新实验报告.docx(48页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、项目编号 创新实验报告实验项目名称 基于Android手机操作系统的游戏软件开发学 生 姓 名 石皓程 樊峰辰 学生学号 021112218/021112230 所在学院 电子电气工程学院 指导教师 施一萍 目录一、 实验目的二、 实验方案2.1总体设计思想 2.2实验流程(步骤) 2.3实验环境 2.4实验分工三、 实验过程3.1Andriod软件开发环境搭建3.2模块划分3.3游戏主界面模块3.4游戏控制模块3.5模块实现原理3.51游戏界面模块实现3.52游戏控制模块实现3.6游戏界面具体实现 3.61蛇身、食物和墙的实现 3.62处理键盘事件 3.63 TileView类的设计 3.6
2、4 SnakeView类的设计 3.65 RefreshHandler类的设计3.7程序调试与运行四、 实验结果和分析五、 参考文献六、 附录一 代码清单七、 附录二 环境搭建和运行 一 实验目的贪吃蛇游戏一款非常经典的手机游戏,因为它比较简单有趣,无论老少都比较适合。贪吃蛇的设计对每一个Java语言设计者进行语言提高和进阶都是一个很好的锻炼机会。 贪吃蛇游戏的设计比较复杂,它涉及面广、牵涉方面多,如果不好好考虑和设计,将难以成功开发出这个游戏。在这个游戏的设计中,牵涉到图形界面的显示与更新、数据的收集与更新,并且在这个游戏的开发中,还要应用类的继承机制以及一些设计模式。因此,如何设计和开发好
3、这个贪吃蛇游戏,对于提高Java开发水平和系统的设计能力有极大的帮助。在设计开发过程中,需要处理好各个类之间的继承关系,还要处理各个类相应的封装,并且还要协调好各个模块之间的逻辑依赖关系和数据通信关系。本项目在Android平台下,使用Java语言,Android开发技术开发一款界面友好,功能齐全的贪吃蛇游戏。二 实验方案2.1总体设计思想 本软件是针对贪吃蛇小游戏的JAVA程序,利用上、下、左、右方向键来改变蛇的运动方向,长按某个方向键后,蛇的运动速度会加快,在随机的地方产生食物,吃到食物就变成新的蛇体,碰到壁或自身则游戏结束,否则正常运行游戏,在到达固定的分数后,游戏速度会加快。2.2实验
4、流程Java编程语言Android软件的开发环境搭建(Eclipse开发软件、Android SDK开发框架、Android Development Tool开发环境)Android程序的框架结构游戏软件的开发2.3实验环境 实验地点在实训楼1号楼计算中心。计算中心具有较好的实验设备,拥有较高配置的PC机300台(Intel酷睿2 Q8300四核处理器、2G内存),都可以接入校园网和Inter网,完全能满足该创新实验项目的需要。2.4实验分工 李 琦:环境的搭建和游戏的编译 邵彧韬:截图和后期的制作三 实验过程3.1Andriod软件开发环境搭建 采用eclipse开发工具在windows7下
5、进行,基于安卓2.2操作系统。 环境搭建:1. JDK安装 2. Eclipse安装 3. Android SDK安装 4. ADT安装创建AVD软件总体设计 工程中包括4个Activity,分别为Snake(主界面)、Game(游戏界面)、Help(游戏说明界面)、AuthorView(作者信息界面),通过不同Activity之间的转换实现不同界面之间的切换。Snake(Activity)继承了SnakeView类,SnakeView类继承了TileView类。TileView类继承了View其实 Snake的工程蛮简单的,源文件就三个: Snake.java SnakeView.java
6、TileView.java。 Snake类是这个游戏的入口点, TitleView类进行游戏的绘画, SnakeView类则是对游戏控制操作的处理。 Coordinate, RefreshHandler是 2个辅助类,也是 SnakeView类中的内部类。其中, Coordinate是一个点的坐标( x, y), RefreshHandler将 RefreshHandler对象绑定某个线程并给它发送消息。如下图: 图3.13.2模块划分从面向对象程序设计的角度,本项目总体地可以分为游戏界面模块、数据存储模块和控制模块。如下图所示:游戏数据存储模块贪吃蛇游戏游戏主界面模块游戏控制模块图3.2游戏
7、总体模块3.3游戏主界面模块游戏界面主框架主要包括游戏图形区域界面、游戏的开始按钮、暂停按钮、游戏的退出按钮。游戏界面主框架的主要结构图如图3.3所示。游戏的主界面架游戏图形区域界面(即游戏画布)游戏控制按钮界面图3.3 游戏主界面3.4 游戏控制模块 游戏控制模块主要通过手机键盘上的按钮来控制游戏的开始、游戏的暂停、游戏的退出这三个功能以及控制游戏分数变化。在这个模块中,需要给各个按钮添加响应事件代码,来对上述的功能加以进一步的实现。游戏控制模块的主要框架如图3.4所示。游戏控制模块游戏的移动速度功能能游戏的暂停功能游戏的重新开始图3.4 游戏控制模块框架3.5模块实现原理3.5.1游戏界面
8、模块实现1.实现游戏背景本游戏采用Activity作为游戏背景的载体,在Android中一个Activity就相当于windows中的一个窗口,Activity上可以放置许多类型的控件。一个activity主要有三个状态:当在屏幕前台时(位于当前任务堆栈的顶部),它是活跃或运行的状态。它就是相应用户操作的activity。 当它失去焦点但仍然对用户可见时,它处于暂停状态。即是:在它之上有另外一个activity。这个activity也许是透明的,或者未能完全遮蔽全屏,所以被暂停的activity仍对用户可见。暂停的activity仍然是存活状态(它保留着所有的状态和成员信息并连接至窗口管理器)
9、,但当系统处于极低内存的情况下,仍然可以杀死这个activity。如果它完全被另一个activity覆盖是,它处于停止状态。它仍然保留所有的状态和成员信息。然而它不在为用户可见,所以它的窗口将被隐藏,如果其它地方需要内存,则系统经常会杀死这个activity。如果一个activity处于暂停或停止状态,系统可以通过要求它结束(调用它的 finish() 方法)或直接杀死它的进程来将它驱出内存。当它再次为用户可见的时候,它只能完全重新启动并恢复至以前的状态。当一个activity从这个状态转变到另一个状态时,它被以下列protected方法所通知:void onCreate(Bundle sav
10、edInstanceState) 、void onStart() 、void onRestart() 、void onResume() 、void onPause() 、void onStop() 、void onDestroy()2. 实现蛇的身体蛇可以看做是一个个节点组成的,因此可以用一个链表来存储蛇身的元素,在画蛇时遍历这个链表讲里面的元素一一画出,这样就实现了一条蛇.3. 实现蛇的移动用一个timer(定时器)来不断地刷新游戏画面,每刷新一次就再蛇头的前面(链表的尾部)增加一个新元素,同时把蛇尾的一个元素删掉,这样从视觉上看起来就实现了蛇的移动.4. 实现蛇吃食物 蛇移动的过程中如果蛇
11、头的坐标与食物出现的坐标重合了,那么就在蛇头的位置增加一个元素同时不删除蛇尾的最后一个元素,这样蛇每迟到一个食物身体就会变长一截.3.5.2 游戏控制模块实现1. 实现操作蛇的移动方向在Android系统中,手机上的每个按钮都会有一个对应的键值跟它对应,所在可以给对应的按钮设置监听器OnClickListener,监听器是一个接口,该接口中有一个方法onClick(View v)。当按钮被点击的时候系统会自动调用该监听器的onClick(View v)方法。所以实现游戏控制的具体代码将被写到该方法中。因为本游戏中不允许蛇向与蛇头相反的方向移动,所以当用户操作时需要判断用户操作的方向是不是跟规则
12、冲突,若冲突则无视该操作,若不冲突则响应该操作,所以需要用一个变量来记录蛇头的当前方向。2. 实现游戏暂停 在Activity的生命周期中,有一个onPause()方法.该方法在Activity变得不可见的时候被系统自动调用.在玩游戏过程中,如果有来电或是其它事件中断,这时应该把当前状态保存。以便返回时,还可以继续玩游戏。这就使用onSaveInstanceState实现保存当前状态。3. 实现游戏恢复Activity生命周期的onResume()方法.该方法在Activity从不可见的状态下变得可见时被系统自动调用.在用户接完电话或者在暂停状态下触摸屏幕后可以在该生命周期方法中对游戏进行恢复
13、.4. 实现游戏退出当一个Activity退出或者被调用finish()方法后,系统会调用其生命周期方法onDestroy().当用户退出游戏时,可以在这个方法中对资源进行释放.3.6游戏界面具体实现3.6.1 蛇身、食物和墙的实现前面已经提过,蛇身的数据用一个链表来存储,具体我使用ArrayList来实现。蛇身的每个元素、食物和墙都是一个坐标对象,画这些东西的时候只需要把它们的坐标传给画的方法就行了。这里需要引进一个坐标类Coordinate,这是一个包括两个参数,用于记录X轴和Y轴简单类,其中包括一个比较方法,该方法用于判断蛇头于食物或者墙是否重合.该类的代码如下:class Coordi
14、nate public int x; public int y; public Coordinate(int newX, int newY) x = newX; y = newY; public boolean equals(Coordinate other) if (x = other.x & y = other.y) return true; return false; public String toString() return Coordinate: + x + , + y + ; 蛇身的初始长度我设置为5,new 5个Coordinate的对象放入ArrayList中。整个屏幕可以
15、看做是有很多个网格组成的,而蛇就在这些网格中移动。用一个二维数组int mTileGrid来存储网格的坐标,将蛇身、食物或者墙的坐标传到该数组中,onDraw方法按照该数组中的坐标将屏幕相应位置的网格填充成位图。画蛇身、食物、墙的方法为: public void onDraw(Canvas canvas) super.onDraw(canvas); for (int x = 0; x mXTileCount; x +) for (int y = 0; y 0) canvas.drawBitmap(mTileArraymTileGridxy, mXOffset + x * mTileSize,
16、mYOffset + y * mTileSize, mPaint); 3.6.2处理键盘事件使用View类的onKeyDown方法,该方法由系统监听调用。根据按键的值处理响应事件,该方法中解决了反向移动的问题。mDirection 为当前蛇头的方向,mNextDirection 为按键对应的方向,按键按下后会先判断当前方向是否跟下一方向相反,若相反则不响应事件。具体代码如下: public boolean onKeyDown(int keyCode, KeyEvent msg) if (keyCode = KeyEvent.KEYCODE_DPAD_UP) if (mMode = READY
17、| mMode = LOSE) initNewGame(); setMode(RUNNING); update(); return (true); if (mMode = PAUSE) setMode(RUNNING); update(); return (true); if (mDirection != SOUTH) mNextDirection = NORTH; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_DOWN) if (mDirection != NORTH) mNextDirection = SOUTH; return (t
18、rue); if (keyCode = KeyEvent.KEYCODE_DPAD_LEFT) if (mDirection != EAST) mNextDirection = WEST; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_RIGHT) if (mDirection != WEST) mNextDirection = EAST; return (true); return super.onKeyDown(keyCode, msg); if (direction != currentDirection) & !needUpdat
19、e)/ 取出列表中的最后一个元素(蛇的头部)WormLink sl = (WormLink)worm.lastElement();int x = sl.getEndX();int y = sl.getEndY();/ 不同的运动方向坐标的改变也不一样switch (direction) case UP: / 当这段向上运动的时候if (currentDirection != DOWN) y-; needUpdate = true; break;case DOWN: / 当这段向下运动的时候if (currentDirection != UP) y+; needUpdate = true; br
20、eak;case LEFT: / 当这段向左运动的时候if (currentDirection != RIGHT) x-; needUpdate = true; break;case RIGHT: / 当这段向右运动的时候if (currentDirection != LEFT) x+; needUpdate = true; break; / 当更改方向后需要更新if (needUpdate = true) worm.addElement (new WormLink (x, y, 0, direction);currentDirection = direction; 3.6.3 TileVie
21、w类的设计TileView是游戏的界限,即蛇头若触碰到界限则游戏结束。因为界限也需要被现实到屏幕上,所以TileView需要继承android.view.View类。android.view.View类是描绘块状视图的基类。View会绘制一个包含Drawing是event事件的方形块。View是所有与用户交互的组件的Widgets的基类(Buttons,textField等),View的子类ViewGroup是layouts类的基类,layouts类可以包含其他的View/ViewGroup组件并且定义展示的属性。实现一个View,首先需要实现框架中一些所有Views公用的方法。不必重写所有所
22、有的方法,可以仅仅重写onDraw(android.graphics.Canvas)3.6.4 SnakeView类的设计SnakeView是本游戏的业务逻辑类,该类中包含了游戏数据和一些处理数据的方法以及一些内部类。SnakeView的方法摘要:1、 判断按键的方法在Android手机上,每个按键都会有一个唯一的键值与它对应,可以通过获得键值来判断哪个键被按下了并采取相应的动作。2、 设置提示信息的方法通过程序判断动态地设置用户提示信息,如游戏结束。3、 在随机位置出现食物的方法通过随机数在屏幕范围内随机出现一个食物,但是不允许同一时刻有两个食物存在。4、 刷新蛇的当前位置的方法主要用于刷新
23、蛇的当前位置5、 判断蛇是否吃到食物的方法因为食物和蛇都会有一个坐标,所以可以通过判断蛇头坐标是否跟食物坐标相等的方法来判断蛇是否吃到了食物。3.6.5 RefreshHandler类的设计RefreshHandler类需要处理是否需要重绘Snake,所以需要继承继承android.os.Handler类。Handler类允许你发送和处理和当前MessageQueue相关的Message类和Runnable类。每一个Handler类都和一个唯一的线程(以及这个线程的MessageQueue)关联。当你创建一个新的Handler类的时候,它就和创建它的Thread/Message Queue绑定
24、,也就是说这个Handler类会向它所关联的MessageQueue递送Messages/Runnables并且在该Message/Runnable从MessageQueue出列时候执行它。在这里我用来调度可能会被执行的Messages和Runnables。3.6.7逻辑处理开始始初化蛇和苹果屏幕显示蛇和苹果位置蛇开始移动,后坐标覆盖前坐标是否有按键否根据上次方向更新坐标是根据按键不同在原坐标基础上改变蛇的坐标位置更新方向是否吃到苹果是蛇身加1否是否越界或撞到蛇身是游戏结束否图3.53.7程序调试与运行(1)游戏功能测试经过在模拟器上的测试,本软件能书案例实现其功能,达到了小蛇在屏幕上的移动,
25、小蛇吃苹果,苹果随机出现的功能,当小蛇头尾相撞或与墙相撞时,游戏结束.这些均在测试中得到验证。(2)游戏控制测试在测试过程中,也着重对游戏的控制功能进行了测试,游戏是通过方向键的控制来实现的,在游戏刚开始的阶段,上下左右四个方位的控制都很成功,但随着蛇移动的速度越来越快,按键的控制反应会出现滞后,通过分析,可能是由于蛇的运动速度超过了键盘的反应速度造成的,与软件无关,所以得出结论,游戏的控制设计也是成功的。(3)游戏界面测试游戏运行之后,就是在画面中出现蛇和两个苹果的初始位置,并且是静止的,并且在画面上还会出现操作提示“按上键开始游戏”,游戏运行过程中,除了蛇的运动之外,界面大题没有变化,分别
26、由绿色矩形块的围墙,黄色矩形块的苹果和红色矩形块的蛇身(蛇头为黄色)组成。游戏结束后,界面处于暂停状态,提示游戏结束并显示分数。(4)测试结果通过对游戏软件的功能测试,控制测试和界面测试。详细说是对游戏的开始新游戏、退出、查看最高成绩、计时、统计分数等功能进行测试,并测试程序的鼠标点击事件、菜单的响应及按键响应等事件,结论是该游戏软件能正确实现功能要求。要求输出的效果与预期的输出效果完全一致。 图3.6 游戏前画面图3.7 游戏中界面图3.8 游戏结束时画面四 实验结果与分析(1)测试结果通过对游戏软件的功能测试,控制测试和界面测试。详细说是对游戏的开始新游戏、 退出、 查看最高成绩、 计时、
27、 统计分数等功能进行测试, 并测试程序的鼠标点击事件、菜单的响应及按键响应等事件,结论是该游戏软件能正确实现功能要求。要求输出的效果与预期的输出效果完全 一致。(2)分析回顾这个设计过程,我学到了许多书本上没有学到的知识。通过这次自己制作的软件,丰富了自己的实践技能,扩展了本专业的知识面,使我受益非浅,同时 也体验到了搞软件开发的困难度。 在这次设计的同时,我又从中学到了许多东西。 但由于我对这样的软件开发还只是一个开始,了解的不多,这其中或许还有很多 的不足,有些模块做得不是很好,界面的设计及整体的布局还比较简单,没有突 出特色出来,这也可能是我这个系统的不足之处,在这里也恳请老师能够对 我
28、的作品指明不足并加以改正。 我所做的设计功能并不算强大,但是这些结合了本学期所学习的内容,主要是界面的设计,并改写了两个类。通过自己写代码,我更进一步清楚了android工程的框架及设计的步骤,以及每个文件的作用,稍微掌握了一些View类的方法,同时也学到了更多的界面设计的方法,比如如何实现一个TextView里显示多行数据,如何自定义视图等。但同时我也遇到了问题,比如在编写控制模块代码的时候,如何何时按键监听这一块让我很头疼,另外在设计界面整体布局的时候,如何编写XML文件,这也是很大的问题后来通过查阅资料,对这些问题都做到了很好的解决总之,在这一次的课程设计过程中,我查阅了大量的资料,对
29、Java 有了一 点初步的认识,对于软件工程这些辅助性的教材也巩固了不少,为我这次的课设 提供了很大的帮助,锻炼了我的能力让我掌握了一门新的程序设计语言:java 语言,系统地学习了数据库方面的知识,并更进一步提高了我在程序设计、调试 方面的技巧。更重要的是,它还让我认识到了自己的不足,在编程方面,我仅仅 是刚刚入门而已,以后的道路任重道远,需要我不断的丰富自己、充实自己,这 样才能在程序设计方面有所收获。五、参考文献:1 沈泽刚,秦玉平.Java 语言程序设计M.清华大学出版社,2009 2 陈昊鹏同译者作品 .Java 编程思想(第 4 版).机械工业出版社,20073 耿祥义,张跃平.
30、Java 实用教程(第三版).清华大学出版社,2006六、附录一 代码清单TiltView.java/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http:/www.apach
31、e.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permis
32、sions and * limitations under the License. */package com.example.android.snake;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.uti
33、l.AttributeSet;import android.view.View;/* * TileView: a View-variant designed for handling arrays of icons or other * drawables. * */public class TileView extends View /* * Parameters controlling the size of the tiles and their range within view. * Width/Height are in pixels, and Drawables will be
34、scaled to fit to these * dimensions. X/Y Tile Counts are the number of tiles that will be drawn. */ protected static int mTileSize; protected static int mXTileCount; protected static int mYTileCount; private static int mXOffset; private static int mYOffset; /* * A hash that maps integer handles spec
35、ified by the subclasser to the * drawable that will be used for that reference */ private Bitmap mTileArray; /* * A two-dimensional array of integers in which the number represents the * index of the tile that should be drawn at that locations */ private int mTileGrid; private final Paint mPaint = n
36、ew Paint(); public TileView(Context context, AttributeSet attrs, int defStyle) super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView); mTileSize = a.getInt(R.styleable.TileView_tileSize, 12); a.recycle(); public TileView(Context context, Attribute
37、Set attrs) super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView); mTileSize = a.getInt(R.styleable.TileView_tileSize, 12); a.recycle(); /* * Rests the internal array of Bitmaps used for drawing tiles, and * sets the maximum index of tiles to be inserted *
38、* param tilecount */ public void resetTiles(int tilecount) mTileArray = new Bitmaptilecount; Override protected void onSizeChanged(int w, int h, int oldw, int oldh) mXTileCount = (int) Math.floor(w / mTileSize); mYTileCount = (int) Math.floor(h / mTileSize); mXOffset = (w - (mTileSize * mXTileCount)
39、 / 2); mYOffset = (h - (mTileSize * mYTileCount) / 2); mTileGrid = new intmXTileCountmYTileCount; clearTiles(); /* * Function to set the specified Drawable as the tile for a particular * integer key. * * param key * param tile */ public void loadTile(int key, Drawable tile) Bitmap bitmap = Bitmap.cr
40、eateBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); tile.setBounds(0, 0, mTileSize, mTileSize); tile.draw(canvas); mTileArraykey = bitmap; /* * Resets all tiles to 0 (empty) * */ public void clearTiles() for (int x = 0; x mXTileCount; x+) for (int y = 0; y
41、mYTileCount; y+) setTile(0, x, y); /* * Used to indicate that a particular tile (set with loadTile and referenced * by an integer) should be drawn at the given x/y coordinates during the * next invalidate/draw cycle. * * param tileindex * param x * param y */ public void setTile(int tileindex, int x, int y)