單人衛星定位遊戲-小飛機
手機遊戲-飛機大戰外星蜘蛛(GPS版)
遊戲玩法:利用手機的GPS功能來進行飛機的移動,飛機本身會自行發射子彈,目標是摧毀外星蜘蛛即可過關。
說明:此範例的特色為,利用接收GPS的功能來進行飛機的移動,其遊戲與單人飛機遊戲相似,差別只在於把重力加速感測器功能拿掉,而增加GPS的功能,玩法大致上差異不大。
下圖為遊戲程式執行畫面、式的狀態圖、架構圖及流程圖。
圖一-遊戲畫面
圖二-敵機狀態圖
圖三-關卡魔王狀態圖]
圖四-主架構圖
圖五-執行緒架構圖
圖六-繼承類別圖
圖七-小飛機GPS版流程圖
以下為飛機大戰外星蜘蛛(GPS版)的程式碼:
專案下載:Bee(GPS).rar
主程式:BeeGPS.java
package BeeGPS.main; import Bee.Object.Music; import Bee.Role.F16; import BeeGPS.main.R; import Bee.scene.Game1; import BeeGPS.main.GameStateClass.GameState; import Gps.MyLocationListener; import android.app.Activity; import android.app.Service; import android.content.Context; import android.content.pm.ActivityInfo; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.PowerManager; import android.os.Vibrator; import android.os.PowerManager.WakeLock; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Window; import android.view.WindowManager; public class BeeGPS extends Activity { private PowerManager powerManager; private WakeLock wakeLock; // GPS初始化 private LocationManager localManager; private LocationListener locationListener; // 重力加速度感測器 private SensorManager sensorMgr; private Sensor sensor; // 遊戲選單 public Game1 game; // 程式進入點 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化 Initialize(); // 載入資源 LoadContent(); } // 初始化 private void Initialize() { GV.res = getResources(); // 取得震動系統服務 GV.vibrator = (Vibrator) getApplication().getSystemService( Service.VIBRATOR_SERVICE); // 無標題列 requestWindowFeature(Window.FEATURE_NO_TITLE); // 全螢幕設定 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 螢幕固定成垂直方向 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // 初始化GPS服務 localManager = (LocationManager) getSystemService(Activity.LOCATION_SERVICE); // 初始化事件 locationListener = new MyLocationListener(); // 事件更新 localManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); // 取得螢幕大小 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); GV.scaleWidth = dm.widthPixels; GV.scaleHeight = dm.heightPixels; GV.halfWidth = GV.scaleWidth >> 1; GV.halfHeight = GV.scaleHeight >> 1; // 取得螢幕恆亮服務 powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "BackLight"); // 取得重力加速度感測器服務 sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } // 載入資源 public void LoadContent() { // 遊戲狀態初始化 GameStateClass.currentState = GameState.op; GameStateClass.oldState = GameState.None; // 背景音樂 GV.music = new Music(this, R.raw.stage1, 3); // 初始化遊戲 game = new Game1(this); // 初始化影片播放器 GV.videoPlayer = new VideoPlayer(this); // 載入開頭動畫 GV.videoPlayer.Load(R.raw.op); // 播放開頭動畫 GV.videoPlayer.Play(); } // 釋放資源 public void UnloadContent() { GV.snd.release(); GV.snd = null; finish(); } // 回復程式 @Override protected void onResume() { wakeLock.acquire(); // 加速度計註冊 sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME); // 繼續播放影片 if (GV.videoPlayer.isRuningVideo) GV.videoPlayer.Resume(); super.onResume(); // 會切到surfaceCreated } // 暫停程式 @Override protected void onPause() { GV.vibrator.cancel(); wakeLock.release(); // 加速度計解註冊 sensorMgr.unregisterListener(lsn); // 暫停影片播放 if (GV.videoPlayer.isRuningVideo) GV.videoPlayer.Pause(); if (game != null) { // 暫停音樂播放 if (GameStateClass.currentState != GameState.Menu) { if (GV.music != null) GV.music.Pause(); } // 停止遊戲迴圈 game.Exit(); } super.onPause(); } // 觸控事件 public boolean onTouchEvent(MotionEvent event) { // 按下 if (event.getAction() == MotionEvent.ACTION_DOWN) { switch(GameStateClass.currentState) { case op: GV.videoPlayer.Destroy(); break; case Menu: // 如果正在播放影片則停止播放 if (!GV.videoPlayer.isRuningVideo) { // 停止遊戲執行緒 game.Exit(); // 載入並播放F16起飛動畫 GV.videoPlayer.Load(R.raw.f16); GV.videoPlayer.Play(); }else { GV.videoPlayer.Destroy(); } break; case Stage1: // 大絕招 if (F16.bigBoom > 0) { if ((int)game.totalFrames - F16.startBigBoomFrame > F16.bigBoomDelayFrame) { F16.startBigBoomFrame = (int)game.totalFrames; F16.isTouchBoom = true; F16.bigBoom--; } } break; } } return super.onTouchEvent(event); } // 鍵盤事件 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch(keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: GV.x -=10; break; case KeyEvent.KEYCODE_DPAD_RIGHT: GV.x +=10; break; case KeyEvent.KEYCODE_DPAD_UP: GV.y -=10; break; case KeyEvent.KEYCODE_DPAD_DOWN: GV.y +=10; break; } return super.onKeyDown(keyCode, event); } // 重力加速度感測器 private SensorEventListener lsn = new SensorEventListener() { public void onSensorChanged(SensorEvent e) { // GV.x += (int) -e.values[SensorManager.DATA_X] << 2; // GV.y += (int) e.values[SensorManager.DATA_Y] << 2; // // if (GV.y > GV.scaleHeight) // { // GV.y = GV.scaleHeight; // } // GV.z = (int)e.values[SensorManager.DATA_Z]; } public void onAccuracyChanged(Sensor s, int accuracy) { } }; }
程式:GameStateClass.java
package Bee.main; import XNA.lbs.DrawableGameComponent; import XNA.lbs.Game; public class GameStateClass { // 遊戲狀態 public enum GameState { None, op, Menu, Stage1, Stage2, } public static GameState currentState; // 目前遊戲狀態 public static GameState oldState; // 上一次的遊戲狀態 // 切換關卡 public static void changeState(GameState newState,DrawableGameComponent nowGameClass,Game game) { // 從Game1元件中移除 game.Components.remove(nowGameClass); // 釋放Class nowGameClass.Dispose(); currentState = newState; } }
程式:GV.java
package Bee.main; import Bee.Object.Music; import android.content.res.Resources; import android.graphics.Rect; import android.media.SoundPool; import android.os.Vibrator; // 所有類別共用變數 public class GV { public enum Sound{ boom, alert, } // 影片播放 public static VideoPlayer videoPlayer = null; // 播放音樂 public static Music music = null; // 播放遊戲音效 public static SoundPool snd = null; // 音效ID public static int soundIDBoom = 0; // 音效ID public static int soundIDAlert = 0; // 螢幕大小 public static int scaleWidth = 0; public static int scaleHeight = 0; public static int halfWidth = 0; public static int halfHeight = 0; // 螢幕範圍 public static Rect screenRect = null; // 震動 public static Vibrator vibrator = null; // 資源 public static Resources res = null; // 自機的位置 public static int x , y; // 畫布 public static Surface surface = null; // 碰撞偵測 public static boolean isCollision(Rect a, Rect b) { if (a.left < b.right) if (a.right > b.left) if (a.top < b.bottom) if (a.bottom > b.top) return true; return false; } // 是否在螢幕內 public static boolean isInScreen(Rect obj) { return isCollision(obj, screenRect); } // 三角函數 public static float[] Cosine = new float[360]; public static float[] Sine = new float[360]; // 求角度 public static int getTheta(double XDistance, double YDistance) { // 不可除以0 if (XDistance == 0) XDistance = 1; // 角度 int theta = (int)(Math.atan(YDistance / XDistance) * 180 / Math.PI); // 象限轉換 if (XDistance >= 0 && theta <= 0) theta += 360; else if (XDistance <= 0) theta += 180; return theta; } // 播放音效 public static void playSound(Sound sound) { switch(sound) { case boom: snd.play(soundIDBoom, 1, 1, 0, 0, 1); break; case alert: snd.play(soundIDAlert, 1, 1, 0, 0, 1); break; } } }
程式:Surface.java
package Bee.main; import android.view.SurfaceHolder; import android.view.SurfaceView; public class Surface extends SurfaceView implements SurfaceHolder.Callback { public SurfaceHolder mHolder; private Bee bee; public Surface(Bee context) { super(context); bee = context; mHolder = this.getHolder(); mHolder.addCallback(this); } public void surfaceCreated(SurfaceHolder arg0) { // 如果影片不是播放的狀態才執行遊戲執行緒 if (!GV.videoPlayer.isRuningVideo) { // 以新的執行緒執行 bee.game.Run(); switch(GameStateClass.currentState) { case Menu: break; case Stage1: // 播放音樂 GV.music.Play(); break; } } } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { } public void surfaceDestroyed(SurfaceHolder arg0) { } }
程式:VideoPlayer.java
package Bee.main; import Bee.main.R; import Bee.main.GameStateClass.GameState; import android.content.Context; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.net.Uri; import android.view.MotionEvent; import android.widget.VideoView; public class VideoPlayer { private myVideo video; private int videoPosition = 0; private Bee bee; public boolean isRuningVideo; public VideoPlayer(Bee bee) { this.bee = bee; video = new myVideo(bee); Load(R.raw.f16); video.setOnCompletionListener(new OnCompletionListener() { public void onCompletion(MediaPlayer arg0) { Destroy(); } }); } public void Load(int movie) { Uri uri = Uri.parse("android.resource://" + bee.getPackageName() + "/" + movie); video.setVideoURI(uri); } public void Play() { isRuningVideo = true; bee.setContentView(video); video.requestFocus(); video.start(); } public void Resume() { video.seekTo(videoPosition); video.start(); } public void Pause() { video.pause(); videoPosition = video.getCurrentPosition(); } public void Stop() { isRuningVideo = false; video.stopPlayback(); } public void Destroy() { Stop(); video.destroyDrawingCache(); video.clearAnimation(); video.clearFocus(); // 切換關卡 switch(GameStateClass.currentState) { case op: // 初始化畫布View GameStateClass.currentState = GameState.Menu; GV.surface = new Surface(bee); break; case Menu: GameStateClass.changeState(GameState.Stage1, bee.game.menu, bee.game); break; case Stage1: break; } bee.setContentView(GV.surface); } class myVideo extends VideoView { public myVideo(Context context) { super(context); } // 將影片設定為全螢幕 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(GV.scaleWidth, GV.scaleHeight); } @Override public boolean onTouchEvent(MotionEvent ev) { return false; } } }
程式:Music.java
package Bee.Object; import Bee.main.R; import android.content.Context; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; public class Music{ public MediaPlayer player; public boolean isComplete; public Music(Context context,int music,int volume) { player = MediaPlayer.create(context, music); // 音量大小(0~10) player.setVolume(volume, volume); isComplete = false; player.setOnCompletionListener(new OnCompletionListener() { public void onCompletion(MediaPlayer arg0) { isComplete = true; } }); } public void Play() { if (!isComplete) if (!player.isPlaying()) player.start(); } public void Stop() { player.stop(); isComplete = false; } public void Pause() { player.pause(); } }
程式:Object2D.java
package Bee.Object; import Bee.main.R; import android.content.Context; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; public class Music{ public MediaPlayer player; public boolean isComplete; public Music(Context context,int music,int volume) { player = MediaPlayer.create(context, music); // 音量大小(0~10) player.setVolume(volume, volume); isComplete = false; player.setOnCompletionListener(new OnCompletionListener() { public void onCompletion(MediaPlayer arg0) { isComplete = true; } }); } public void Play() { if (!isComplete) if (!player.isPlaying()) player.start(); } public void Stop() { player.stop(); isComplete = false; } public void Pause() { player.pause(); } }
程式:Plane.java
package Bee.Object; import java.util.ArrayList; import android.graphics.Color; import android.graphics.Rect; import Bee.Role.Boom; import Bee.Role.Bullet1; import Bee.Role.ShootEffect; import Bee.main.GV; import Bee.main.GV.Sound; public class Plane extends Object2D{ public class Barrel extends Object2D { // 開始射擊時間 public int startShootFrame = 0; // 再度發射延遲時間 public int bulletDelayFrame; // 炮管的角度 public int barrelTheta; // 子彈 public ArrayList<Bullet1> bullet; public Barrel(int length,int barrelTheta,int theta, int speed, int bulletDelayFrame) { super(length, theta, speed); bullet = new ArrayList<Bullet1>(); // 炮管在機身中位置的角度 this.barrelTheta = barrelTheta; // 再度發射延遲時間 this.bulletDelayFrame = bulletDelayFrame; } public void addBarrelTheta(int speed) { barrelTheta = (barrelTheta + speed) % 360; if (barrelTheta < 0) barrelTheta += 360; } } // 多個炮管 public ArrayList<Barrel> barrel = new ArrayList<Barrel>(); // 影格欄數 private static final int col = 4; // 動畫最大索引 private int maxIndex = 18; // 迴圈變數 private int f,j,k; // 子彈暫存用 private Bullet1 bullet; // 增加或減少畫格 protected int offset; // 生命 public int life; // 血量 public int blood; // 子彈位置 private int x; private int y; // 透明回復開始時間 private int startRestoreAlphaFrame; // 透明回復延遲時間 private static int resotreAlphaDelayFrame = 5; public Plane(int destX,int destY,int destWidth,int destHeight,int srcX,int srcY,int srcWidth,int srcHeight,int speed,int color,int theta) { super(destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight, speed, color,theta); } // 檢查飛機碰撞 public static void CheckPlaneCollision(int frameTime,ArrayList<Plane> planeA,ArrayList<Plane> planeB,ArrayList<Boom> boom) { for (int f = planeA.size() - 1; f >= 0; f--) { if (planeA.get(f).isAlive) { for (int j = planeB.size() - 1; j >= 0; j--) { if (planeB.get(j).isAlive) { if (GV.isCollision(planeA.get(f).destRect, planeB.get(j).destRect)) { planeA.get(f).Collisioned(frameTime,boom); planeB.get(j).Collisioned(frameTime,boom); break; } } } } } } // 檢查子彈與飛機是否碰撞 public void CheckBulletCollision(int frameTime,ArrayList<Plane> plane,ArrayList<Boom> boom) { // 炮管 for (f = barrel.size() - 1; f >= 0; f--) { // 子彈 for (j = barrel.get(f).bullet.size() - 1; j >= 0; j--) { // 被碰撞的飛機 for (k = plane.size() - 1; k >= 0; k--) { if (plane.get(k).isAlive) { // 暫存子彈 bullet = barrel.get(f).bullet.get(j); // 檢查是否碰撞 if (GV.isCollision(bullet.destRect, plane.get(k).destRect)) { // 子彈消失 barrel.get(f).bullet.remove(j); // 發生碰撞 plane.get(k).Collisioned(frameTime,boom); break; } } } } } } // 碰撞發生 public void Collisioned(int frameTime,ArrayList<Boom> boom) { blood--; if (blood > 0) { paint.setAlpha(128); startRestoreAlphaFrame = frameTime; } else { // 新增爆炸 boom.add(new Boom(getX() + halfWidth - Boom.halfSize, getY() + halfHeight - Boom.halfSize, Boom.size, Boom.size)); // 爆炸音效 GV.playSound(Sound.boom); // 飛機消失 isAlive = false; life--; if (life > 0) Rebirth(); } } // 重生 protected void Rebirth() { } // 敵機行動 public void Action(int frameTime, Plane plane, ArrayList<ShootEffect> shootEffect) { ActionCommon(frameTime); } // 自機行動 public void Action(int frameTime,ArrayList<ShootEffect> shootEffect) { ActionCommon(frameTime); } // 行動共用 private void ActionCommon(int frameTime) { if (frameTime - startRestoreAlphaFrame > resotreAlphaDelayFrame) { paint.setAlpha(255); } } // 子彈移動 public void AllBulletMove() { // 走訪炮管 for (f = barrel.size() - 1; f >= 0; f--) { // 走訪子彈 for (j = barrel.get(f).bullet.size() - 1 ; j>=0 ;j--) { if (barrel.get(f).bullet.get(j).bulletMove()) barrel.get(f).bullet.remove(j); } } } // 子彈射擊 public void Shoot(int frameTime,ArrayList<ShootEffect> shootEffect) { // 走訪炮管 for (f = barrel.size() - 1; f >= 0; f--) { if (frameTime - barrel.get(f).startShootFrame > barrel.get(f).bulletDelayFrame) { // 儲存開始發射時間 barrel.get(f).startShootFrame = frameTime; x = getX() + halfWidth + (int)(barrel.get(f).destHeight * GV.Cosine[barrel.get(f).barrelTheta]); y = getY() + halfHeight + (int)(barrel.get(f).destHeight * GV.Sine[barrel.get(f).barrelTheta]); // 新增子彈 barrel.get(f).bullet.add(new Bullet1(x - Bullet1.halfSize, y - Bullet1.halfSize, barrel.get(f).speed, Color.WHITE, barrel.get(f).theta)); // 新增特效 shootEffect.add(new ShootEffect(x - ShootEffect.halfWidth, y - ShootEffect.halfHeight)); } } } // 民航機向下移動 protected boolean moveDown(int destY) { // 遞增 addY(speed); // 是否到達目的地 if (getY() + halfHeight > destY) { setY(destY - halfHeight); return true; } else return false; } // 民航機向上移動 protected boolean moveUp(int destY) { // 遞減 addY(-speed); // 是否到達目的地 if (getY() + halfHeight < destY) { setY(destY - halfHeight); return true; } else return false; } // 向左移動 protected boolean moveLeft(int destX) { addX(-speed); if (getX() + halfWidth < destX) { setX(destX - halfWidth); return true; } else return false; } // 向右移動 protected boolean moveRight(int destX) { addX(speed); if (getX() + halfWidth > destX) { setX(destX - halfWidth); return true; } else return false; } // 自轉 protected boolean rotationPlane(int destTheta) { int value = destTheta - theta; int speed = 0; if (value != 0) { if (value > 0) { if (Math.abs(value)>=180) { // 逆轉 speed = -1; } else { // 順轉 speed = 1; } } else if (value < 0) { if (Math.abs(value)>=180) { // 順轉 speed = 1; } else { // 逆轉 speed = -1; } } addTheta(speed); // 炮管與機身同步旋轉 for (f = barrel.size() - 1; f >= 0; f--) { barrel.get(f).addTheta(speed); barrel.get(f).barrelTheta = barrel.get(f).theta; } } if (theta == destTheta) return true; else return false; } // 播放動畫 protected void planeAnimation() { // 設定影格 setAnimationIndex(col); // 慢慢回復成正面,offset對畫格做增減 if (offset == 0) { if (index > 10) index--; else if (index < 10) index++; } else index += offset; // 歸零 offset = 0; // 防止動畫索引超出範圍 if (index < 0) index = 0; else if (index > maxIndex) index = maxIndex; } }
程式:Text.java
package Bee.Object; import android.graphics.Paint; import android.graphics.Typeface; public class Text { public int x; public int y; public int size; public String message; public Paint paint; public boolean isVisible; public int startFrame; public int delayFrame; public Text(int x, int y, int size, String message, int color) { this.x = x; this.y = y; this.size = size; this.message = message; paint = new Paint(); paint.setColor(color); paint.setTextSize(size); paint.setTypeface(Typeface.MONOSPACE); } }
程式:Aircraft.java
package Bee.Role; import java.util.ArrayList; import android.util.StateSet; import Bee.Object.Object2D; import Bee.Object.Plane; import Bee.main.GV; public class Aircraft extends Plane{ // 狀態種類 private State kind = State.step1; // 長 public static int width = 0; // 寬 public static int height = 0; public static int halfWidth = 0; public static int halfHeight = 0; // 瞄準目標時間 private int startTargetFrame = 0; // 切換到射擊狀態的時間 private static final int switchShootDelayFrame = 60; // 開始結束狀態時間 private int startEndFrame = 0; // 切換到結束狀態的時間 private static final int switchEndDelayFrame = 300; // 用來判斷左右 private int tempX; // 向下移動到目的位置 private int movDestY; // 暫存角度 private int tempTheta; public Aircraft(int destX,int destY,int destWidth,int destHeight,int srcX,int srcY,int srcWidth,int srcHeight,int speed,int color,int theta,State kind) { super( destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight,speed, color,theta); // Action的狀態圈 this.kind = kind; switch(kind) { case step1: // 新增炮管 barrel.add(new Barrel(halfHeight, theta, theta, 5, 60)); blood = 4; break; case step2: blood = 4; break; case step3: case step4: tempTheta = theta; setTheta(90); blood = 3; break; } // 設為已存活 isAlive = true; // 動畫正面 index = 10; // 向下移動到目的位置 movDestY = destY + GV.scaleHeight; } @Override public void Action(int frameTime, Plane myPlane,ArrayList<ShootEffect> shootEffect) { tempX = getX(); switch(kind) { case step1: switch(state) { case step1: // 向下移動 if (moveDown(movDestY)) { state = State.step2; startTargetFrame = frameTime; startEndFrame = frameTime; } break; case step2: // 瞄準目標 rotationPlane(getTargetTheta(myPlane.destRect,this.destRect)); // 切換下一個狀態 if (frameTime - startTargetFrame > switchShootDelayFrame) { state = State.step3; } break; case step3: // 射擊 Shoot(frameTime,shootEffect); // 切換成瞄準狀態 startTargetFrame = frameTime; state = State.step2; // 切換成結束狀態 if (frameTime - startEndFrame > switchEndDelayFrame) { state = State.step4; } break; case step4: if (moveUp(-destHeight)) isAlive = false; break; } break; case step2: switch(state) { case step1: // 移動到螢幕四分之一的高度 if (moveDown(GV.halfHeight >> 1)) { state = State.step2; } break; case step2: // 向F16衝撞 setTheta(getTargetTheta(myPlane.destRect,this.destRect)); move(); if (frameTime - startEndFrame > switchEndDelayFrame) { state = State.step3; } break; case step3: move(); if (!GV.isInScreen(destRect)) { isAlive = false; } break; } break; case step3: switch(state) { case step1: if (moveDown(movDestY)) { theta = tempTheta; state = State.step2; } break; case step2: move(); if (!GV.isInScreen(destRect)) { isAlive = false; } break; } break; case step4: switch(state) { case step1: if (moveDown(destHeight << 2)) { theta = tempTheta; state = State.step2; } break; case step2: move(); if (!GV.isInScreen(destRect)) { isAlive = false; } break; } break; } tempX = getX() - tempX; if (tempX > 0) offset = 1; else if (tempX < 0) offset = -1; // 自機動畫 planeAnimation(); super.Action(frameTime, myPlane,shootEffect); } }
程式:Boom.java
package Bee.Role; import android.graphics.Color; import Bee.Object.Object2D; public class Boom extends Object2D{ public static int size = 0; public static int halfSize = 0; public static int col = 5; public static int maxIndex = 24; public Boom(int destX,int destY,int destWidth,int destHeight) { super(destX, destY, destWidth, destHeight, 0, 0, size, size, 0, Color.WHITE,0); isAlive = true; } public void Animation() { setAnimationIndex(col); if (index < maxIndex) index++; else isAlive = false; } }
程式:Bullet1.java
package Bee.Role; import java.util.ArrayList; import Bee.Object.Object2D; import Bee.main.GV; // 子彈 public class Bullet1 extends Object2D{ // 子彈的大小 public static int size = 15; public static int halfSize = size >> 1; public Bullet1(int destX,int destY,int speed,int color, int theta) { super( destX, destY, size, size, 0, 0, size, size,speed, color,theta); isAlive = true; } // 子彈移動 public boolean bulletMove() { move(); // 是否超出螢幕 if (!GV.isInScreen(destRect)) return true; else return false; } }
程式:F16.java
package Bee.Role; import java.util.ArrayList; import Bee.Object.Plane; import Bee.main.GV; public class F16 extends Plane { // 大絕招 public static int bigBoom = 3; // 使用大絕招 public static boolean isTouchBoom; // 開始使用大絕招的時間 public static int startBigBoomFrame = 0; // 再度使用大絕招的延遲時間 public static int bigBoomDelayFrame = 30; // 一秒後 // 大絕招的破壞力 public static int bigBoomPower = 10; public F16(int destX, int destY, int destWidth, int destHeight, int srcX, int srcY, int srcWidth, int srcHeight,int speed, int color,int theta) { super(destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight, speed, color,theta); // 新增炮管(距離飛機中心的距離,距離飛機中心的絕對距離) barrel.add(new Barrel(halfHeight, theta, theta, 10, 10)); barrel.add(new Barrel(halfHeight, theta - 20, theta - 15, 10, 12)); barrel.add(new Barrel(halfHeight, theta + 20, theta + 15, 10, 12)); barrel.add(new Barrel(halfHeight, theta - 45, theta - 30, 10, 12)); barrel.add(new Barrel(halfHeight, theta + 45, theta + 30, 10, 12)); // 設定大絕招的數量 bigBoom = 3; // 大絕開始使用時間歸零 startBigBoomFrame = 0; // 生命 life = 5; lifeInitialize(); } private void lifeInitialize() { // 可使用大絕的次數 bigBoom = 3; // 動畫正面 index = 10; // 設為已存活 isAlive = true; // 血量 blood = 10; } // 自機行動 @Override public void Action(int frameTime, ArrayList<ShootEffect> shootEffect) { if (GV.x - (getX() + halfWidth) > 5) { offset = 1; addX(speed); } else if (GV.x - (getX() + halfWidth) < -5) { offset = -1; addX(-speed); } if (GV.y - (getY() + halfHeight) > 5) addY(speed); else if (GV.y - (getY() + halfHeight) < -5) addY(-speed); // 防止超出邊界 if (getX() < 0) { offset = 0; GV.x = halfWidth; setX(0); } else if (getX() + destWidth > GV.scaleWidth) { offset = 0; GV.x = GV.scaleWidth - halfWidth; setX(GV.scaleWidth - destWidth); } if (getY() < 0) { GV.y = halfHeight; setY(0); } else if (getY() + destHeight > GV.scaleHeight) { if (GV.y > GV.scaleHeight - halfHeight) GV.y = GV.scaleHeight - halfHeight; setY(GV.scaleHeight - destHeight); } // 自動發射子彈 Shoot(frameTime,shootEffect); // 自機動畫 planeAnimation(); super.Action(frameTime,shootEffect); } // 被撞擊後 @Override public void Collisioned(int frameTime,ArrayList<Boom> boom) { // 震動0.1秒 GV.vibrator.vibrate(100); super.Collisioned(frameTime, boom); } // 重生 @Override protected void Rebirth() { GV.x = GV.halfWidth; GV.y = GV.halfHeight + destHeight; setX(GV.halfWidth - halfWidth); setY(GV.scaleHeight << 1); lifeInitialize(); } }
程式:RedMask.java
package Bee.Role; import android.graphics.Color; import Bee.Object.Object2D; import Bee.Object.Text; import Bee.main.GV; import Bee.main.GV.Sound; public class RedMask extends Object2D{ private int startFrame; private int delayFrame = 300; public Text warningText; public RedMask(int color,int alpha) { super(0, 0, GV.scaleWidth, GV.scaleHeight, color, alpha); warningText = new Text(50, GV.halfHeight, 36, "Warning", Color.BLACK); } public void Action(int frameTime) { switch(state) { case step1: startFrame = frameTime; state = State.step2; break; case step2: if (FadeIn()) state = State.step3; break; case step3: if (FadeOut()) state = State.step2; if (frameTime - startFrame > delayFrame) { isAlive = false; } break; } } public boolean FadeIn() { alpha+=5; if (alpha > 192) { alpha = 192; GV.playSound(Sound.alert); return true; } paint.setAlpha(alpha); return false; } public boolean FadeOut() { alpha-=5; if (alpha < 0) { alpha = 0; return true; } paint.setAlpha(alpha); return false; } }
程式:ShootEffect.java
package Bee.Role; import android.graphics.Color; import Bee.Object.Object2D; import Bee.Object.Object2D.State; public class ShootEffect extends Object2D{ public static int width; public static int height; public static int halfWidth; public static int halfHeight; public ShootEffect(int destX,int destY) { super( destX, destY, width, height, 0, 0, width, height,0, Color.WHITE,0); alpha = 255; } public boolean Animation() { destRect.left++; destRect.top++; destRect.right--; destRect.bottom--; alpha-=5; paint.setAlpha(alpha); if (destWidth <= 0 || destHeight <= 0 || alpha <= 0) return true; else return false; } }
程式:Spider.java
package Bee.Role; import java.util.ArrayList; import Bee.Object.Object2D; import Bee.Object.Plane; import Bee.main.GV; import Bee.main.GV.Sound; import android.graphics.Color; public class Spider extends Plane{ public static int width; public static int height; // 切換成炮管左右來回旋轉的延遲時間 private int startSwitchStep4Frame; private int switchStep4DelayFrame = 300; // 切換到stpe6的延遲時間 private int startSwitchStep6Frame; private int switchStep6DelayFrame = 300; // 切換到stpe8的延遲時間 private int startSwitchStep8Frame; private int switchStep8DelayFrame = 300; // 血條物件 public Object2D bloodObj; // 最大血量 private static final int maxBlood = 500; // 迴圈變數 private int f; public Spider(int destX,int destY,int destWidth,int destHeight,int srcX,int srcY,int srcWidth,int srcHeight, int speed,int color, int theta) { super( destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight, speed, color, theta); barrel.add(new Barrel(halfHeight,theta, theta, 5, 5)); barrel.add(new Barrel(halfHeight,theta, theta - 45, 5, 5)); barrel.add(new Barrel(halfHeight,theta, theta + 45, 5, 5)); // 初始化血條 bloodObj = new Object2D(20, 20, GV.scaleWidth - 40, 10, Color.RED, 128); // 設為存活 isAlive = true; // 血量 blood = maxBlood; } @Override public void Action(int frameTime, Plane plane,ArrayList<ShootEffect> shootEffect) { switch(state) { case step1: // 移進螢幕 if (moveDown(20)) { state = State.step2; // 切換到 step 4 計時 startSwitchStep4Frame = frameTime; } break; case step2: // 向右移動並發射子彈 if (moveRight(GV.scaleWidth - halfWidth)) { state = State.step3; } Shoot(frameTime, shootEffect); // 時間到則切換step4 if (frameTime - startSwitchStep4Frame > switchStep4DelayFrame) { state = State.step4; // 增加子彈再度發射的延遲時間 for (f = barrel.size() -1 ;f>=0;f--) { barrel.get(f).bulletDelayFrame = 15; } // 切換到step6計時 startSwitchStep6Frame = frameTime; } break; case step3: // 向左移動並發射子彈 if (moveLeft(halfWidth)) { state = State.step2; } Shoot(frameTime, shootEffect); break; case step4: Shoot(frameTime, shootEffect); // 順轉炮管 for (f = barrel.size() - 1; f >= 0; f--) { rotationBarrel(barrel.get(f), 1); // 旋轉次數 if (barrel.get(f).theta > 180) { state = State.step5; break; } } break; case step5: Shoot(frameTime, shootEffect); // 逆轉炮管 for (f = barrel.size() - 1; f >= 0; f--) { rotationBarrel(barrel.get(f), -1); // 旋轉角度 if (barrel.get(f).theta > 350) { state = State.step4; break; } } // 時間到就切換到state6 if (frameTime - startSwitchStep6Frame > switchStep6DelayFrame) { state = State.step6; } break; case step6: // 蜘蛛旋轉 rotationBarrel(this, 1); if (theta > 270) { state = State.step7; // 移除所有炮管 barrel.removeAll(barrel); // 新增炮管 for (f = 0; f < 360; f += 15) { barrel.add(new Barrel(halfHeight >> 2,f, f, 10, 5)); } startSwitchStep8Frame = frameTime; } break; case step7: Shoot(frameTime, shootEffect); // 時間到就切到狀態8 if (frameTime - startSwitchStep8Frame > switchStep8DelayFrame) { state = State.step8; } break; case step8: // 旋轉蜘蛛 rotationBarrel(this, 1); if (theta == 90) { // 移除所有炮管 barrel.removeAll(barrel); // 還原初始炮管 barrel.add(new Barrel(halfHeight,theta, theta, 5, 5)); barrel.add(new Barrel(halfHeight,theta, theta - 45, 5, 5)); barrel.add(new Barrel(halfHeight,theta, theta + 45, 5, 5)); state = State.step1; } break; } super.Action(frameTime, plane, shootEffect); } @Override public void Collisioned(int frameTime, ArrayList<Boom> boom) { bloodObj.destRect.right = (int)((float)blood / maxBlood * (GV.scaleWidth - 20)); // 新增爆炸 if (blood < 2) { boom.add(new Boom(getX() + halfWidth - GV.halfWidth, getY() + halfHeight - GV.halfHeight, GV.halfWidth, GV.halfHeight)); } super.Collisioned(frameTime, boom); } // 旋轉炮管 private void rotationBarrel(Object2D obj, int speed) { obj.addTheta(speed); } }
程式:Game1.java
package Bee.scene; import Bee.Object.Music; import Bee.Role.F16; import Bee.main.Bee; import Bee.main.GV; import Bee.main.GameStateClass; import Bee.main.R; import XNA.lbs.Game; import android.graphics.Color; import android.media.AudioManager; import android.media.SoundPool; public class Game1 extends Game { public Menu menu; public Stage1 stage1; public Bee bee; public Game1(Bee bee) { this.bee = bee; } @Override protected void Initialize() { // 設定靜態變數的初值 F16.bigBoom = 1; F16.startBigBoomFrame = 0; super.Initialize(); } @Override protected void LoadContent() { // 遊戲音效 GV.snd = new SoundPool(10, AudioManager.STREAM_MUSIC, 0); // 爆炸 GV.soundIDBoom = GV.snd.load(bee, R.raw.explosion, 0); // 警告 GV.soundIDAlert = GV.snd.load(bee, R.raw.sysalert, 0); super.LoadContent(); } @Override protected void UnloadContent() { super.UnloadContent(); } @Override protected void Update() { if (GameStateClass.currentState != GameStateClass.oldState) { switch (GameStateClass.currentState) { case None: bee.UnloadContent(); break; case Menu: menu = new Menu(this); Components.add(menu); break; case Stage1: // 新增第一關 stage1 = new Stage1(this); Components.add(stage1); // 播放背景音樂 if (!GV.music.player.isPlaying()) { GV.music.player.release(); GV.music = new Music(bee, R.raw.stage1,2); GV.music.Play(); } break; } GameStateClass.oldState = GameStateClass.currentState; } super.Update(); } @Override protected void Draw() { canvas = GV.surface.mHolder.lockCanvas(null); // 清空 canvas.drawColor(Color.BLACK); super.Draw(); } }
程式:Menu.java
package Bee.scene; import Bee.Object.Object2D; import Bee.Object.Text; import Bee.main.GV; import XNA.lbs.DrawableGameComponent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; public class Menu extends DrawableGameComponent{ private Game1 game; private Canvas subCanvas; // 畫格時間 private int frameTime; // 背景 private Bitmap menuBitmap; private Object2D menuObj; // "Touch"文字 private Text menuText; private Text menuShadow; // 標題文字 private Text menuTitleText; private Text menuTitleShadow; public Menu(Game1 game) { this.game = game; } @Override protected void Initialize() { // 標題文字 menuTitleText = new Text(65, 50, 36, "小飛機", Color.YELLOW); menuTitleShadow = new Text(menuTitleText.x + 10, menuTitleText.y - 5, menuTitleText.size, menuTitleText.message, Color.BLACK); // "Touch"文字 menuText = new Text(50, GV.scaleHeight - 70, 12, "Touch screen to start", Color.YELLOW); menuText.delayFrame = 20; menuShadow = new Text(menuText.x + 10, menuText.y - 5, menuText.size, menuText.message, Color.BLACK); // 載入背景 menuBitmap = BitmapFactory.decodeResource(GV.res, Bee.main.R.drawable.menu); // 初始化背景物件 menuObj = new Object2D(0, 0, GV.scaleWidth, GV.scaleHeight, 0, 0, menuBitmap.getWidth(), menuBitmap.getHeight(), 0, Color.WHITE, 0); menuObj.paint.setAlpha(170); super.Initialize(); } @Override protected void UnloadContent() { super.UnloadContent(); } @Override protected void Update() { // 取得目前的畫格時間 frameTime = (int)game.totalFrames; // 閃礫"Touch"文字 if (frameTime - menuText.startFrame > menuText.delayFrame) { menuText.startFrame = frameTime; menuText.isVisible = !menuText.isVisible; } super.Update(); } @Override protected void Draw() { subCanvas = game.canvas; // 畫出背景 subCanvas.drawBitmap(menuBitmap, menuObj.srcRect, menuObj.destRect, menuObj.paint); // 畫出標題陰影 subCanvas.drawText(menuTitleShadow.message, menuTitleShadow.x, menuTitleShadow.y, menuTitleShadow.paint); // 畫出標題 subCanvas.drawText(menuTitleText.message, menuTitleText.x, menuTitleText.y, menuTitleText.paint); // 閃礫 if (menuText.isVisible) { // 畫出"Touch"陰影 subCanvas.drawText(menuShadow.message, menuShadow.x, menuShadow.y, menuShadow.paint); // 畫出"Touch"文字 subCanvas.drawText(menuText.message, menuText.x, menuText.y, menuText.paint); } super.Draw(); } }
程式:Stage1.java
package Bee.scene; import java.util.ArrayList; import Bee.Object.Music; import Bee.Object.Object2D; import Bee.Object.Plane; import Bee.Object.Text; import Bee.Object.Object2D.State; import Bee.Role.Aircraft; import Bee.Role.Boom; import Bee.Role.Bullet1; import Bee.Role.F16; import Bee.Role.RedMask; import Bee.Role.ShootEffect; import Bee.Role.Spider; import Bee.main.GV; import Bee.main.GameStateClass; import Bee.main.R; import Bee.main.GameStateClass.GameState; import XNA.lbs.DrawableGameComponent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; public class Stage1 extends DrawableGameComponent { private Game1 game; private Canvas subCanvas; // 顯示FPS文字 private Text fpsText; // 自機圖片 private Bitmap f16Bitmap; // 自機物件 private ArrayList<Plane> myPlane; // 民航機圖片 private Bitmap aircraftBitmap; // 民航機物件 private ArrayList<Plane> aircraft; // 子彈圖片 private Bitmap bulletBitmap1; // 一般背景圖片 private Bitmap backGroundImage; // 一般背景物件 private Object2D backGroundObj; // 爆炸圖片 private Bitmap boomBitmap; // 爆炸 private ArrayList<Boom> boom = new ArrayList<Boom>(); // 子彈暫存用物件 private Bullet1 bullet; // 爆炸暫存 private Boom subBoom; // 飛機暫存 private Plane plane; // 迴圈變數 private int f, j, k; // 發射特效圖片 private Bitmap shootEffectBitmap; // 發射特效物件 public ArrayList<ShootEffect> shootEffect = new ArrayList<ShootEffect>(); // 是否啟用黑色遮罩 private boolean isBlackMask; private Object2D blackMask; // 是否啟用紅色遮罩 private RedMask redMask; // 黑色遮罩開始啟用時間 private int startBlackMaskFrame; // 從黑色遮罩到重新遊戲的時間 private int restartDelayFrame = 150; // 顯示GameOver文字 private Text gameOverText; // 蜘蛛 private Bitmap spiderBitmap; private ArrayList<Plane> spiderObj; // 畫格總數 private int frameTime; // 蜘蛛背景 private Bitmap spiderBackGroundBitmap; // 蜘蛛背景物件 private Object2D spiderBackGroundObj; // 破關 private boolean breakOff; public Stage1(Game1 game) { this.game = game; } @Override protected void Initialize() { // 預先算好三角函數 for (int f = 0; f < 360; f++) { GV.Cosine[f] = (float) Math.cos(f * Math.PI / 180); GV.Sine[f] = (float) Math.sin(f * Math.PI / 180); } GV.screenRect = new Rect(0, 0, GV.scaleWidth, GV.scaleHeight); // 歸零 game.totalFrames = 0; super.Initialize(); } @Override protected void LoadContent() { // 取得單一影格的寬高 int width, height; // 民航機 aircraftBitmap = (Bitmap) BitmapFactory.decodeResource(GV.res, R.drawable.aircraft); width = aircraftBitmap.getWidth() / 4; height = aircraftBitmap.getHeight() / 5; aircraft = new ArrayList<Plane>(); Aircraft.width = width; Aircraft.height = height; Aircraft.halfWidth = width >> 1; Aircraft.halfHeight = height >> 1; // 自機 f16Bitmap = (Bitmap) BitmapFactory.decodeResource(GV.res, R.drawable.f16); width = f16Bitmap.getWidth() / 4; height = f16Bitmap.getHeight() / 5; myPlane = new ArrayList<Plane>(); myPlane.add(new F16(GV.halfWidth - (width >> 1), GV.scaleHeight, width, height, 0, 0, width, height, 5, Color.WHITE, 270)); // 設定觸控位置在中下方 GV.x = GV.halfWidth; GV.y = GV.scaleHeight - height; // 子彈 bulletBitmap1 = BitmapFactory .decodeResource(GV.res, R.drawable.bullet1); // 背景 backGroundImage = (Bitmap) BitmapFactory.decodeResource(GV.res, R.drawable.water); // 背景物件 backGroundObj = new Object2D(0, 0, GV.scaleWidth / backGroundImage.getWidth(), GV.scaleHeight / backGroundImage.getHeight(), 0, 0, 0, 0, 0, 0, 0); backGroundObj.isAlive = true; // 文字 fpsText = new Text(GV.halfWidth, 20, 12, "FPS", Color.YELLOW); // 爆炸 boomBitmap = BitmapFactory.decodeResource(GV.res, R.drawable.boom2); Boom.size = boomBitmap.getWidth() / Boom.col; Boom.halfSize = Boom.size >> 1; // 發射的特效 shootEffectBitmap = BitmapFactory.decodeResource(GV.res, R.drawable.effect); ShootEffect.width = shootEffectBitmap.getWidth(); ShootEffect.height = shootEffectBitmap.getHeight(); ShootEffect.halfWidth = ShootEffect.width >> 1; ShootEffect.halfHeight = ShootEffect.height >> 1; // 紅色Mask redMask = new RedMask(Color.RED, 0); // 黑色Mask blackMask = new Object2D(0, 0, GV.scaleWidth, GV.scaleHeight, Color.BLACK, 128); gameOverText = new Text(20, GV.halfHeight-18, 36, "Game Over", Color.WHITE); // 蜘蛛 spiderBitmap = BitmapFactory.decodeResource(GV.res, R.drawable.spider); Spider.width = spiderBitmap.getWidth(); Spider.height = spiderBitmap.getHeight(); spiderObj = new ArrayList<Plane>(); // 蜘蛛背景 spiderBackGroundBitmap = BitmapFactory.decodeResource(GV.res, R.drawable.spider_scene); // 蜘蛛背景物件 spiderBackGroundObj = new Object2D(0,-GV.scaleHeight,GV.scaleWidth,GV.scaleHeight,0, 0, spiderBackGroundBitmap.getWidth(), spiderBackGroundBitmap.getHeight(),0,Color.WHITE,0); super.LoadContent(); } @Override protected void UnloadContent() { super.UnloadContent(); } @Override protected void Update() { frameTime = (int)game.totalFrames; // 在遊戲中初始化飛機(對映到下方的Action) switch ((int) game.totalFrames) { case 150: // 5秒 aircraft.add(new Aircraft(GV.halfWidth - Aircraft.halfWidth, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); break; case 240: // 8秒 aircraft.add(new Aircraft(20, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); break; case 330: // 11秒 aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step1)); aircraft.add(new Aircraft(30, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.GREEN, 90, State.step1)); aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 30, -Aircraft.height, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.GREEN, 90, State.step2)); break; case 450: // 15秒 左邊連續出現 for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.RED, 90, State.step1)); } break; case 540: // 18秒 中間連續出現 for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(GV.halfWidth - Aircraft.halfWidth, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.BLUE, 90, State.step2)); } break; case 630: // 21秒 右邊連續出現 for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.GRAY, 90, State.step1)); } break; case 750: // 25秒 左跟右連續出現 for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); } for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.YELLOW, 90, State.step2)); } break; case 930: // 31秒 for (f = 0; f < 5; f++) { aircraft.add(new Aircraft(GV.halfWidth - Aircraft.halfWidth, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.BLACK, 90, State.step1)); } break; case 1020: // 34 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(-Aircraft.width, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); } break; case 1110: // 37 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step4)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step4)); } break; case 1200: // 40 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step4)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step4)); } break; case 1290: // 43 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step4)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step4)); } break; case 1380: // 46 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step3)); } break; case 1470: // 49 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step3)); } break; case 1560: // 52 for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); } for (f = 0; f < 3; f++) { aircraft.add(new Aircraft(20, -GV.halfHeight + (-Aircraft.halfHeight - 20) * (f + 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); } break; case 1650: // 55 aircraft.add(new Aircraft(GV.halfWidth - Aircraft.width, -Aircraft.halfHeight - 20, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step1)); aircraft.add(new Aircraft(GV.halfWidth + Aircraft.width, -Aircraft.halfHeight - 20, Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step1)); aircraft.add(new Aircraft(GV.halfWidth - (Aircraft.width << 1), -(Aircraft.halfHeight << 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); aircraft.add(new Aircraft(GV.halfWidth + (Aircraft.width << 1), -(Aircraft.halfHeight << 1), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 90, State.step2)); aircraft.add(new Aircraft(GV.halfWidth + Aircraft.width * 3, -(Aircraft.halfHeight * 3), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step3)); aircraft.add(new Aircraft(GV.halfWidth - (Aircraft.width * 3), -(Aircraft.halfHeight * 3), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step3)); aircraft.add(new Aircraft(20, -(Aircraft.halfHeight << 2), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 45, State.step4)); aircraft.add(new Aircraft(GV.scaleWidth - Aircraft.width - 20, -(Aircraft.halfHeight << 2), Aircraft.width, Aircraft.height, 0, 0, Aircraft.width, Aircraft.height, 5, Color.WHITE, 135, State.step4)); break; case 1800: // 60 redMask.isAlive = true; break; case 1950: // 65 // 蜘蛛背景音樂 GV.music.player.release(); GV.music = new Music(game.bee, R.raw.spidermusic, 1); GV.music.Play(); spiderObj.add(new Spider(GV.halfWidth - (Spider.width >> 1), -Spider.height , Spider.width, Spider.height, 0, 0, spiderBitmap.getWidth(),spiderBitmap.getHeight() , 5, Color.WHITE, 90)); break; } // 蜘蛛 for (f = spiderObj.size() - 1; f >= 0; f--) { plane = spiderObj.get(f); // 子彈移動 plane.AllBulletMove(); if (plane.isAlive) { // 被大絕打到 if (F16.isTouchBoom) { // 損血 plane.blood -= F16.bigBoomPower; // 直接進行碰撞 plane.Collisioned(frameTime, boom); } // 蜘蛛行動 plane.Action(frameTime, myPlane.get(0), shootEffect); } else { // 破關 breakOff = true; // 蜘蛛炮管 for (j = plane.barrel.size() - 1; j >= 0; j--) { // 子彈數量 if (plane.barrel.get(j).bullet.size() != 0) break; } // 所有子彈消失後移除蜘蛛 if (j == -1) spiderObj.remove(f); } // 檢查子彈與F16碰撞 plane.CheckBulletCollision(frameTime, myPlane, boom); } // 檢查蜘蛛與自機碰撞 Plane.CheckPlaneCollision((int) game.totalFrames, spiderObj, myPlane,boom); // 檢查民航機與自機碰撞 Plane.CheckPlaneCollision((int) game.totalFrames, aircraft, myPlane, boom); // aircraft民航機行動 for (f = aircraft.size() - 1; f >= 0; f--) { plane = aircraft.get(f); // 被大絕招打到 if (F16.isTouchBoom) { // 損血 plane.blood -= F16.bigBoomPower; // 直接進行碰撞 plane.Collisioned(frameTime, boom); } // 子彈移動 plane.AllBulletMove(); if (plane.isAlive) plane.Action((int) game.totalFrames, myPlane.get(0), shootEffect); else { // 民航機炮管 for (j = plane.barrel.size() - 1; j >= 0; j--) { // 子彈數量 if (plane.barrel.get(j).bullet.size() != 0) break; } // 所有子彈消失後移除民航機 if (j == -1) aircraft.remove(f); } } // 自機 for (f = myPlane.size() - 1; f >= 0; f--) { plane = myPlane.get(f); // 子彈移動 plane.AllBulletMove(); // 自機行動 if (plane.isAlive) plane.Action((int) game.totalFrames, shootEffect); // 檢查自機子彈與民航機碰撞 plane.CheckBulletCollision((int) game.totalFrames, aircraft, boom); // 檢查自機子彈與蜘蛛碰撞 plane.CheckBulletCollision(frameTime, spiderObj, boom); } // 檢查民航機子彈與自機的碰撞 for (f = aircraft.size() - 1; f >= 0; f--) { aircraft.get(f).CheckBulletCollision((int) game.totalFrames, myPlane, boom); } // 大絕招 if (F16.isTouchBoom) { // 新增爆炸 boom.add(new Boom(0, 0, GV.scaleWidth, GV.scaleHeight)); F16.isTouchBoom = false; } // 爆炸動畫 for (f = boom.size() - 1; f >= 0; f--) { subBoom = boom.get(f); subBoom.Animation(); if (!subBoom.isAlive) boom.remove(f); } // 發射特效 for (f = shootEffect.size() - 1; f >= 0; f--) { if (shootEffect.get(f).Animation()) { shootEffect.remove(f); } } // 紅色遮罩淡入淡出 if (redMask.isAlive) { redMask.Action(frameTime); // 設為切換背景 spiderBackGroundObj.isAlive = true; } // 一般背景捲動 if (backGroundObj.isAlive) { backGroundObj.addY(1); // 不斷循環 backGroundObj.setY(backGroundObj.getY() % backGroundImage.getHeight()); } // 如果是一般背景狀態 if (spiderBackGroundObj.isAlive) { // 蜘蛛背景捲動 if (spiderBackGroundObj.getY() < 0) { spiderBackGroundObj.addY(1); } else backGroundObj.isAlive = false; } // 更新fps顯示 fpsText.message = (int) game.actualFPS + " FPS (" + (int) game.fps + ") " + (int) game.totalFrames; // 重新初始化 if (myPlane.get(0).life == 0 || breakOff) { if (!isBlackMask) { isBlackMask = true; gameOverText.isVisible = true; startBlackMaskFrame = frameTime; } // 重新遊戲 if (frameTime - startBlackMaskFrame > restartDelayFrame) { GV.music.Stop(); GameStateClass.changeState(GameState.Menu, this, game); } } // 10ms後震動100ms // vibrator.vibrate(new long[]{10,100},-1); super.Update(); } @Override protected void Draw() { // 取得canvas subCanvas = game.canvas; // 一般背景 if (backGroundObj.isAlive) { for (f = 0; f <= backGroundObj.destWidth; f++) { for (j = -1; j <= backGroundObj.destHeight; j++) { subCanvas.drawBitmap(backGroundImage, f * backGroundImage.getWidth() + backGroundObj.destRect.left, j * backGroundImage.getHeight() + backGroundObj.destRect.top, null); } } } // 蜘蛛背景 if (spiderBackGroundObj.isAlive) { subCanvas.drawBitmap(spiderBackGroundBitmap, spiderBackGroundObj.srcRect,spiderBackGroundObj.destRect,null); } // 蜘蛛 for (f = spiderObj.size() - 1; f >= 0; f--) { plane = spiderObj.get(f); if (plane.isAlive) { subCanvas.save(); subCanvas.rotate(plane.theta - 90, plane.getX() + plane.halfWidth, plane.getY() + plane.halfHeight); subCanvas.drawBitmap(spiderBitmap, plane.srcRect, plane.destRect, plane.paint); subCanvas.restore(); subCanvas.drawRect(((Spider)plane).bloodObj.destRect,((Spider)plane).bloodObj.paint); } // 子彈 for (j = plane.barrel.size() - 1; j >= 0; j--) { for (k = plane.barrel.get(j).bullet.size() - 1; k >= 0 ;k--) { bullet = plane.barrel.get(j).bullet.get(k); subCanvas.drawBitmap(bulletBitmap1, bullet.getX(), bullet.getY(),bullet.paint); } } } // 民航機 for (f = aircraft.size() - 1; f >= 0; f--) { plane = aircraft.get(f); if (plane.isAlive) { subCanvas.save(); subCanvas.rotate(plane.theta - 90, plane.getX() + Aircraft.halfWidth, plane.getY() + Aircraft.halfHeight); subCanvas.drawBitmap(aircraftBitmap, plane.srcRect, plane.destRect, plane.paint); subCanvas.restore(); } // 民航機子彈 for (j = plane.barrel.size() - 1; j >= 0; j--) { for (k = plane.barrel.get(j).bullet.size() - 1; k >= 0; k--) { bullet = plane.barrel.get(j).bullet.get(k); subCanvas.drawBitmap(bulletBitmap1, bullet.getX(), bullet .getY(), bullet.paint); } } } // 自機 for (f = myPlane.size() - 1; f >= 0; f--) { plane = myPlane.get(f); if (plane.isAlive) subCanvas.drawBitmap(f16Bitmap, plane.srcRect, plane.destRect, plane.paint); // 自機炮管 for (j = plane.barrel.size() - 1; j >= 0; j--) { // 自機子彈 for (k = plane.barrel.get(j).bullet.size() - 1; k >= 0; k--) { bullet = plane.barrel.get(j).bullet.get(k); subCanvas.drawBitmap(bulletBitmap1, bullet.getX(), bullet .getY(), bullet.paint); } } } // 爆炸 for (f = 0; f < boom.size(); f++) { subBoom = boom.get(f); subCanvas.drawBitmap(boomBitmap, subBoom.srcRect, subBoom.destRect, subBoom.paint); } // 發射特效 for (f = shootEffect.size() - 1; f >= 0; f--) { subCanvas.drawBitmap(shootEffectBitmap, shootEffect.get(f).srcRect, shootEffect.get(f).destRect, shootEffect.get(f).paint); } // FPS文字 subCanvas.drawText(fpsText.message, fpsText.x, fpsText.y, fpsText.paint); // 紅色遮罩 if (redMask.isAlive) { subCanvas.drawRect(redMask.destRect, redMask.paint); // 警告訊息 subCanvas.drawText(redMask.warningText.message, redMask.warningText.x, redMask.warningText.y, redMask.warningText.paint); } // 黑色遮罩 if (isBlackMask) subCanvas.drawRect(blackMask.destRect, blackMask.paint); // gameover if (gameOverText.isVisible) subCanvas.drawText(gameOverText.message, gameOverText.x, gameOverText.y, gameOverText.paint); super.Draw(); } }
程式:DrawableGameComponent.java
package XNA.lbs; public class DrawableGameComponent { public DrawableGameComponent() { } public void Dispose() { UnloadContent(); } protected void Initialize() { } protected void LoadContent(){ } protected void UnloadContent() { } protected void Update() { } protected void Draw() { } }
程式:Game.java
package XNA.lbs; import android.graphics.Canvas; import Bee.main.GV; public class Game { // 是否為第一次跑 private boolean isRun; public GameComponentCollection Components = new GameComponentCollection(); public Canvas canvas = null; public long totalFrames; public int fps; public int actualFPS; public int setFPS = 30; private int fpsInterval = 1000 / setFPS; private Thread gameLoop; private int f; public Game() { } // 開始遊戲 public void Run() { // 如果是第一次跑則進行初始化並載入資源 if (!isRun) { Initialize(); LoadContent(); // 設為已跑過 isRun = true; } gameLoop = new Thread(new GameLoop()); gameLoop.setDaemon(true); gameLoop.start(); } // 離開遊戲 public void Exit() { if (gameLoop != null) { gameLoop.interrupt(); } } class GameLoop implements Runnable { // 遊戲主迴圈 public void run() { long startTime; int delayTime; int sleepTime; while(!Thread.interrupted()) { startTime = System.currentTimeMillis(); // 動作更新 Update(); // 畫面更新 Draw(); delayTime = (int)(System.currentTimeMillis() - startTime); if (delayTime == 0) delayTime = 1; fps = 1000 / delayTime; // 如果太快就延遲 sleepTime = fpsInterval - delayTime; if (sleepTime > 0) { actualFPS = 1000 / fpsInterval; try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } }else { actualFPS = 1000 / delayTime; } } } } protected void Initialize() { } protected void LoadContent(){ } protected void UnloadContent() { Exit(); } protected void Update() { for (f = Components.size() -1 ; f >= 0; f--) Components.get(f).Update(); } protected void Draw() { for (f = Components.size() -1 ; f >= 0; f--) Components.get(f).Draw(); // 解除鎖定 GV.surface.mHolder.unlockCanvasAndPost(canvas); totalFrames++; } }
程式:GameComponentCollection.java
package XNA.lbs; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; public class GameComponentCollection implements Collection<DrawableGameComponent>{ protected List<DrawableGameComponent> componse = new ArrayList<DrawableGameComponent>(); public boolean add(DrawableGameComponent arg0) { arg0.Initialize(); arg0.LoadContent(); return componse.add(arg0); } public DrawableGameComponent get(int arg0) { return componse.get(arg0); } public void add(int arg0,DrawableGameComponent arg1) { componse.add(arg0, arg1); } public boolean addAll(Collection<? extends DrawableGameComponent> arg0) { // TODO Auto-generated method stub return componse.addAll(arg0); } public void clear() { componse.clear(); } public boolean contains(Object arg0) { // TODO Auto-generated method stub return componse.contains(arg0); } public boolean containsAll(Collection<?> arg0) { // TODO Auto-generated method stub return componse.containsAll(arg0); } public boolean isEmpty() { // TODO Auto-generated method stub return componse.isEmpty(); } public Iterator<DrawableGameComponent> iterator() { // TODO Auto-generated method stub return componse.iterator(); } public boolean remove(Object arg0) { return componse.remove(arg0); } public boolean removeAll(Collection<?> arg0) { // TODO Auto-generated method stub return componse.removeAll(arg0); } public boolean retainAll(Collection<?> arg0) { // TODO Auto-generated method stub return componse.retainAll(arg0); } public int size() { // TODO Auto-generated method stub return componse.size(); } public Object[] toArray() { // TODO Auto-generated method stub return componse.toArray(); } public <T> T[] toArray(T[] arg0) { // TODO Auto-generated method stub return componse.toArray(arg0); } }
程式:Game.java
package Gps; public class GPS { // 經度 public static double lng = 0.0; // 緯度 public static double lat = 0.0; // 經度絕對點 public static int lngX = 0; // 緯度絕對點 public static int latY = 0; // 上一次的經緯度絕對點 public static int oldLngX = 0; public static int oldLatY = 0; // 地圖縮放係數 public static int zoom = 22; public static void setLng(double x) { oldLngX = lngX; lng = x; lngX = LngToX(x); } public static void setLat(double y) { oldLatY = latY; lat = y; latY = LatToY(y); } // 經度轉成點(point) public static int LngToX(double Longitude) { int numberOfTiles = 1 << zoom << 8; return (int)((Longitude + 180.0) * numberOfTiles / 360.0); } // 緯度轉成點(point) public static int LatToY(double Latitude) { int numberOfTiles = 1 << zoom << 8; double projection = Math.log(Math.tan(Math.PI / 4 + ((Latitude / 180 * Math.PI) / 2))); double y = (projection / Math.PI); y = 1.0 - y; y = y / 2.0 * numberOfTiles; return (int)y; } }
程式:Game.java
package Gps; import BeeGPS.main.GV; import android.location.Location; import android.location.LocationListener; import android.os.Bundle; // GPS監聽者 public class MyLocationListener implements LocationListener { // GPS位置事件更新 public void onLocationChanged(Location loc) { if (loc != null){ // 設定經緯度 GPS.setLng(loc.getLongitude()); GPS.setLat(loc.getLatitude()); if (GPS.oldLngX != 0) { if (GPS.oldLatY != 0) { // 更新F16位置 GV.x += GPS.lngX - GPS.oldLngX; GV.y += GPS.latY - GPS.oldLatY; } } } } public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } }
AndroidManifest.xml為使用權限:
<?xml version="1.0" encoding="utf-8"?> <manifest package="BeeGPS.main" android:versionCode="1" android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name=".BeeGPS" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="4" /> <!-- 震動權限 --> <uses-permission android:name="android.permission.VIBRATE"/> <!-- 恆亮權限 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- GPS權限設定 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
程式影片解說
程式手機執行影片
page revision: 20, last edited: 26 Dec 2010 09:33
Post preview:
Close preview