学android也将近一个月了。也练习了许多的功能点(比较分散)的代码,所以想做一个简单demo来把学习的总结一下。
我的思路很简单,一个敌人在上方左右移动,没两秒中向下发出一颗子弹,主角在下方,但是可以上下移动,并朝上方发射子弹。相互检查对方的子弹击中对方,如击中就判断出胜负,并且游戏结束。其中也运用到程序切割图片用来展示主角的上下左右移动时的动画。
游戏中用到了两张图片,主角和敌人共用一张,子弹一张
下面我将分别展示开发练习中所用到的类,以及代码。
动画类:MyAnimation.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import java.io.InputStream; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; public class MyAnimation { /** * 帧动画的图片数组 */ Bitmap[] frameBitmaps; /** * 当前播放的图片帧ID */ int currentFrameID=0; /** * 是否循环播放 */ boolean isLoop; /** * 是否播放结束 */ boolean isEnd; /** * 帧动画图片的数量 */ int frameCount; /** * 上一次播放的时间 */ long lastPlayTime=0; /** * 每一帧的间隔时间 */ final int Anim_Time=100; /** * 构造 * @param context * @param FrameBitmapIDs 帧动画所需图片的资源ID数组 * @param IsLoop 是否循环播放 */ public MyAnimation(Context context,int[]FrameBitmapIDs,boolean IsLoop) { this.frameCount=FrameBitmapIDs.length; frameBitmaps=new Bitmap[frameCount]; for (int i = 0; i) { frameBitmaps[i]=ReadBitMap(context, FrameBitmapIDs[i]); } this.isEnd=true; this.isLoop=IsLoop; } /** * 构造 * @param context * @param framBitmaps 帧动画所需图片的bitmap数组 * @param IsLoop 是否循环播放 */ public MyAnimation(Context context, Bitmap[]framBitmaps,boolean IsLoop){ this.frameCount=framBitmaps.length; this.frameBitmaps=framBitmaps; this.isLoop=IsLoop; } /** * 绘制某一帧 * @param canvas * @param paint * @param x * @param y * @param PlayFrameID 某一帧所在数组的索引 */ public void DrawFrame(Canvas canvas,Paint paint,int x,int y,int PlayFrameID) { canvas.drawBitmap(frameBitmaps[PlayFrameID], x, y, paint); } /** * 绘制动画 * @param canvas * @param paint * @param x * @param y */ public void DrawAnimation(Canvas canvas,Paint paint,int x,int y) { if(!isEnd){ canvas.drawBitmap(frameBitmaps[currentFrameID], x, y, paint); long time=System.currentTimeMillis(); if(time-lastPlayTime>Anim_Time){ currentFrameID++; lastPlayTime=time; if(currentFrameID>=frameCount){//播放的是最后一帧 isEnd=true; if(isLoop){//是循环播放 isEnd=false; currentFrameID=0; } } } } } /** * 绘制动画 * @param bitmaps 动画集合 * @param canvas * @param paint * @param x * @param y */ public void DrawAnimation(Bitmap[] bitmaps,Canvas canvas,Paint paint,int x,int y) { if(!isEnd){ canvas.drawBitmap(frameBitmaps[currentFrameID], x, y, paint); long time=System.currentTimeMillis(); if(time-lastPlayTime>Anim_Time){ currentFrameID++; lastPlayTime=time; if(currentFrameID>=frameCount){//播放的是最后一帧 isEnd=true; if(isLoop){//是循环播放 isEnd=false; currentFrameID=0; } } } } } /** * 停止动画 */ public void StopAnimation() { isEnd=true; } /** * 开始动画 */ public void StartAnimation() { isEnd=false; } /** * 设置动画所需的bitmap数组 * @param bitmaps */ public void setBitmap(Bitmap[] bitmaps) { this.frameBitmaps=bitmaps; } /** * 读取图片资源 * @param context * @param resId * @return */ public static Bitmap ReadBitMap(Context context, int resId) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; // 获取资源图片 InputStream is = context.getResources().openRawResource(resId); return BitmapFactory.decodeStream(is, null, opt); } }
BitmapHelper.java(切割图片的一个公用类)
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
/** * 将一张图片分割 * @param bitmap 源图片 * @param Currentlengthways 当前所在的纵行 * @param crosswiseCount 横向的小图个数 * @param lengthwaysCount 纵向的小图个数 * @return */ public static Bitmap[] ClipBitmap(Bitmap bitmap,int Currentlengthways,int crosswiseCount,int lengthwaysCount) { Bitmap[] bitmaps=new Bitmap[crosswiseCount]; int frameW=bitmap.getWidth()/crosswiseCount; int frameH=bitmap.getHeight()/lengthwaysCount; for (int i = 0; i < crosswiseCount; i++) { bitmaps[i]=Bitmap.createBitmap(bitmap, i*frameW, (Currentlengthways-1)*frameH, frameW, frameH); } return bitmaps; }
主角类:Player.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.util.Log; import android.view.KeyEvent; public class Player { /** * 主角的x,y坐标 以及手机屏幕的宽高 */ int x,y,screenH,screenW; /** * 主角的移动速度 */ final int speed=3; /** * 主角所用的所有图片和当前使用的图片 */ Bitmap[] playBitmapDown,playBitmapUp,playBitmapLeft,playBitmapRight,playBitmapCurrent; /** * 主角的方向 */ boolean isUp=false,isDown=false,isLeft=false,isRight=false; /** * 检测主角是否发生了碰撞 */ boolean isCollsion; /** * 主角图片的宽高 */ int frameW,frameH; /** * 引用的动画类实例 */ MyAnimation animation; Context context; /** * 构造 * @param context * @param playBitmapDown 主角向下移动所需的bitmap数组 * @param playBitmapUp 主角向上移动所需的bitmap数组 * @param playBitmapLeft 主角向左移动所需的bitmap数组 * @param playBitmapRight 主角向右移动所需的bitmap数组 * @param x * @param y * @param screenW * @param screenH */ public Player(Context context,Bitmap[] playBitmapDown,Bitmap[] playBitmapUp,Bitmap[] playBitmapLeft,Bitmap[] playBitmapRight,int x,int y,int screenW,int screenH){ this.playBitmapDown=playBitmapDown; this.playBitmapUp=playBitmapUp; this.playBitmapLeft=playBitmapLeft; this.playBitmapRight=playBitmapRight; frameW=playBitmapDown[0].getWidth(); frameH=playBitmapDown[0].getHeight(); this.x=x; this.y=y; this.screenW=screenW; this.screenH=screenH; playBitmapCurrent=playBitmapUp; animation=new MyAnimation(context, playBitmapCurrent, true); Log.e("mygemebitmap",playBitmapCurrent.toString()); } /** * 绘制主角 * @param canvas * @param paint */ public void Draw(Canvas canvas,Paint paint) { canvas.save(); canvas.clipRect(x, y, x + frameW, y + frameH); animation.DrawFrame(canvas, paint, x, y, animation.currentFrameID); canvas.restore(); } /** * 玩家按钮向下操作主角 * @param keyCode */ public void onKeyDown(int keyCode) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_DOWN: isDown=true; Log.e("mygamedir", "向下"); animation.StartAnimation(); animation.setBitmap(playBitmapDown); break; case KeyEvent.KEYCODE_DPAD_UP: Log.e("mygamedir", "向上"); isUp=true; animation.StartAnimation(); animation.setBitmap(playBitmapUp); break; case KeyEvent.KEYCODE_DPAD_LEFT: Log.e("mygamedir", "向坐"); isLeft=true; animation.StartAnimation(); animation.setBitmap(playBitmapLeft); break; case KeyEvent.KEYCODE_DPAD_RIGHT: Log.e("mygamedir", "向右"); isRight=true; animation.StartAnimation(); animation.setBitmap(playBitmapRight); break; default: break; } } /** * 玩家按钮向上操作主角 * @param keyCode */ public void onKeyUp(int keyCode) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_DOWN: isDown=false; animation.StopAnimation(); break; case KeyEvent.KEYCODE_DPAD_UP: isUp=false; animation.StopAnimation(); break; case KeyEvent.KEYCODE_DPAD_LEFT: isLeft=false; animation.StopAnimation(); break; case KeyEvent.KEYCODE_DPAD_RIGHT: isRight=false; animation.StopAnimation(); break; default: break; } } /** * 业务逻辑 */ public void logic() { //判断移动方向 if(isDown){ y+=speed; } else if(isUp) { y-=speed; } else if(isLeft){ x-=speed; } else if (isRight) { x+=speed; } //超出边界 //判断屏幕X边界 if (x + frameW>= screenW) { x =screenW - frameW; } else if (x <= 0) { x = 0; } //判断屏幕Y边界 if (y +frameH >= screenH) { y = screenH - frameH; } else if (y <= 0) { y = 0; } } /** * 检测主角是否与子弹发生了碰撞 * @param bullet 子弹对象 * @return */ public boolean CheckCollsionWithBullet(Bullet bullet) { int BulletX=bullet.x; int BulletY=bullet.y; int BulletWidth=bullet.bulletBitmap.getWidth(); int BulletHeight=bullet.bulletBitmap.getHeight(); if(x>BulletX&&x>BulletX+BulletWidth){ isCollsion=false; } else if (xBulletX) { isCollsion=false; } else if (y >BulletY && y >= BulletY + BulletHeight) { isCollsion=false; } else if (y < BulletY && y + frameH < BulletY) { isCollsion=false; } else{ isCollsion=true; } return isCollsion; } }
敌人类:Enemy.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; /** * 敌人 */ public class Enemy { /** * 敌人的坐标以及屏幕的宽高 */ int x,y,screenH,screenW; /** * 敌人的所需图片 */ Bitmap[] enemyBitmap; boolean isCollsion; //是否发生碰撞 Context context; int frameW,frameH; MyAnimation animation; /** * 敌人移动的方向 1:向右,2:向左 */ int dir=1; /** * 构造 * @param enemyBitmap * @param x * @param y * @param screenW * @param screenH */ public Enemy(Context context,Bitmap[] enemyBitmap,int x,int y,int screenW,int screenH){ this.enemyBitmap=enemyBitmap; frameW=enemyBitmap[0].getWidth(); frameH=enemyBitmap[0].getHeight(); this.x=x; this.y=y; this.screenW=screenW; this.screenH=screenH; this.context=context; animation=new MyAnimation(context, enemyBitmap, true); } /** * 绘制敌人 * @param canvas * @param paint */ public void Draw(Canvas canvas,Paint paint) { canvas.save(); canvas.clipRect(x, y, x + frameW, y + frameH); animation.DrawFrame(canvas, paint, x, y, animation.currentFrameID); canvas.restore(); } /** * 业务逻辑 */ public void logic(){ if(x+frameW>=screenW){ //敌人到达右边界 就设置下次的移动方向是左 dir=2; } else if(x<=0){//敌人到达左边界 就设置下次的移动方向是右 dir=1; } //设置敌人的位置坐标 if(dir==1){ x++; } else if(dir==2){ x--; } //动画的设置 animation.currentFrameID++; if(animation.currentFrameID>=4){ animation.currentFrameID=0; } } /** * 检测敌人是否与子弹发生了碰撞 * @param bullet 子弹对象 * @return */ public boolean CheckCollsionWithBullet(Bullet bullet) { int BulletX=bullet.x; int BulletY=bullet.y; int BulletWidth=bullet.bulletBitmap.getWidth(); int BulletHeight=bullet.bulletBitmap.getHeight(); if(x>=BulletX&&x>=BulletX+BulletWidth){ isCollsion=false; } else if (x<=BulletX&&x+enemyBitmap[animation.currentFrameID].getWidth()<=BulletX) { isCollsion=false; } else if (y >=BulletY && y >= BulletY + BulletHeight) { isCollsion=false; } else if (y <= BulletY && y + enemyBitmap[animation.currentFrameID].getHeight() <= BulletY) { isCollsion=false; } else{ isCollsion=true; } return isCollsion; } }
子弹类:Bullet.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; /** * 子弹对象 */ public class Bullet { int x,y,screenH,screenW; Bitmap bulletBitmap; /** * 子弹的类型 */ int bullet_Type; /** * 子弹类型:是来自主角还是敌人 */ final int Bullet_Type_Player=1,Bullet_Type_Enemy=2; /** * 是否超出手机屏幕 */ boolean isDead; /** * 方向 */ int Dir; /* * 子弹的速度 */ int speed=5; //8方向常量 public static final int DIR_UP = 1,DIR_DOWN = 2, DIR_LEFT = 3,DIR_RIGHT = 4,DIR_UP_LEFT = 5,DIR_UP_RIGHT = 6,DIR_DOWN_LEFT = 7,DIR_DOWN_RIGHT = 8; /** * 构造 * @param bulletBitmap * @param x * @param y * @param bullet_Type 子弹类型:来自主角1,来自敌人2 * @param Dir 子弹的方向 * @param screenW * @param screenH */ public Bullet(Bitmap bulletBitmap,int x,int y,int bullet_Type,int Dir,int screenW,int screenH) { this.bulletBitmap=bulletBitmap; this.x=x; this.y=y; this.bullet_Type=bullet_Type; this.Dir=Dir; this.screenH=screenH; this.screenW=screenW; isDead=false; } /** * 绘制子弹 * @param canvas * @param paint */ public void Draw(Canvas canvas,Paint paint) { if(!isDead){ canvas.drawBitmap(bulletBitmap, x, y, paint); } } /** * 逻辑 */ public void logic() { if(Dir==DIR_DOWN){ y+=speed; } else if (Dir==DIR_LEFT) { x-=speed; } else if (Dir==DIR_RIGHT) { x+=speed; } else if (Dir==DIR_UP) { y-=speed; } //边界处理 if (y+bulletBitmap.getHeight() >screenH || y <=0 || x+bulletBitmap.getWidth()> screenW || x <= 0) { isDead = true; } } }
显示类: MySurfaceView.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import java.util.Vector; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.util.Log; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements Callback, Runnable { // 主角上线左右移动 Bitmap[] hero_DwonBitmaps; Bitmap[] hero_UpBitmaps; Bitmap[] hero_LeftBitmaps; Bitmap[] hero_RightBitmaps; // 敌人上下左右移动 Bitmap[] enemy_DwonBitmaps; Bitmap[] enemy_UpBitmaps; Bitmap[] enemy_LeftBitmaps; Bitmap[] enemy_RightBitmaps; Canvas canvas; Paint paint; SurfaceHolder surfaceHolder; Thread thread; boolean flag; /** * 主角和敌人共用了一张大图 */ Bitmap hero_enemy_bitmap; // 背景子弹图片 //Bitmap bgBitmap; Bitmap bulletBitmap; MyAnimation animation; Player player; Enemy enemy; /** * 敌人的子弹 */ VectorenemyBullets; /** * 主角的子弹 */ Vector playerBullets; /** * 最后一次发子弹的时间 */ long lastSendBulletTime; /** *是否胜利 1:进行中,2:胜利,3:失败了 */ int isWin=1; int screenW, screenH; int timesleep = 100;//刷新的间隔时间 /** * 构造 * @param context * @param screenW * @param screenH */ public MySurfaceView(Context context,int screenW,int screenH) { super(context); surfaceHolder = this.getHolder(); surfaceHolder.addCallback(this); paint = new Paint(); paint.setStyle(Style.STROKE); paint.setAntiAlias(true); paint.setColor(Color.RED); // 子弹 bulletBitmap = MyAnimation.ReadBitMap(context, R.drawable.bullet); // 主角与敌人公用的大图 hero_enemy_bitmap = MyAnimation.ReadBitMap(context, R.drawable.hero); // 主角 hero_DwonBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 1, 4, 4); hero_UpBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 4, 4, 4); hero_LeftBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 2, 4, 4); hero_RightBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 3, 4, 4); enemy_DwonBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 1, 4, 4); enemy_UpBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 4, 4, 4); enemy_LeftBitmaps = BitmapHelper.ClipBitmap(hero_enemy_bitmap, 2, 4, 4); enemy_RightBitmaps = BitmapHelper .ClipBitmap(hero_enemy_bitmap, 3, 4, 4); this.screenW =screenW; this.screenH =screenH; player = new Player(context,hero_DwonBitmaps,hero_UpBitmaps,hero_LeftBitmaps,hero_RightBitmaps, 200, 600,screenW,screenH); enemy = new Enemy(context, enemy_DwonBitmaps, 100, 100, screenW, screenH); enemyBullets = new Vector (); playerBullets = new Vector (); //设置焦点 this.setFocusable(true); this.setFocusableInTouchMode(true); } public void draw() { try { canvas = surfaceHolder.lockCanvas(); synchronized (canvas) { //canvas.drawBitmap(bgBitmap, 0, 0, paint); canvas.drawColor(Color.GRAY); player.Draw(canvas, paint); paint.setColor(Color.GREEN); canvas.drawText("这个是主角", player.x, player.y, paint); player.animation.DrawAnimation(canvas, paint, player.x, player.y); enemy.Draw(canvas, paint); paint.setColor(Color.RED); canvas.drawText("这个是敌人", enemy.x, enemy.y, paint); if(isWin==2){ paint.setTextSize(20); paint.setColor(Color.GREEN); canvas.drawText("我赢了", 10, 100, paint); Log.e("mygame","我赢了"); flag=false; } else if(isWin==3){ paint.setTextSize(20); paint.setColor(Color.RED); canvas.drawText("我输了", 10, 100, paint); Log.e("mygame","我输了"); flag=false; return; } for (Bullet bullet : enemyBullets) { //Log.e("mygame", "敌人子弹当前位置:"+bullet.x+"/"+bullet.y+"。玩家当前位置:"+player.x+"/"+player.y); bullet.Draw(canvas, paint); } for (Bullet bullet : playerBullets) { //Log.e("mygame", "玩家子弹当前位置:"+bullet.x+"/"+bullet.y+"。敌人当前位置:"+player.x+"/"+player.y); bullet.Draw(canvas, paint); } } } catch (Exception e) { Log.e("mygame", e.getMessage()); } finally { if (canvas != null) { surfaceHolder.unlockCanvasAndPost(canvas); } } } public void logic() { long time = System.currentTimeMillis(); if (time - lastSendBulletTime >= 2000) { lastSendBulletTime = time; Bullet bullet = new Bullet(bulletBitmap, enemy.x, enemy.y, 2, 2, screenW, screenH); enemyBullets.addElement(bullet); } player.logic(); enemy.logic(); for (int i = 0; i < enemyBullets.size(); i++) { Bullet bullet=enemyBullets.elementAt(i); if(player.CheckCollsionWithBullet(bullet)){ isWin=3; } if(bullet.isDead){ Log.e("mygame", "敌人子弹超屏,移出他"); enemyBullets.removeElement(bullet); } else{ bullet.logic(); } } for (int i = 0; i < playerBullets.size(); i++) { Bullet bullet=playerBullets.elementAt(i); if(enemy.CheckCollsionWithBullet(bullet)){ isWin=2; } if(bullet.isDead){ Log.e("mygame", "玩家子弹超屏,移出他"); playerBullets.removeElement(bullet); } else{ bullet.logic(); } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { player.onKeyDown(keyCode); if(keyCode==KeyEvent.KEYCODE_DPAD_CENTER){ Bullet bullet=new Bullet(bulletBitmap, player.x, player.y,1, 1, screenW, screenH); playerBullets.add(bullet); } return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { player.onKeyUp(keyCode); return true; } @Override public void run() { while (flag) { draw(); logic(); try { Thread.sleep(timesleep); } catch (Exception e) { Log.e("mygame", e.getMessage()); } } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub flag = true; thread = new Thread(this); thread.start(); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub flag = false; thread=null; System.exit(0); } }
MainActivity.java
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
import android.os.Bundle; import android.view.Display; import android.view.Window; import android.view.WindowManager; import android.app.Activity; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); Display display= getWindowManager().getDefaultDisplay(); setContentView(new MySurfaceView(this,display.getWidth(),display.getHeight())); } }
下一步,研究一下敌人的AI,努力实现敌人的智能设置,以及子弹方向的多元化设置(跟踪弹这种)。
还是附上源代码 附件下载