Android植物大战僵尸小游戏

植物大战僵尸小游戏,无论老少皆爱,非常有意思,具有挑战性,那么基于代码是怎么实现的呢?下面通过本文给大家介绍Android植物大战僵尸小游戏,感兴趣的朋友一起学习吧

Android植物大战僵尸小游戏全部内容如下:

相关下载:Android植物大战僵尸小游戏

具体代码如下所示:

 package com.example.liu.mygame; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.tools.DeviceTools; import com.example.liu.mygame.view.GameView; import android.os.Bundle; import android.app.Activity; import android.graphics.BitmapFactory; import android.view.Menu; import android.view.MotionEvent; public class MainActivity extends Activity { private GameView gameview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); init(); gameview = new GameView(this); setContentView(gameview); } // 初始化游戏资源 private void init() { // TODO Auto-generated method stub // 获取屏幕大小尺寸 Config.deviceWidth = DeviceTools.getDeviceInfo(this)[0]; Config.deviceHeight = DeviceTools.getDeviceInfo(this)[1]; // 得到原始图片 Config.gameBK = BitmapFactory.decodeResource(getResources(), R.drawable.bk); // 获取缩放比 Config.scaleWidth = Config.deviceWidth / (float) Config.gameBK.getWidth(); Config.scaleHeight = Config.deviceHeight / (float) Config.gameBK.getHeight(); // 处理图片让它成为目标图片 Config.gameBK = DeviceTools.resizeBitmap(Config.gameBK); Config.seedBank = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.seedbank)); // 绘制出卡片,不能进行等比缩放要进行目标大小的输入控制 Config.seedFlower = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.seed_flower), Config.seedBank.getWidth() / 10, Config.seedBank.getHeight() * 8 / 10); Config.seedPea = DeviceTools.resizeBitmap(BitmapFactory.decodeResource( getResources(), R.drawable.seed_pea), Config.seedBank .getWidth() / 10, Config.seedBank.getHeight() * 8 / 10); // 初始化阳光图片 Config.sun = DeviceTools.resizeBitmap(BitmapFactory.decodeResource( getResources(), R.drawable.sun)); // 初始化子弹图片 Config.bullet = DeviceTools.resizeBitmap(BitmapFactory.decodeResource( getResources(), R.drawable.bullet)); // 初始化gameOver图片 Config.gameOver = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.gameover)); // 初始化动态图片帧 Config.flowerFrames[0] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_01)); Config.flowerFrames[1] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_02)); Config.flowerFrames[2] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_03)); Config.flowerFrames[3] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_04)); Config.flowerFrames[4] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_05)); Config.flowerFrames[5] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_06)); Config.flowerFrames[6] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_07)); Config.flowerFrames[7] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_1_08)); Config.peaFrames[0] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_01)); Config.peaFrames[1] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_02)); Config.peaFrames[2] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_03)); Config.peaFrames[3] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_04)); Config.peaFrames[4] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_05)); Config.peaFrames[5] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_06)); Config.peaFrames[6] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_07)); Config.peaFrames[7] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.p_2_08)); Config.zombieFrames[0] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_01)); Config.zombieFrames[1] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_02)); Config.zombieFrames[2] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_03)); Config.zombieFrames[3] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_04)); Config.zombieFrames[4] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_05)); Config.zombieFrames[5] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_06)); Config.zombieFrames[6] = DeviceTools.resizeBitmap(BitmapFactory .decodeResource(getResources(), R.drawable.z_1_07)); } // 重写onTouch触摸响应事件,返回值为gameview中生成的onTouch事件值 @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub return gameview.onTouchEvent(event); } // 销毁 @Override protected void onDestroy() { super.onDestroy(); } // 停止 @Override protected void onPause() { super.onPause(); } // 重启 @Override protected void onResume() { super.onResume(); } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; public class Bullet extends BaseModel { // 位置 private int locationX; private int locationY; // 生命 private boolean isAlife; // 子弹产生时间 private long birthTime = 0l; // X方向上的速度分量 // 根据帧数,确定移动时间,然后来确定移动方式 private float SpeedX = 10; public Bullet(int locationX, int locationY) { this.locationX = locationX + 40; this.locationY = locationY + 20; this.isAlife = true; // 获取系统时间 birthTime = System.currentTimeMillis(); } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { // 移动 locationX += SpeedX; // 如果图片的Y轴坐标移动到超出屏幕或者说移动到与屏幕齐平,那么生命周期结束 if (locationX > Config.deviceWidth) { // 去除子弹 isAlife = false; } } canvas.drawBitmap(Config.bullet, locationX, locationY, paint); } @Override public int getModelWidth() { // TODO Auto-generated method stub return Config.bullet.getWidth(); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.view.MotionEvent; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.TouchAble; import com.example.liu.mygame.view.GameView; public class EmplaceFlower extends BaseModel implements TouchAble { private int locationX; private int locationY; // 生命 private boolean isAlife; // 触摸区域(矩形) private Rect touchArea; public EmplaceFlower(int locationX, int locationY) { this.locationX = locationX; this.locationY = locationY; this.isAlife = true; // 初始化触摸响应矩形区域,与整体屏幕一致大小 touchArea = new Rect(0, 0, Config.deviceWidth, Config.deviceHeight); } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { canvas.drawBitmap(Config.flowerFrames[0], locationX, locationY, paint); } } @Override public boolean onTouch(MotionEvent event) { // TODO Auto-generated method stub int x = (int) event.getX(); int y = (int) event.getY(); // 如果点击的地方是在矩形区域内,那么开始设置跟随 if (touchArea.contains(x, y)) { // 图标跟随 // switch中需要相应三个事件:按下、抬起、拖动 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: // drawSelf方法已定,那么我们需要改变表示位置的两个变量,同时也要改变响应点击的区域touchArea locationX = x - Config.flowerFrames[0].getWidth() / 2; locationY = y - Config.flowerFrames[0].getHeight() / 2; break; case MotionEvent.ACTION_UP: // 放手以后此移动中的实例的生命周期结束并在特定点产生新的固定的实例 isAlife = false; // 交由GameView处理 GameView.getInstance().applay4Plant(locationX, locationY, this); break; } } return false; } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.view.MotionEvent; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.TouchAble; import com.example.liu.mygame.view.GameView; public class EmplacePea extends BaseModel implements TouchAble { private int locationX; private int locationY; // 生命 private boolean isAlife; // 触摸区域(矩形) private Rect touchArea; public EmplacePea(int locationX, int locationY) { this.locationX = locationX; this.locationY = locationY; this.isAlife = true; // 初始化触摸响应矩形区域 touchArea = new Rect(0, 0, Config.deviceWidth, Config.deviceHeight); } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { canvas.drawBitmap(Config.peaFrames[0], locationX, locationY, paint); } } @Override public boolean onTouch(MotionEvent event) { // TODO Auto-generated method stub int x = (int) event.getX(); int y = (int) event.getY(); // 如果点击的地方是在矩形区域内,那么开始设置跟随 if (touchArea.contains(x, y)) { // 图标跟随 // switch中需要相应三个事件:按下、抬起、拖动 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: // drawSelf方法已定,那么我们需要改变表示位置的两个变量,同时也要改变响应点击的区域touchArea locationX = x - Config.peaFrames[0].getWidth() / 2; locationY = y - Config.peaFrames[0].getHeight() / 2; break; case MotionEvent.ACTION_UP: // 放手以后此移动中的实例的生命周期结束并在特定点产生新的固定的实例 isAlife = false; // 交由GameView处理 GameView.getInstance().applay4Plant(locationX, locationY, this); break; } } return false; } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.Plant; import com.example.liu.mygame.view.GameView; //豌豆射手实体类 public class Flower extends BaseModel implements Plant { private int locationX; private int locationY; private boolean isAlife; // 图片帧数组的下标 private int frameIndex = 0; // 一个标记通过此标记确定此处是否有植物 private int mapIndex; // 控制产生阳光的时间 private long lastBirthTime; // 摆动速度控制,两帧一动 private boolean swingSpeed; public Flower(int locationX, int locationY, int mapIndex) { this.locationX = locationX; this.locationY = locationY; this.mapIndex = mapIndex; isAlife = true; // 初始化时间用来确保初试时间与花的创造时间一致 lastBirthTime = System.currentTimeMillis(); swingSpeed = false; } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { // 这里绘入的bitmap就需要在绘制自己的时候换自己的帧动画以形成动态效果 // 这个组在Config中已经初始化好了 canvas.drawBitmap(Config.flowerFrames[frameIndex], locationX, locationY, paint); // 用此变量让数组变化 // 通过这样的取模方法,可以让这个frameIndex值不超过7 // 当frameIndex为8时会变为0,避免数组越界 if (!swingSpeed) { frameIndex = (++frameIndex) % 8; swingSpeed = false; } else { swingSpeed = true; } // 用此处判断来确定每10秒一个阳光的产生 if (System.currentTimeMillis() - lastBirthTime > 10000) { lastBirthTime = System.currentTimeMillis(); giveBirth2Sun(); } } } // 产生阳光 // 阳光具有生命,然后两种情况,被点击则转换状态,移动到上方阳光的标志处,过一段时间不点击则死亡消失 // 产生在花的位置上 private void giveBirth2Sun() { // 首先要有阳光的图层集合,处于第三层,那么就需要操作集合,就需要调用GameView.getInstance GameView.getInstance().giveBrith2Sun(locationX, locationY); } @Override public int getModelWidth() { // TODO Auto-generated method stub return Config.flowerFrames[0].getWidth(); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } @Override public int getmapIndex() { // TODO Auto-generated method stub return mapIndex; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.util.Log; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.Plant; import com.example.liu.mygame.view.GameView; //豌豆射手实体类 public class Pea extends BaseModel implements Plant { private int locationX; private int locationY; private boolean isAlife; // 图片帧数组的下标 private int frameIndex = 0; // 一个标记通过此标记确定此处是否有植物 private int mapIndex; // 控制产生子弹的时间 private long lastBirthTime; // 摆动速度控制,两帧一动 private boolean swingSpeed; public Pea(int locationX, int locationY, int mapIndex) { this.locationX = locationX; this.locationY = locationY; this.mapIndex = mapIndex; isAlife = true; swingSpeed = false; } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { // 这里绘入的bitmap就需要在绘制自己的时候换自己的帧动画以形成动态效果 // 这个组在Config中已经初始化好了 canvas.drawBitmap(Config.peaFrames[frameIndex], locationX, locationY, paint); // 用此变量让数组变化 // 通过这样的取模方法,可以让这个frameIndex值不超过7 // 当frameIndex为8时会变为0,避免数组越界 if (!swingSpeed) { frameIndex = (++frameIndex) % 8; swingSpeed = false; } else { swingSpeed = true; } // 用此处判断来确定每10秒一个子弹的产生 if (System.currentTimeMillis() - lastBirthTime > 10000) { lastBirthTime = System.currentTimeMillis(); giveBirth2Bullet(); } } } // 产生子弹 // 子弹具有生命,然后两种情况,被点击则转换状态,移动到上方子弹的标志处,过一段时间不点击则死亡消失 // 产生在花的位置上 private void giveBirth2Bullet() { // 首先要有子弹的图层集合,处于第三层,那么就需要操作集合,就需要调用GameView.getInstance GameView.getInstance().giveBirth2Bullet(locationX, locationY); } @Override public int getModelWidth() { // TODO Auto-generated method stub return Config.peaFrames[0].getWidth(); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } @Override public int getmapIndex() { // TODO Auto-generated method stub return mapIndex; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.Log; import android.view.MotionEvent; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.TouchAble; import com.example.liu.mygame.view.GameView; public class SeedFlower extends BaseModel implements TouchAble { private int locationX; private int locationY; // 生命 private boolean isAlife; // 触摸区域(矩形) private Rect touchArea; public SeedFlower(int locationX, int locationY) { this.locationX = locationX; this.locationY = locationY; this.isAlife = true; // 初始化触摸响应矩形区域 touchArea = new Rect(locationX, locationY, locationX + Config.seedFlower.getWidth(), locationY + Config.seedFlower.getHeight()); } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { canvas.drawBitmap(Config.seedFlower, locationX, locationY, paint); } } @Override public boolean onTouch(MotionEvent event) { // TODO Auto-generated method stub // 获取并传入触摸的X,Y坐标,getX() getY()获取到的数据都是float型 int x = (int) event.getX(); int y = (int) event.getY(); if (touchArea.contains(x, y)) { // 当触摸点落在区域内则响应 // 生成安置状态的花(优先级最高) if (Config.sunlight >= 50) { applay4EmplaceFlower(); return true; } } return false; } // 通过GameView来请求生成一个安置状态的花(优先级最高) private void applay4EmplaceFlower() { // TODO Auto-generated method stub GameView.getInstance().applay4EmplacePlant(locationX, locationY, this); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.Log; import android.view.MotionEvent; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.TouchAble; import com.example.liu.mygame.view.GameView; public class SeedPea extends BaseModel implements TouchAble { private int locationX; private int locationY; // 生命 private boolean isAlife; // 触摸区域(矩形) private Rect touchArea; public SeedPea(int locationX, int locationY) { this.locationX = locationX; this.locationY = locationY; this.isAlife = true; // 初始化触摸响应矩形区域 touchArea = new Rect(locationX, locationY, locationX + Config.seedPea.getWidth(), locationY + Config.seedPea.getHeight()); } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { canvas.drawBitmap(Config.seedPea, locationX, locationY, paint); } } @Override public boolean onTouch(MotionEvent event) { // TODO Auto-generated method stub // 获取并传入触摸的X,Y坐标,getX() getY()获取到的数据都是float型 int x = (int) event.getX(); int y = (int) event.getY(); if (touchArea.contains(x, y)) { // 当触摸点落在区域内则响应 // 生成安置状态的豌豆(优先级最高) if (Config.sunlight >= 100) { applay4EmplacePea(); return true; } } return false; } // 通过GameView来请求生成一个安置状态的豌豆(优先级最高) private void applay4EmplacePea() { // TODO Auto-generated method stub GameView.getInstance().applay4EmplacePlant(locationX, locationY, this); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.view.MotionEvent; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.TouchAble; public class Sun extends BaseModel implements TouchAble { // 位置 private int locationX; private int locationY; // 生命 private boolean isAlife; // 可触摸区域 private Rect touchArea; // 阳光产生时间 private long birthTime; // 标示阳光的状态 private SunState state; // 移动距离 private int DirectionDistanceX; private int DirectionDistanceY; // XY方向上的速度分量 // 根据帧数,确定移动时间,然后来确定移动方式 private float SpeedX; private float SpeedY; // 用此枚举来标示阳光的状态 // 两个状态:静止、移动 // 移动过程中生命周期对阳光无效,静止时生命周期有效 public enum SunState { SHOW, MOVE } public Sun(int locationX, int locationY) { this.locationX = locationX; this.locationY = locationY; this.isAlife = true; // 初始化触摸响应矩形区域 // 对于每个阳光来说能出没的地方只有他这张图片大小的区域 touchArea = new Rect(locationX, locationY, locationX + Config.sun.getWidth(), locationY + Config.sun.getHeight()); // 获取系统时间 birthTime = System.currentTimeMillis(); // 初始实例化为SHOW状态 state = SunState.SHOW; } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (isAlife) { if (state == SunState.SHOW) { // 判断当前系统时间如果比出生时间大5000毫秒那么阳光生命结束,消失 if (System.currentTimeMillis() - birthTime > Config.lifeTime) { isAlife = false; } } else {// 对于move状态的阳光的处理 // 移动 locationX -= SpeedX; locationY -= SpeedY; // 如果图片的Y轴坐标移动到超出屏幕或者说移动到与屏幕齐平,那么生命周期结束 if (locationY <= 0) { // 去除阳光 isAlife = false; // 改变阳光值 Config.sunlight += 25; } } canvas.drawBitmap(Config.sun, locationX, locationY, paint); } } // 触摸事件响应 @Override public boolean onTouch(MotionEvent event) { // TODO Auto-generated method stub // 获取触摸点 int x = (int) event.getX(); int y = (int) event.getY(); // 如果触摸点在可触摸区域内 if (touchArea.contains(x, y)) { // 开始运动并且不可被点击,同时可能会与上边框产生碰撞事件 // 移动过程中也需要时间,如果这个收集时间中用了超过阳光生命值5秒的时间 // 那么我们需要在点击以后改变阳光的状态并删除原本的静态阳光 state = SunState.MOVE; // 改变状态以后,那么就要开始移动,移动的起点不一定,但是终点是一定的 // 移动的终点可以认为是条形框(seedBank)的左上角点 // 起始点就是此阳光图片的左上角 // XY方向上的移动距离 DirectionDistanceX = locationX - Config.seedBankLocationX; DirectionDistanceY = locationY; // 移动速度分量的计算,具体帧数需要项目分析,这里设置为20帧 SpeedX = DirectionDistanceX / 20f; SpeedY = DirectionDistanceY / 20f; return true; } return false; } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.view.GameView; public class Zombie extends BaseModel { private int locationX; private int locationY; private boolean isAlife; // 僵尸位于的跑道,因为此僵尸只跟其所在的跑道内的植物、子弹等进行碰撞检测 private int raceWay; // 因为僵尸是移动中的 所以他要有动画帧的下标 private int frameIndex = 0; // 移动速度,每一帧移动3像素 private int peedX = 3; public Zombie(int locationX, int locationY, int raceWay) { this.locationX = locationX; this.locationY = locationY; isAlife = true; this.raceWay = raceWay; } // 在某跑道随机产生僵尸,同时间隔一段时间出现一只僵尸 @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub if (locationX <0) { Config.game = false; } if (isAlife) { canvas.drawBitmap(Config.zombieFrames[frameIndex], locationX, locationY, paint); frameIndex = (++frameIndex) % 7; locationX -= peedX; // 碰撞检测,僵尸发起的此碰撞检测 GameView.getInstance().checkCollision(this, raceWay); } } @Override public int getModelWidth() { // TODO Auto-generated method stub return Config.zombieFrames[0].getWidth(); } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.entity; import android.graphics.Canvas; import android.graphics.Paint; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.view.GameView; public class ZombieManager extends BaseModel { // 一般需要显示出现在屏幕上的实体才需要继承BaseModel // 所以此处的僵尸控制器其实不需要继承BaseModel // 但是为了与之前的flower和pea产生器相统一 // 效仿以前的模式减少工作量 // 在这里也进行继承 private boolean isAlife; // 最后一只僵尸的产生时间 private long lastBirthTime; public ZombieManager() { lastBirthTime = System.currentTimeMillis(); isAlife = true; } @Override public void drawSelf(Canvas canvas, Paint paint) { // TODO Auto-generated method stub // 此处不需要绘制出图片,所以不需要draw,但是可以进行逻辑上的处理 if (System.currentTimeMillis() - lastBirthTime > 15000) { lastBirthTime = System.currentTimeMillis(); giveBirth2Zombie(); } } private void giveBirth2Zombie() { // 与GameView请求加入僵尸 GameView.getInstance().apply4AddZombie(); } } package com.example.liu.mygame.global; import java.util.HashMap; import android.graphics.Bitmap; import android.graphics.Point; //常量 public class Config { public static float scaleWidth; public static float scaleHeight; public static int deviceWidth; public static int deviceHeight; public static Bitmap gameBK; public static Bitmap seedBank; public static Bitmap gameOver; // seedBank的位置X坐标 public static int seedBankLocationX; public static Bitmap seedFlower; public static Bitmap seedPea; // 阳光 public static Bitmap sun; // 阳光的生存时间5000毫秒 public static long lifeTime = 5000; // 现在的阳光值 public static int sunlight = 200; // 僵尸和植物图片的高度差 public static int heightYDistance; // 子弹 public static Bitmap bullet; // 将图片帧放入数组 public static Bitmap[] flowerFrames = new Bitmap[8]; public static Bitmap[] peaFrames = new Bitmap[8]; public static Bitmap[] zombieFrames = new Bitmap[7]; // 放置植物的点 public static HashMap plantPoints = new HashMap(); // 跑道 public static int[] raceWayYpoints = new int[5]; // 输赢判断标志 public static boolean game = true; } package com.example.liu.mygame.model; import android.graphics.Canvas; import android.graphics.Paint; public class BaseModel { // 基础类,对于所有能展示在屏幕上的动态对象都要继承自此类 // 位置 private int locationX; private int locationY; // 生命 private boolean isAlife; // 绘制自己,即移动 public void drawSelf(Canvas canvas, Paint paint) { } public int getModelWidth() { return 0; } public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public boolean isAlife() { return isAlife; } public void setAlife(boolean isAlife) { this.isAlife = isAlife; } } package com.example.liu.mygame.model; // 所有需要种植在地上保持静止的植物都要有这个接口 public interface Plant { // 用于key public int getmapIndex(); } package com.example.liu.mygame.model; import android.view.MotionEvent; public interface TouchAble { // 对于能接受触摸事件的对象的一个公用接口 // 传入MotionEvent事件 public boolean onTouch(MotionEvent event); } package com.example.liu.mygame.tools; import com.example.liu.mygame.global.Config; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Matrix; import android.util.DisplayMetrics; import android.util.Log; public class DeviceTools { private static int[] deviceWidthHeight = new int[2]; // 重新设置Bitmap的大小 public static Bitmap resizeBitmap(Bitmap bitmap) { if (bitmap != null) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Log.i("info", width + "," + height); Matrix matrix = new Matrix(); matrix.postScale(Config.scaleWidth, Config.scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return resizedBitmap; } else { return null; } } // 重载 // 原因是找到的素材需要进行处理来适应手机屏幕,等比操作,但是如果合成的两张材料图不成比例 那么就不得不用这种重载来适应 // 首先传入一个bitmap和期望的宽高 public static Bitmap resizeBitmap(Bitmap bitmap, int w, int h) { if (bitmap != null) { // 获取传入的图片宽高 int width = bitmap.getWidth(); int height = bitmap.getHeight(); // 传入期望的宽高 int newWidth = w; int newHeight = h; // 缩放比 float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // 图片矩阵对象,3X3矩阵 Matrix matrix = new Matrix(); // 把缩放比传入期望矩阵 matrix.postScale(scaleWidth, scaleHeight); // 生成期望的图片 Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return resizeBitmap; } else { return null; } } // 获取屏幕的宽高 // 在DisplayMetrics类中可以获取屏幕的亮度,宽高,刷新率等相关信息 public static int[] getDeviceInfo(Context context) { if ((deviceWidthHeight[0] == 0) && (deviceWidthHeight[1] == 0)) { DisplayMetrics metrics = new DisplayMetrics(); ((Activity) context).getWindowManager().getDefaultDisplay() .getMetrics(metrics); deviceWidthHeight[0] = metrics.widthPixels; deviceWidthHeight[1] = metrics.heightPixels; } return deviceWidthHeight; } } package com.example.liu.mygame.view; import java.util.ArrayList; import com.example.liu.mygame.R; import com.example.liu.mygame.entity.*; import com.example.liu.mygame.global.Config; import com.example.liu.mygame.model.BaseModel; import com.example.liu.mygame.model.Plant; import com.example.liu.mygame.model.TouchAble; import android.R.bool; import android.R.integer; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Typeface; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; //对于这种有赛道的游戏可以用以下方法 //对于那种可以上下移动的游戏可以把所有精灵放在一个集合里 不用分图层 每次绘制的时候要按照Y坐标进行排序 //对于先画出来的肯定是排在前面的 所以Y最小的排在前面即离屏幕上边缘最近的精灵 //那种游戏肯定会通过游戏引擎来进行开发 public class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private Canvas canvas; private Paint paint; private SurfaceHolder surfaceHolder; private boolean gameRunFlag; private Context context;// 用于存放图片地址 // 把GameView当做总管理,所有的实体都向这里发送请求并处理 private static GameView gameView; private ArrayList deadList;// 存放已消亡的实体,在拖动放手后实体会不显示,但是还存在所以要进行清理 private ArrayList gameLayout3;// 存放第三图层中的实体; private ArrayList gameLayout2;// 存放第二图层中的实体 private ArrayList gameLayout1;// 存放第一图层中的实体 // 跑道从上至下 // 这些可以做一个封装,放入一个for循环进行创建即可 private ArrayList gameLayout4plant0; private ArrayList gameLayout4plant1; private ArrayList gameLayout4plant2; private ArrayList gameLayout4plant3; private ArrayList gameLayout4plant4; // 定义僵尸跑道 private ArrayList gamelayout4zombie0; private ArrayList gamelayout4zombie1; private ArrayList gamelayout4zombie2; private ArrayList gamelayout4zombie3; private ArrayList gamelayout4zombie4; // 定义僵尸控制器,通过此控制器来使僵尸实现移动 private ZombieManager zombieManager; public GameView(Context context) { super(context); // TODO GameView this.context = context; paint = new Paint(); surfaceHolder = getHolder(); surfaceHolder.addCallback(this); gameRunFlag = true; gameView = this; if (Config.game == false) { canvas.drawBitmap(Config.gameOver, 0, 0, paint); } } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO surfaceCreated // 加载bitmap(图片) createElement(); new Thread(this).start(); } private void createElement() { // TODO createElement // 给植物与僵尸的高度差赋值 Config.heightYDistance = Config.zombieFrames[0].getHeight() - Config.flowerFrames[0].getHeight(); // 给seedBank的X坐标赋初值 Config.seedBankLocationX = (Config.deviceWidth - Config.seedBank .getWidth()) / 2; // 初始化第三图层 gameLayout3 = new ArrayList(); // 当此方法被触发时便会创建卡片对象 gameLayout2 = new ArrayList(); SeedFlower seedFlower = new SeedFlower( (Config.deviceWidth - Config.seedBank.getWidth()) / 2 + Config.seedFlower.getWidth() / 3 + Config.seedBank.getWidth() / 7, Config.seedBank.getHeight() / 10); SeedPea seedPea = new SeedPea( (Config.deviceWidth - Config.seedBank.getWidth()) / 2 + Config.seedFlower.getWidth() / 7 + Config.seedBank.getWidth() / 7 * 2, Config.seedBank.getHeight() / 10); gameLayout2.add(seedFlower); gameLayout2.add(seedPea); // 添加安置状态中的植物 gameLayout1 = new ArrayList(); deadList = new ArrayList(); gameLayout4plant0 = new ArrayList(); gameLayout4plant1 = new ArrayList(); gameLayout4plant2 = new ArrayList(); gameLayout4plant3 = new ArrayList(); gameLayout4plant4 = new ArrayList(); // 僵尸跑道初始化 gamelayout4zombie0 = new ArrayList(); gamelayout4zombie1 = new ArrayList(); gamelayout4zombie2 = new ArrayList(); gamelayout4zombie3 = new ArrayList(); gamelayout4zombie4 = new ArrayList(); // 初始化僵尸控制器 zombieManager = new ZombieManager(); // 放置植物的合适位置 for (int i = 0; i <5; i++) { for (int j = 0; j <9; j++) { Config.plantPoints.put(i * 10 + j, new Point( (j + 2) * Config.deviceWidth / 11 - Config.deviceWidth / 11 / 2, (i + 1) * Config.deviceHeight / 6)); if (j == 0) { Config.raceWayYpoints[i] = (i + 1) * Config.deviceHeight / 6; } } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO surfaceChanged } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO surfaceDestroyed } // 所有的动画帧都由这个run方法来控制 // 控制动画帧的时候要注意首先进行数据更新 然后在更新图像 @Override public void run() { // TODO run while (gameRunFlag) { synchronized (surfaceHolder) { try { // 为了形成动画效果首先需要清理屏幕 // 加锁避免很多线程同时绘制 canvas = surfaceHolder.lockCanvas(); // 绘入背景,最底层图层 canvas.drawBitmap(Config.gameBK, 0, 0, paint); // 绘入上方植物栏,倒数第二层图层,仅覆盖于背景之上 canvas.drawBitmap(Config.seedBank, Config.seedBankLocationX, 0, paint); // 数据更改操作 updateData(); // 绘入植物卡片(第二层) ondraw(canvas); } catch (Exception e) { // TODO: handle exception } finally { // 解锁并提交 surfaceHolder.unlockCanvasAndPost(canvas); // CanvasAndPost必须要进行解锁 不管程序有什么问题必须给用户直观完整的显示过程 // 以防万一的话 加入try catch } } // 加入以下语句每次循环中休眠50毫秒减少一直循环的系统资源浪费 // 使用50毫秒的原因是在42帧及以上肉眼就会认为是流畅的,即1秒42张图片,每次循环休眠50毫秒即20帧 // 如果把sleep放在synchronized中的话会出现程序每次遍历完立刻睡眠然后再次遍历没有给其他进程事件运行会造成卡死 try { Thread.sleep(40); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void updateData() { // 在此方法中进行数据更新 // 清除deadList deadList.clear(); // 遍历第一图层 for (BaseModel model : gameLayout1) { if (!model.isAlife()) { deadList.add(model); } } // 遍历第二图层 for (BaseModel model : gameLayout2) { if (!model.isAlife()) { deadList.add(model); } } // 遍历第三图层 for (BaseModel model : gameLayout3) { if (!model.isAlife()) { deadList.add(model); } } // 遍历五条跑道上的僵尸 for (BaseModel model : gamelayout4zombie0) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gamelayout4zombie1) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gamelayout4zombie2) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gamelayout4zombie3) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gamelayout4zombie4) { if (!model.isAlife()) { deadList.add(model); } } // 遍历五条跑道上的植物 for (BaseModel model : gameLayout4plant0) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gameLayout4plant1) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gameLayout4plant2) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gameLayout4plant3) { if (!model.isAlife()) { deadList.add(model); } } for (BaseModel model : gameLayout4plant4) { if (!model.isAlife()) { deadList.add(model); } } // 遍历deadList集合 for (BaseModel model : deadList) { // 在各个图层列表中把它们移除 gameLayout1.remove(model); gameLayout2.remove(model); gameLayout3.remove(model); gamelayout4zombie0.remove(model); gamelayout4zombie1.remove(model); gamelayout4zombie2.remove(model); gamelayout4zombie3.remove(model); gamelayout4zombie4.remove(model); } } private void ondraw(Canvas canvas) { // TODO ondraw // 在此方法中进行绘图作业 // 按照游戏的层次进行绘制,先画游戏层次最下方的精灵 // 按照已经写好的分层顺序 // 绘制出阳光值 Paint paint2 = new Paint(); paint2.setTypeface(Typeface.DEFAULT_BOLD); paint2.setTextSize(15); canvas.drawText(Config.sunlight + "", Config.deviceWidth * 2 / 7, Config.deviceHeight / 8, paint2); // 僵尸控制器中的drawSelf实现僵尸移动 zombieManager.drawSelf(canvas, paint); // 跑道应该处于第四层故放在上方先绘制出来 // 遍历五条跑道调用drawSelf方法进行绘制植物 // 此处也可以进行方法的抽象 或者说应该把这些重复的代码抽象为一个方法调用不同的值进去 for (BaseModel model : gameLayout4plant0) { model.drawSelf(canvas, paint); } for (BaseModel model : gameLayout4plant1) { model.drawSelf(canvas, paint); } for (BaseModel model : gameLayout4plant2) { model.drawSelf(canvas, paint); } for (BaseModel model : gameLayout4plant3) { model.drawSelf(canvas, paint); } for (BaseModel model : gameLayout4plant4) { model.drawSelf(canvas, paint); } // 第三层(阳光) for (BaseModel model : gameLayout3) { model.drawSelf(canvas, paint); } // 第二层 for (BaseModel model : gameLayout2) { model.drawSelf(canvas, paint); } // 遍历五条跑道调用drawSelf方法进行绘制僵尸 // 此处也可以进行方法的抽象 或者说应该把这些重复的代码抽象为一个方法调用不同的值进去 // 第二层是植物卡片,僵尸在经过第一行的时候应该可以挡住植物卡片 for (BaseModel model : gamelayout4zombie0) { model.drawSelf(canvas, paint); } for (BaseModel model : gamelayout4zombie1) { model.drawSelf(canvas, paint); } for (BaseModel model : gamelayout4zombie2) { model.drawSelf(canvas, paint); } for (BaseModel model : gamelayout4zombie3) { model.drawSelf(canvas, paint); } for (BaseModel model : gamelayout4zombie4) { model.drawSelf(canvas, paint); } // 第一层 // gameLayout1比gameLayout2的层次要高故放在后面 for (BaseModel model : gameLayout1) { model.drawSelf(canvas, paint); } /* * private m=200; Paint paint3 = new Paint(); paint3.setAlpha(100); * canvas.drawRect(100, 100, 200, m, paint3); m-=5; 设置半透明效果 * m的作用是可以让这个半透明效果逐步消去, m的变化大小就可以理解为此植物的冷却时间 */ } // 在这里重写触摸响应事件 @Override public boolean onTouchEvent(MotionEvent event) { // TODO onTouchEvent // 对于相应来说gameLayout1的优先级最高故放在gameLayout2上方 for (BaseModel model : gameLayout1) { // 判定是否为touchAble的子类,只有是touchAble的子类才能响应 if (model instanceof TouchAble) { // 然后进行onTouch事件,查看是否被点击,如果点击那么返回true if (((TouchAble) model).onTouch(event)) { return true; } } } // 遍历第二层中的全部实体 for (BaseModel model : gameLayout2) { // 判定是否为touchAble的子类,只有是touchAble的子类才能响应 if (model instanceof TouchAble) { // 然后进行onTouch事件,查看是否被点击,如果点击那么返回true if (((TouchAble) model).onTouch(event)) { return true; } } } // 遍历第三层中的全部实体 for (BaseModel model : gameLayout3) { // 判定是否为touchAble的子类,只有是touchAble的子类才能响应 if (model instanceof TouchAble) { // 然后进行onTouch事件,查看是否被点击,如果点击那么返回true if (((TouchAble) model).onTouch(event)) { return true; } } } return false; } // 获取GameView的方法,让GameView编程所有实体的总桥梁 public static GameView getInstance() { return gameView; } // 添加EmplacePlant植物(优先级最高) public void applay4EmplacePlant(int locationX, int locationY, BaseModel model) { // TODO applay4EmplacePlant // 相当于在进行数据更新,在onDraw中会从这里取出一个个元素进行绘制,绘制过程中如果这里还会有更新那么会产生冲突,所以需要在这里加入一个同步锁 // 所有对于集合的操作都要加入同步锁,锁对象用surfaceHolder当得到此surfaceHolder锁对象的时候才能够进行操作 synchronized (surfaceHolder) { // gameLayout1放的是正在安放状态的植物,没有放下 // new一个处于安置状态的实体 // gameLayout1中只能有0~1个实例 if (gameLayout1.size() <1) { if (model instanceof SeedPea) { gameLayout1.add(new EmplacePea(locationX, locationY)); } else { gameLayout1.add(new EmplaceFlower(locationX, locationY)); } } } } public void applay4Plant(int locationX, int locationY, BaseModel baseModel) { // TODO applay4Plant // 安放静态植物 // 以空间换时间,因为植物、子弹、僵尸、都在第四层所以对于这些来说把它们分为五个赛道从上至下五层 // 每条赛道上有两个集合,一个是僵尸的集合,另一个是植物与子弹的集合,这样分是为了碰撞检测 // 为了减少碰撞检测事件去除部分不必要的运算,故而分成很多层 // 循环这个可安放植物的HashMap,目的是拿出每个元素与locationX和locationY进行比较 // key的作用是让每个Paint的标示不同 synchronized (surfaceHolder) {// 加锁 Point point; for (Integer key : Config.plantPoints.keySet()) { // 找距离locationX与locationY最近而且处于目标地域上 point = Config.plantPoints.get(key); if ((Math.abs(locationX - point.x) 

以上就是Android植物大战僵尸小游戏的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 移动