基于-an~droid地贪吃蛇游戏设计与-开发.doc
-_课 程 实 训 报 告课程名称课程名称 计算机系统综合实训计算机系统综合实训 课题名称课题名称 基于基于 Android 的贪吃蛇游戏开发的贪吃蛇游戏开发 专专 业业 计算机科学与技术计算机科学与技术 班班 级级 学学 号号 姓姓 名名 指导教师指导教师 2013 年年 12 月月 4 日日-_湖南工程学院课 程 实 训 任 务 书课程名称 计算机系统综合实训课 题 基于基于 Android 的贪吃蛇游戏开发的贪吃蛇游戏开发 专业班级 学生姓名 学 号 指导老师 审 批 任务书下达日期 2013 年 12 月 4 日任务完成日期 2013 年 12 月 20 日-_目录目录1、程序构思、程序构思.2 2、程序设计、程序设计.3 2.1 游戏功能.3 2.2 总设计模块的划分.4 2.3 游戏主界面模块.4 2.4 游戏控制模块.4 2.5 类模块设计.4 3、程序实现、程序实现.5 3.1、 游戏界面的实现.5 3.2、 游戏整个框架的构建.6 3.3、实现键盘响应事件.8 3.4、刷新.9 3.4、实现页面的切换.9 3.5、 加载游戏.9 3.6、游戏背景界面的改进.9 3.8、添加音效.10 3.9、游戏本身的完善.10 3、类模块具体设计、类模块具体设计.11TitleView.java.11 SnakeView.java.12 4.程序结果程序结果.14 5.总结与展望总结与展望.17 6. 附录附录.171、程序构思、程序构思贪吃蛇游戏是一款非常经典的手机游戏,贪吃蛇游戏的设计比较复杂,它涉及面广、 牵涉方面多,如果不好好考虑和设计,将难以成功开发出这个游戏。在这个游戏的设计中, 牵涉到图形界面的显示与更新、数据的收集与更新,并且在这个游戏的开发中,还要应用 类的继承机制以及一些设计模式。因此,在设计开发过程中,需要处理好各个类之间间的 逻辑依赖关系和数据通信关系。 正是因为如此,本次设计的目的在于学习 Java 程序设计基本技术,学习用 android 开发 Java 程序的相关技术,熟悉游戏“贪吃蛇”的需求,熟悉项目开发的完整过程。学会怎样 进行一个项目的需求分析、概要设计、详细设计等软件开发过程,熟练地掌握 Java 程序设 计的基本技术和方法,熟练地掌握 android 环境的使用方法,培养初步的项目分析能力和 程序设计能力。 -_2、程序设计、程序设计游戏设计的处理流程图游戏设计的处理流程图:开始初始化界面和蛇身放置食物蛇开始运动蛇吃到食?蛇长大蛇死亡?继续 续?退出界面NNYNY游戏者按键选择Y-_2.12.1 游戏功能游戏功能本系统主要完成以下几方面的功能: 游戏控制功能包括游戏的开始、暂停、退出 界面布局 其他辅助功能(如游戏帮助,游戏积分,游戏过关等)2.22.2 总设计模块的划分总设计模块的划分游戏总设计模块划分为游戏主要界面模块、游戏控制模块和游戏菜单模块。-_2.32.3 游戏主界面模块游戏主界面模块游戏主界面模块主要是指游戏的框图,其包括一下内容: 1、游戏界面的边界,即游戏中的墙; 2、游戏中蛇的构成,以及苹果的构成; 3、游戏中障碍物的构成; 4、游戏中分数显示以及关卡显示。2.42.4 游戏控制模块游戏控制模块(1)游戏开始控制: 我们的程序是使用上键开始游戏,启动游戏后会有一个初始菜单界面,我们点击“开始游 戏” ,弹出一句话“请按上键开始游戏” 。游戏开始后蛇向下移动,然后由控制上下左右键 来控制蛇的移动。 在程序中我们重新建了一个 activity 来控制游戏的开始,使游戏的开始 界面更美观。 (2)游戏暂停控制: 我们是使用 center 键来控制游戏的暂停的,这是一项人性化的设计,当玩家在游戏过程中 突遇紧急情况时可以按 center 键暂停游戏,等玩家空闲后按 center 键可以继续游戏。 (3)游戏退出控制: 在游戏的退出上我们的程序使用了多种方式来应对不同的情况,当玩家正在游戏中时,如 想退出可以按“1”键,程序会自动跳转到初始菜单界面,在初始菜单界面点击“退出游戏” 即可退出游戏。如果玩家在游戏中由于碰到墙或者咬到自己或者碰到障碍物而导致游戏结 束的,游戏或自动弹出一个界面,里面有提示是继续游戏还是退出游戏,当点击“取消” 时,游戏就会自动跳转到初始菜单,再点击“退出游戏”即可。2.52.5 类模块设计类模块设计src 源码目录:Snake.java 为主界面类; SnakeView 为贪吃蛇类的视图主要逻辑控制和绘制类; TitleView 为界面的整体视图; MenuActivity 为菜单类,可以跳转到 Help 类和 Snake 类; Help 为游戏帮助类。-_3、程序实现、程序实现3.13.1、 游戏界面的实现游戏界面的实现1、先声明用来存放绘画图像的 X,Y 轴的位置的数组:private int mTileGrid; 2、编写存放图片索引用图片的 X,Y 轴位置;public void setTile(int tileindex, int x, int y) mTileGridxy = tileindex; 3. 把图片素材加入到 bitmap 中 public void loadTile(int key, Drawable tile) Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap); tile.setBounds(0, 0, mTileSize, mTileSize);tile.draw(canvas);mTileArraykey = bitmap; 4、调用以上的方法以循环的方式位置数组赋值以及图片的索引, private void updateWalls() for (int x = 0; x 0) canvas.drawBitmap(mTileArraymTileGridxy,mXOffset + x * mTileSize,mYOffset + y * mTileSize, mPaint);同上可见: 整个界面其实就是由图片数组拼直面成的。到此,则可以实现游戏背景墙。-_3.23.2、 游戏整个框架的构建游戏整个框架的构建1 实现方案游戏的整个框架的构建包括基本的蛇身,苹果的实现,有两种方案: 方案一:使用常用的数组来存储蛇身和苹果的点集的信息。此方案的优点是对数组的操作 较为熟悉,实现简单,但是部分操作较为麻烦,有可能出现数组越界,或者浪费太多存储 空间。 方案二:使用动态数组 ArrayList 来存储蛇身和苹果点集的信息。ArrayList 可以用来定义为 各种不同类型的数组,不仅仅局限于 int 整型;而且 ArrayList 为用户编程提供了各种借口, 比如插入,删除元素,统计元素个数等,实现较为简单,不会出现数组越界的问题。 结合各种因素的考虑,我们在设计中采用第二种方案。定义 Position 方法,用于存储蛇身和苹果的点集坐标 private class Position /存储每个点的 坐标public int x;public int y;public Position(int xposition, int yposition) x = xposition;y = yposition;public boolean equals(int newx,int newy) if (x = newx return false; 定义 setMode 方法,用于表示游戏所处的几种状态:进行,暂停, public void setMode(int newMode) int oldMode = mMode; mMode = newMode; if(newMode = RUNNING 用于存储苹果的坐标位置根据游戏的需要,苹果的位置应该是随机产生的,使用 java.util.Random 类中提供的随机 数实现苹果坐标的随机。int newapplex = 2+random.nextInt(mYTileCount-2)-4);int newappley = 2+random.nextInt(mXTileCount-2)-4);-_newapple = new Position(newapplex,newappley);检测苹果坐标是否与蛇的坐标以及墙的左边冲突 设置冲突标志位:boolean flag = false; int snakelength = mSnakeTrail.size();for (int index = 0; index mAppleTrail = new ArrayList(); 用于存储苹果的坐标位置 蛇的初始化蛇身的初始化在 ininNewGame 中实现,直接把最初要呈现给玩家的蛇的情况定义出 来,即添加一定数量的坐标点进入 mSnakeTrail 中,使得在最初开始游戏时,有蛇可以进 行自由移动。蛇的移动游戏中是通过触发来改变坐标(+1,-1)的方式来改蛇头的方向,包括后面的蛇的碰 撞检测都要用到蛇头。 获取蛇的头部: Position head = mSnakeTrail.get(0);蛇的新头部: Position newHead = new Position(2,2);通过设置整型变量 mDirection 以及 mNextDirection 来判断蛇下一步移动方向,然后改变 蛇头的坐标,使蛇移动switch (mDirection) case EAST: newHead = new Position(head.x,head.y-1);break;. 蛇的碰撞检测 蛇在移动时,若碰撞到墙壁或者自己身体,则游戏结束。 蛇的碰壁检测:if(head.x mYTileCount-2) | (head.y > mXTileCount-2)setMode(LOSE);return;-_蛇的自身碰撞的检测:int wallength = mWallTrail.size(); for ( int wallindex = 0 ; wallindex mAppleList = new ArrayList())坐标集里面集依次判断,若是 坐标相同,那个这个苹果就被蛇吃了 。 找苹果的方法: int applecount = mAppleTrail.size(); int appleindex;for ( appleindex = 0; appleindex mSnakeTrail = new ArrayList(); private ArrayList mAppleTrail = new ArrayList(); private ArrayList mWallTrail = new ArrayList();private ArrayList mPoisonApple = new ArrayList();private ArrayList mLoveApple = new ArrayList();MediaPlayer mp=MediaPlayer.create(this.getContext(),R.raw.background);/相当于数组 大小可变 /* param context-_* param attrs*/class RefreshHandler extends Handler /每 600ms 刷新一次/* 响应消息*/Overridepublic void handleMessage(Message msg) update();invalidate();/消失 重新调用 on draw/* 向外提供人工的调用消息的接口* param delayMillis*/public void sleep(long delayMillis) /隔 600ms 重新调用这个函数this.removeMessages(0); sendMessageDelayed(obtainMessage(0), delayMillis);public SnakeView(Context context, AttributeSet attrs) super(context, attrs); setFocusable(true); ininSnakeView(); public void ininSnakeView()/初始化界面 Resources r = this.getContext().getResources(); resetTiles(6);loadTile(1, r.getDrawable(R.drawable.redstar); loadTile(2, r.getDrawable(R.drawable.yellowstar); loadTile(3, r.getDrawable(R.drawable.greenstar);loadTile(4,r.getDrawable(R.drawable.purplewstar);loadTile(5,r.getDrawable(R.drawable.favourite); private class Position /存储每个点的 坐标public int x;public int y;-_public Position(int xposition, int yposition) x = xposition;y = yposition;public boolean equals(int newx,int newy) if (x = newx return false; public void ininNewGame() mSnakeTrail.clear();mAppleTrail.clear(); mScore=0;stage=1;mSpeed=600;/初始化蛇的位置 mSnakeTrail.add(0,new Position(20,20); mSnakeTrail.add(1,new Position(19,20); mSnakeTrail.add(2,new Position(18,20); /初始化苹果的位置 Apple(); Poisonapple(); Loveapple(); mDirection = NORTH; mNextDirection = NORTH;public boolean onKeyDown(int keyCode,KeyEvent event)/键盘响应 mSpeed = 200;if(keyCode = KeyEvent.KEYCODE_DPAD_UP) if(mMode = READY | mMode = LOSE)ininNewGame(); -_setMode(RUNNING);update();mp.start();return (true);if(mMode = PAUSE)setMode(RUNNING);mp.start();return (true); if(mDirection != NORTH) mNextDirection = SOUTH; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_DOWN) if (mDirection != SOUTH) mNextDirection = NORTH; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_LEFT) if (mDirection != WEST) mNextDirection = EAST; return (true);if (keyCode = KeyEvent.KEYCODE_DPAD_RIGHT) if (mDirection != EAST) mNextDirection = WEST; return (true);if(keyCode = KeyEvent.KEYCODE_DPAD_CENTER)if(mCenterPressed = false) setMode(PAUSE);mp.pause();-_elsesetMode(RUNNING);mp.start();mCenterPressed = !mCenterPressed;if(keyCode = KeyEvent.KEYCODE_1)mUpdateFlag = false;mp.stop();Intent intent = new Intent(this.getContext(),MenuActivity.class);this.getContext().startActivity(intent);return super.onKeyDown(keyCode, event);Override public boolean onKeyUp(int keyCode, KeyEvent event) mSpeed = mNSpeed;if(keyCode = KeyEvent.KEYCODE_DPAD_UP) if(mDirection != NORTH) mNextDirection = SOUTH; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_DOWN) if (mDirection != SOUTH) mNextDirection = NORTH; return (true); if (keyCode = KeyEvent.KEYCODE_DPAD_LEFT) if (mDirection != WEST) mNextDirection = EAST; return (true);-_if (keyCode = KeyEvent.KEYCODE_DPAD_RIGHT) if (mDirection != EAST) mNextDirection = WEST; return (true); / TODO Auto-generated method stub return super.onKeyUp(keyCode, event); public void setMode(int newMode) int oldMode = mMode; mMode = newMode; String str = “; if(newMode = RUNNING mUpdateFlag =true; textView1.setVisibility(View.INVISIBLE); update(); return; if(newMode = PAUSE) str = “按暂停键继续开始“;mUpdateFlag = false; if(newMode = LOSE) str = “游戏结束,按上键重新开始“; mUpdateFlag = false; showRightorNot = new AlertDialog.Builder(this.getContext(); showRightorNot.setIcon(R.drawable.icon); showRightorNot.setTitle(“贪吃蛇“); showRightorNot.setPositiveButton(“确定“, this); showRightorNot.setNegativeButton(“取消“, this); showRightorNot.setMessage(“按确定继续,按取消退出游戏“).show(); mp.stop(); mp.prepareAsync(); if(newMode = READY)-_ mp.start(); str = “按上键开始游戏“; textView1.setText(str); textView1.setVisibility(View.VISIBLE); public void update() if(mUpdateFlag) clearTiles(); updateWalls(); updateSnake(); updateApple(); re.sleep(mSpeed); public void updateWalls() for (int x = 0; x mYTileCount-2) |(newHead.y > mXTileCount-2)setMode(LOSE);return;/蛇自身冲撞检测 int snakelength = mSnakeTrail.size(); for (int snakeindex = 0; snakeindex < snakelength; snakeindex+) Position c = mSnakeTrail.get(snakeindex); if (c.equals(newHead.x,newHead.y) setMode(LOSE);return;/蛇与障碍物的冲撞检测 int wallength = mWallTrail.size(); for ( int wallindex = 0 ; wallindex < wallength; wallindex+)、-_Position c = mWallTrail.get(wallindex); if (c.equals(newHead.x,newHead.y) setMode(LOSE);return;/找苹果 int applecount = mAppleTrail.size();String str1 = “ 分数:“; int appleindex;for ( appleindex = 0; appleindex < applecount; appleindex+) Position c = mAppleTrail.get(appleindex);if (c.equals(newHead.x,newHead.y) /找到苹果 mAppleTrail.remove(c); Apple();mScore+;if(mScore%3=0)mSpeed *=0.95; mNSpeed = mSpeed;stage+;Apple();Poisonapple();Loveapple(); Snakegrow = true;textView2.setText(str1+ mScore + “ 按数字键“1”退出游戏“);String str2=“第 “ + stage + “ 关“; textView3.setText(str2);/毒苹果处理方法 int posioncount = mPoisonApple.size(); for (int index = 0; index < posioncount; index+) Position c = mPoisonApple.get(index); if (c.equals(newHead.x,newHead.y) /找到苹果-_ mPoisonApple.remove(c); mScore = mScore - 3; mSpeed *= 0.8; int lovecount = mLoveApple.size(); for (int index = 0; index < lovecount; index+) Position c = mLoveApple.get(index);if (c.equals(newHead.x,newHead.y) /找到苹果 mLoveApple.remove(c);mScore = mScore + 5;mSpeed /= 0.8; Obstacle(); /将蛇头的位置信息放在第一个的对象中方取值mSnakeTrail.add(0, newHead);if(!Snakegrow) mSnakeTrail.remove(mSnakeTrail.size() - 1); for (Position c : mSnakeTrail) setTile(2, c.x, c.y); /随即产生苹果private void Apple() Position newapple = null;boolean collision =false;while( !collision )/为随即苹果添加一个随即位置 int newapplex = 2+random.nextInt(mYTileCount-2)-4);int newappley = 2+random.nextInt(mXTileCount-2)-4);newapple = new Position(newapplex,newappley);/检查苹果的坐标是否与蛇的冲突-_boolean flag = false;/冲突标志位int snakelength = mSnakeTrail.size();for (int index = 0; index < snakelength; index+) if (mSnakeTrail.get(index).equals(newapple.x,newapple.y) flag = true; int wallength = mWallTrail.size();for (int index = 0; index < wallength; index+) if (mWallTrail.get(index).equals(newapple.x,newapple.y) flag = true; collision = !flag; /把 apple 的坐标添加到 appleTrail 中 mAppleTrail.add(newapple); private void Poisonapple() mPoisonApple.clear();Position newapoison = null;boolean collision1 =false;boolean collision2 =false;while(!collision1 int newapoisony = 2+random.nextInt(mXTileCount-2)-4);newapoison = new Position(newapoisonx,newapoisony);/检查苹果的坐标是否与蛇的冲突boolean flags = false;/冲突标志位boolean flagw = false;int snakelength = mSnakeTrail.size();for (int index = 0; index < snakelength; index+) -_if (mSnakeTrail.get(index).equals(newapoison.x,newapoison.y) flags = true; collision1 = !flags;int wallength = mWallTrail.size();for (int index = 0; index < wallength; index+) if (mWallTrail.get(index).equals(newapoison.x,newapoison.y) flagw = true;collision2 = !flagw; /把 apple 的坐标添加到 appleTrail 中