編輯:關於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<Integer, Point> plantPoints = new HashMap<Integer, Point>(); // 跑道 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<BaseModel> deadList;// 存放已消亡的實體,在拖動放手後實體會不顯示,但是還存在所以要進行清理 private ArrayList<BaseModel> gameLayout3;// 存放第三圖層中的實體; private ArrayList<BaseModel> gameLayout2;// 存放第二圖層中的實體 private ArrayList<BaseModel> gameLayout1;// 存放第一圖層中的實體 // 跑道從上至下 // 這些可以做一個封裝,放入一個for循環進行創建即可 private ArrayList<BaseModel> gameLayout4plant0; private ArrayList<BaseModel> gameLayout4plant1; private ArrayList<BaseModel> gameLayout4plant2; private ArrayList<BaseModel> gameLayout4plant3; private ArrayList<BaseModel> gameLayout4plant4; // 定義僵屍跑道 private ArrayList<BaseModel> gamelayout4zombie0; private ArrayList<BaseModel> gamelayout4zombie1; private ArrayList<BaseModel> gamelayout4zombie2; private ArrayList<BaseModel> gamelayout4zombie3; private ArrayList<BaseModel> 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<BaseModel>(); // 當此方法被觸發時便會創建卡片對象 gameLayout2 = new ArrayList<BaseModel>(); 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<BaseModel>(); deadList = new ArrayList<BaseModel>(); gameLayout4plant0 = new ArrayList<BaseModel>(); gameLayout4plant1 = new ArrayList<BaseModel>(); gameLayout4plant2 = new ArrayList<BaseModel>(); gameLayout4plant3 = new ArrayList<BaseModel>(); gameLayout4plant4 = new ArrayList<BaseModel>(); // 僵屍跑道初始化 gamelayout4zombie0 = new ArrayList<BaseModel>(); gamelayout4zombie1 = new ArrayList<BaseModel>(); gamelayout4zombie2 = new ArrayList<BaseModel>(); gamelayout4zombie3 = new ArrayList<BaseModel>(); gamelayout4zombie4 = new ArrayList<BaseModel>(); // 初始化僵屍控制器 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) < Config.deviceWidth / 11 / 2) && (Math.abs(locationY - point.y) < Config.deviceHeight / 6 / 2)) { // 跑道標示 int raceWayIndex = 6; for (int i = 0; i < Config.raceWayYpoints.length; i++) { // 遍歷跑道的Y值 if (point.y == Config.raceWayYpoints[i]) { // 如果Y值相等那麼跑道確定 raceWayIndex = i; } } if (isPlantExist(key, raceWayIndex)) { // 跑道數出發事件 switch (raceWayIndex) { case 0: if (baseModel instanceof EmplacePea) { gameLayout4plant0.add(new Pea(point.x, point.y, key)); Config.sunlight -= 100; } else { gameLayout4plant0.add(new Flower(point.x, point.y, key)); Config.sunlight -= 50; } break; case 1: if (baseModel instanceof EmplacePea) { gameLayout4plant1.add(new Pea(point.x, point.y, key)); Config.sunlight -= 100; } else { gameLayout4plant1.add(new Flower(point.x, point.y, key)); Config.sunlight -= 50; } break; case 2: if (baseModel instanceof EmplacePea) { gameLayout4plant2.add(new Pea(point.x, point.y, key)); Config.sunlight -= 100; } else { gameLayout4plant2.add(new Flower(point.x, point.y, key)); Config.sunlight -= 50; } break; case 3: if (baseModel instanceof EmplacePea) { gameLayout4plant3.add(new Pea(point.x, point.y, key)); Config.sunlight -= 100; } else { gameLayout4plant3.add(new Flower(point.x, point.y, key)); Config.sunlight -= 50; } break; case 4: if (baseModel instanceof EmplacePea) { gameLayout4plant4.add(new Pea(point.x, point.y, key)); Config.sunlight -= 100; } else { gameLayout4plant4.add(new Flower(point.x, point.y, key)); Config.sunlight -= 50; } break; default: break; } } } } } } // 判斷此處是否已經有植物的方法 // key是標示,raceWayIndex用於確定應查哪一個跑道 private boolean isPlantExist(int key, int raceWayIndex) { switch (raceWayIndex) { case 0: for (BaseModel model : gameLayout4plant0) { // 首先 如果這個區域是繼承了Plant接口的子類(因為子彈和陽光不繼承Plant做以區別) if (model instanceof Plant) { // 然後此處的key與傳入的key相等 if (key == ((Plant) model).getmapIndex()) { // 那麼返回此處不能種植植物 return false; } } } break; case 1: for (BaseModel model : gameLayout4plant1) { // 首先 如果這個區域是繼承了Plant接口的子類(因為子彈和陽光不繼承Plant做以區別) if (model instanceof Plant) { // 然後此處的key與傳入的key相等 if (key == ((Plant) model).getmapIndex()) { // 那麼返回此處不能種植植物 return false; } } } break; case 2: for (BaseModel model : gameLayout4plant2) { // 首先 如果這個區域是繼承了Plant接口的子類(因為子彈和陽光不繼承Plant做以區別) if (model instanceof Plant) { // 然後此處的key與傳入的key相等 if (key == ((Plant) model).getmapIndex()) { // 那麼返回此處不能種植植物 return false; } } } break; case 3: for (BaseModel model : gameLayout4plant3) { // 首先 如果這個區域是繼承了Plant接口的子類(因為子彈和陽光不繼承Plant做以區別) if (model instanceof Plant) { // 然後此處的key與傳入的key相等 if (key == ((Plant) model).getmapIndex()) { // 那麼返回此處不能種植植物 return false; } } } break; case 4: for (BaseModel model : gameLayout4plant4) { // 首先 如果這個區域是繼承了Plant接口的子類(因為子彈和陽光不繼承Plant做以區別) if (model instanceof Plant) { // 然後此處的key與傳入的key相等 if (key == ((Plant) model).getmapIndex()) { // 那麼返回此處不能種植植物 return false; } } } break; default: break; } return true; } // 被Flower請求,用於產生陽光 public void giveBrith2Sun(int locationX, int locationY) { // TODO giveBrith2Sun // 先設置鎖住 synchronized (surfaceHolder) { gameLayout3.add(new Sun(locationX, locationY)); } } // 被Pea請求,用於產生子彈 public void giveBirth2Bullet(int locationX, int locationY) { // TODO Auto-generated method stub // 先設置鎖住 synchronized (surfaceHolder) {// 加鎖 Point point; for (Integer key : Config.plantPoints.keySet()) { // 找距離locationX與locationY最近而且處於目標地域上 point = Config.plantPoints.get(key); if ((Math.abs(locationX - point.x) < Config.deviceWidth / 11 / 2) && (Math.abs(locationY - point.y) < Config.deviceHeight / 6 / 2)) { // 跑道標示 int raceWayIndex = 6; for (int i = 0; i < Config.raceWayYpoints.length; i++) { // 遍歷跑道的Y值 if (point.y == Config.raceWayYpoints[i]) { // 如果Y值相等那麼跑道確定 raceWayIndex = i; } } switch (raceWayIndex) { case 0: gameLayout4plant0.add(new Bullet(locationX, locationY)); break; case 1: gameLayout4plant1.add(new Bullet(locationX, locationY)); break; case 2: gameLayout4plant2.add(new Bullet(locationX, locationY)); break; case 3: gameLayout4plant3.add(new Bullet(locationX, locationY)); break; case 4: gameLayout4plant4.add(new Bullet(locationX, locationY)); break; default: break; } } } } } // 僵屍控制器產生相應,加入僵屍 public void apply4AddZombie() { // TODO apply4AddZombie // 先解鎖 synchronized (surfaceHolder) { int raceWay = 0; // 0~4的隨機數來進行跑到初始化 // Math.random()產生的是0~1的不包括1的隨機double型數字 raceWay = (int) (Math.random() * 5); // Config.deviceWidth + 20是為了讓僵屍逐步走入屏幕 // Config.raceWayYpoints[raceWay] - Config.heightYDistance // 是為了讓僵屍與植物的底對齊 switch (raceWay) { case 0: gamelayout4zombie0 .add(new Zombie(Config.deviceWidth + 20, Config.raceWayYpoints[raceWay] - Config.heightYDistance, raceWay)); break; case 1: gamelayout4zombie1 .add(new Zombie(Config.deviceWidth + 20, Config.raceWayYpoints[raceWay] - Config.heightYDistance, raceWay)); break; case 2: gamelayout4zombie2 .add(new Zombie(Config.deviceWidth + 20, Config.raceWayYpoints[raceWay] - Config.heightYDistance, raceWay)); break; case 3: gamelayout4zombie3 .add(new Zombie(Config.deviceWidth + 20, Config.raceWayYpoints[raceWay] - Config.heightYDistance, raceWay)); break; case 4: gamelayout4zombie4 .add(new Zombie(Config.deviceWidth + 20, Config.raceWayYpoints[raceWay] - Config.heightYDistance, raceWay)); break; default: break; } } } // 處理碰撞檢測,碰撞檢測的發起者是僵屍 public void checkCollision(Zombie zombie, int raceWay) { // TODO Auto-generated method stub synchronized (surfaceHolder) { switch (raceWay) { case 0: for (BaseModel model : gameLayout4plant0) { if (Math.abs((model.getLocationX() + model.getModelWidth() / 2) - (zombie.getLocationX() + zombie.getModelWidth() / 2)) < Math .abs((model.getModelWidth() + zombie .getModelWidth()) / 2)) { if (model instanceof Plant) { // 植物死 model.setAlife(false); } else if (model instanceof Bullet) { // 子彈死 model.setAlife(false); // 僵屍死 zombie.setAlife(false); model.setAlife(true); } } } break; case 1: for (BaseModel model : gameLayout4plant1) { if (Math.abs((model.getLocationX() + model.getModelWidth() / 2) - (zombie.getLocationX() + zombie.getModelWidth() / 2)) < Math .abs((model.getModelWidth() + zombie .getModelWidth()) / 2)) { if (model instanceof Plant) { // 植物死 model.setAlife(false); } else if (model instanceof Bullet) { // 子彈死 model.setAlife(false); // 僵屍死 zombie.setAlife(false); model.setAlife(true); } } } break; case 2: for (BaseModel model : gameLayout4plant2) { if (Math.abs((model.getLocationX() + model.getModelWidth() / 2) - (zombie.getLocationX() + zombie.getModelWidth() / 2)) < Math .abs((model.getModelWidth() + zombie .getModelWidth()) / 2)) { if (model instanceof Plant) { // 植物死 model.setAlife(false); } else if (model instanceof Bullet) { // 子彈死 model.setAlife(false); // 僵屍死 zombie.setAlife(false); model.setAlife(true); } } } break; case 3: for (BaseModel model : gameLayout4plant3) { if (Math.abs((model.getLocationX() + model.getModelWidth() / 2) - (zombie.getLocationX() + zombie.getModelWidth() / 2)) < Math .abs((model.getModelWidth() + zombie .getModelWidth()) / 2)) { if (model instanceof Plant) { // 植物死 model.setAlife(false); } else if (model instanceof Bullet) { // 子彈死 model.setAlife(false); // 僵屍死 zombie.setAlife(false); model.setAlife(true); } } } break; case 4: for (BaseModel model : gameLayout4plant4) { if (Math.abs((model.getLocationX() + model.getModelWidth() / 2) - (zombie.getLocationX() + zombie.getModelWidth() / 2)) < Math .abs((model.getModelWidth() + zombie .getModelWidth()) / 2)) { if (model instanceof Plant) { // 植物死 model.setAlife(false); } else if (model instanceof Bullet) { // 子彈死 model.setAlife(false); // 僵屍死 zombie.setAlife(false); model.setAlife(true); } } } break; default: break; } } } }
Android中實現圓角矩形和圓形有很多種方式,其中最常見的方法有ImageLoader設置Option和自定義View。 1.ImageLoader加載圖片public
iphone上有開關控件,很漂亮,其實android4.0以後也有switch控件,但是只能用在4.0以後的系統中,這就失去了其使用價值,而且我覺得它的界面也不是很好看。
安卓手機QQ自帶截圖功能,iPad、iPhone則需要使用iOS系統自帶的截圖方法或者第三方APP。下面就隨小編分別來看看,安卓手機QQ和iOS系統的ipa
一.前言現在的app基本上都需要用到短信功能,注冊時或者有消息通知時需要給用戶發送一條短信,但是對於個人開發者來說,去買第三方的短信服務實在是有點奢侈,很好的是mob為我