学android也将近一个月了。也练习了许多的功能点(比较分散)的代码,所以想做一个简单demo来把学习的总结一下。
我的思路很简单,一个敌人在上方左右移动,没两秒中向下发出一颗子弹,主角在下方,但是可以上下移动,并朝上方发射子弹。相互检查对方的子弹击中对方,如击中就判断出胜负,并且游戏结束。其中也运用到程序切割图片用来展示主角的上下左右移动时的动画。
游戏中用到了两张图片,主角和敌人共用一张,子弹一张
下面我将分别展示开发练习中所用到的类,以及代码。
动画类:MyAnimation.java
View Code
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 <frameCount; 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(切割图片的一个公用类)
View Code
/**
* 将一张图片分割
* @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
View Code
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 (x<BulletX&&x+frameW<BulletX) {
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
View Code
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
View Code
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
View Code
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;
/**
* 敌人的子弹
*/
Vector<Bullet> enemyBullets;
/**
* 主角的子弹
*/
Vector<Bullet> 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<Bullet>();
playerBullets = new Vector<Bullet>();
//设置焦点
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
View Code
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,努力实现敌人的智能设置,以及子弹方向的多元化设置(跟踪弹这种)。