貪食蛇遊戲
手機遊戲-貪食蛇
遊戲玩法:在時間限制內,將蘋果一一吃盡,每吃得一個蘋果可增加遊戲分數1分,並且可增加遊戲時間3秒,但是撞到牆壁或是本身會進行扣分(每次扣除1分)。
說明:此範例可進行螢幕觸控來控制蛇的移動方向,並且也可以使用手機上的按鍵來進行遊戲,其最大的特色就是在於可進行3600方向移動與一般的貪食蛇只能上下左右有所不同。
下圖為遊戲畫面、程式的狀態圖、架構圖及流程圖::
圖一-遊戲執行畫面
圖二-程式架構圖
圖三-遊戲流程圖
圖四-程式流程
圖五-遊戲狀態圖
以下為貪食蛇遊戲的程式碼:
專案下載:GameSnake1204_final2.rar
主程式:GameSnake.java
package ccc.GameSnake; import android.app.Activity; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.os.Bundle; import android.os.PowerManager; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; import android.view.KeyEvent; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; public class GameSnake extends Activity { SurfaceView gameSurfaceView; SurfaceHolder surfaceHolder; Thread gameThread; Boolean isGameThreadStop = true; GameObj backimg; int gameFPS = 25; KeyHandler keyHandler = new KeyHandler(); TouchPoint touchPoint = new TouchPoint(); PowerManager.WakeLock wakeLock; drawAction nowDrawWork; SnakeObj snake; AppleObj apple; GameStat gameStat; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 隱藏狀態列 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 隱藏視窗標題 requestWindowFeature(Window.FEATURE_NO_TITLE); // 防止手機因手持方向不同 而觸發螢幕方向旋轉 setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT); // 電源管理服務取得 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GameSnake PowerControl"); gameSurfaceView = new SurfaceView(this); surfaceHolder = gameSurfaceView.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { public void surfaceDestroyed(SurfaceHolder arg0) { } public void surfaceCreated(SurfaceHolder arg0) { if (backimg == null) { // 第一次Activity載入時 Resources rs = getResources(); backimg = new GameObj(rs.getDrawable(R.drawable.backimg)); SurfaceView sv = gameSurfaceView; backimg.setRect(new Rect(sv.getLeft(), sv.getTop(), sv .getRight(), sv.getBottom())); readyGame(); } else { // 經由Activity返回載入時 draw(nowDrawWork); openOptionsMenu(); } } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { } }); setContentView(gameSurfaceView); } /** * 電源控制 防止進入休眠狀態切換 */ protected void powerControl(boolean needWake) { if (needWake && !wakeLock.isHeld()) { wakeLock.acquire(); } else if (!needWake && wakeLock.isHeld()) { wakeLock.release(); } } @Override protected void onPause() { pauseGame(); super.onPause(); }; protected static final int MENU_Resume = Menu.FIRST; protected static final int MENU_Reset = Menu.FIRST + 1; protected static final int MENU_Quit = Menu.FIRST + 2; @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_Resume, 0, "繼續"); menu.add(0, MENU_Reset, 0, "重新開始"); menu.add(0, MENU_Quit, 0, "離開"); return super.onCreateOptionsMenu(menu); }; @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_Resume: resumeGame(); break; case MENU_Reset: readyGame(); break; case MENU_Quit: gameExit(); break; } return super.onOptionsItemSelected(item); } @Override public boolean onMenuOpened(int featureId, Menu menu) { pauseGame(); return super.onMenuOpened(featureId, menu); }; void gameExit() { gameThreadStop(); if (gameThread != null) { try { gameThread.join(); } catch (InterruptedException e) { } } finish();// 結束遊戲 } @Override public boolean onTouchEvent(android.view.MotionEvent event) { if (nowDrawWork == drawAction.game) touchPoint.update(event); return true; }; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { keyHandler.keyDown(keyCode); return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { keyHandler.keyUp(keyCode); return super.onKeyUp(keyCode, event); } public void gameThreadStart() { isGameThreadStop = false; powerControl(true); if (gameThread == null) { gameThread = new Thread(gameRun); gameThread.start(); } else if (!gameThread.isAlive()) { gameThread = new Thread(gameRun); gameThread.start(); } } public void gameThreadStop() { isGameThreadStop = true; powerControl(false); } // 準備遊戲 void readyGame() { gameThreadStop(); nowDrawWork = drawAction.ready; Resources rs = getResources(); snake = new SnakeObj(GameSnake.this, backimg.getRect()); apple = new AppleObj(rs.getDrawable(R.drawable.apple), backimg .getRect()); apple.random(backimg.getRect()); gameStat = new GameStat(System.currentTimeMillis() + 3000); gameThreadStart(); } // 開始遊戲 void startGame() { gameStat = new GameStat(System.currentTimeMillis() + 30000); nowDrawWork = drawAction.game; } // 暫停遊戲 void pauseGame() { gameThreadStop(); if (nowDrawWork != drawAction.over) { gameStat.timePause(); draw(drawAction.pause); } } // 繼續遊戲 void resumeGame() { if (nowDrawWork != drawAction.over) { gameThreadStart(); gameStat.timeResume(); } } Runnable gameRun = new Runnable() { public void run() { long delayTime = 1000 / gameFPS; while (!isGameThreadStop) { long startTime = System.currentTimeMillis(); if (nowDrawWork == drawAction.game) gameUpdate(); draw(nowDrawWork); long endTime = System.currentTimeMillis(); long waitTime = delayTime - (startTime - endTime); if (waitTime > 0) { try { Thread.sleep(waitTime); } catch (InterruptedException e) { } } } } }; boolean isKeyDown(int keyCode) { return keyHandler.isKeyDown(keyCode); } /** * 遊戲更新 */ void gameUpdate() { boolean isChangeMove = false; // 觸控事件處理 if (touchPoint.isChangeVector) { snake.move(touchPoint.lastVectorX, touchPoint.lastVectorY); isChangeMove = true; } else { // 按鍵事件處理 if (isKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT)) { snake.move(1, 0); isChangeMove = true; } if (isKeyDown(KeyEvent.KEYCODE_DPAD_LEFT)) { snake.move(-1, 0); isChangeMove = true; } if (isKeyDown(KeyEvent.KEYCODE_DPAD_UP)) { snake.move(0, -1); isChangeMove = true; } if (isKeyDown(KeyEvent.KEYCODE_DPAD_DOWN)) { snake.move(0, 1); isChangeMove = true; } } // 沒有改變移動則往之前方向移動 if (!isChangeMove) snake.move(); // 更新貪食蛇 snake.update(); // 吃到蘋果處理 if (snake.isEatApple(apple)) { // 增加長度 snake.add(); // 增加時間 gameStat.addTime(3000); // 蘋果位置變更 while (snake.isEatApple(apple)) apple.random(backimg.getRect()); } // 更新遊戲分數 gameStat.updateScroe(snake.getLength()); // 判斷是否結束遊戲 if (gameStat.isTimeOver()) nowDrawWork = drawAction.over; } // 畫面繪圖種類 enum drawAction { ready, game, pause, over } // 畫面繪圖處理 void draw(drawAction action) { Canvas canvas = null; try { canvas = surfaceHolder.lockCanvas(null); synchronized (surfaceHolder) { draw(action, canvas); } } finally { if (canvas != null) { surfaceHolder.unlockCanvasAndPost(canvas); } } } // 畫面繪圖函數選擇 void draw(drawAction action, Canvas canvas) { switch (action) { case ready: drawReady(canvas); break; case game: drawGame(canvas); break; case pause: drawPause(canvas); break; case over: drawOver(canvas); break; } } // 畫準備開始 void drawReady(Canvas canvas) { clear(canvas); Paint pt = new Paint(); pt.setTextAlign(Paint.Align.CENTER); pt.setARGB(255, 0, 0, 255); pt.setTextSize(30); canvas.drawText(gameStat.getCountdownTime() + "秒後遊戲開始-", backimg .centerX(), backimg.centerY(), pt); if (gameStat.isTimeOver()) startGame(); } // 畫遊戲中 void drawGame(Canvas canvas) { clear(canvas); apple.draw(canvas); snake.draw(canvas); gameStat.draw(canvas); touchPoint.draw(canvas); } // 畫暫停 void drawPause(Canvas canvas) { draw(nowDrawWork, canvas); Paint pt = new Paint(); pt.setARGB(30, 0, 0, 100); canvas.drawRect(backimg.getRect(), pt); pt.setTextAlign(Paint.Align.CENTER); pt.setARGB(150, 200, 200, 200); pt.setTextSize(50); canvas.drawText("-遊戲暫停-", backimg.centerX(), backimg.centerY(), pt); } // 畫遊戲結束 void drawOver(Canvas canvas) { // 執行緒停止 gameThreadStop(); drawGame(canvas); Paint pt = new Paint(); pt.setARGB(30, 30, 30, 30); canvas.drawRect(backimg.getRect(), pt); pt.setTextAlign(Paint.Align.CENTER); pt.setARGB(100, 0, 0, 255); pt.setTextSize(50); canvas.drawText("-遊戲結束-", backimg.centerX(), backimg.centerY(), pt); } void clear(Canvas canvas) { Paint p = new Paint(); p.setARGB(100, 0, 0, 0); backimg.draw(canvas); } }
程式:GameObj.java
package ccc.GameSnake; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; public class GameObj { /** * 物件顯示角度 */ public float angle; /** * 物件影像資源 */ public Drawable drawable; /** * 是否顯示 */ public boolean Visible = true; /** * 控制致能 */ public boolean Enable = true; /** * 暫存的物件位置 */ private Rect saveRect; /** * 暫存的物件角度 */ public float saveAngle; public GameObj(Drawable drawable) { this.drawable = drawable; drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable .getIntrinsicHeight()); this.save(); } public GameObj(GameObj gameObj,Drawable drawable) { this.drawable = drawable; this.drawable.setBounds(gameObj.drawable.copyBounds()); this.angle=gameObj.angle; this.save(); } /** * 儲存目前物件狀態 */ public void save() { if (Enable) { saveRect = drawable.copyBounds(); saveAngle = angle; } } /** * 恢復物件狀態 */ public void restore() { if (Enable) { drawable.setBounds(saveRect); angle = saveAngle; } } /** * 旋轉物件 */ public void rotate(float angle) { if (Enable) { this.angle += angle; this.angle %= 360; } } /** * 設定物件角度 */ public void setAngle(float angle) { if (Enable) { this.angle = angle; this.angle %= 360; } } /** * 得到物件角度 */ public float getAngle(float angle) { return angle; } /** * 移動物件到新的座標點上 */ public void moveTo(int newLeft, int newTop) { if (Enable) { Rect rect = drawable.getBounds(); drawable.setBounds(newLeft, newTop, newLeft + rect.width(), newTop + rect.height()); } } /** * 移動物件到新的座標點上 */ public void moveTo(float newLeft, float newTop) { moveTo((int)newLeft,(int)newTop); } /** * 物件移動一個向量距離 */ public void move(int dx, int dy) { if (Enable) { Rect rect = drawable.getBounds(); drawable.setBounds(rect.left + dx, rect.top + dy, rect.right + dx, rect.bottom + dy); } } /** * 物件移動一個向量距離 */ public void move(float dx, float dy) { move((int)dx,(int)dy); } /** * 物件範圍縮放 */ public void scale(int addScaleX, int addScaleY) { if (Enable) { Rect rect = drawable.getBounds(); drawable.setBounds(rect.left - addScaleX, rect.top - addScaleY, rect.right + addScaleX, rect.bottom + addScaleY); } } public void draw(Canvas canvas) { if (Visible) { canvas.save(); canvas.rotate(angle, drawable.getBounds().centerX(), drawable .getBounds().centerY()); drawable.draw(canvas); canvas.restore(); } } /** * 得到物件中心X座標 */ public int centerX() { return drawable.getBounds().centerX(); } /** *得到物件中心Y座標 */ public int centerY() { return drawable.getBounds().centerY(); } /** * 得到物件範圍 */ public Rect getRect() { return drawable.getBounds(); } /** * 得到物件高度 */ public int getHeight() { return drawable.getBounds().height(); } /** * 得到物件寬度 */ public int getWidth() { return drawable.getBounds().width(); } /** * 得到原始影像高度 */ public int getSrcHeight() { return drawable.getIntrinsicHeight(); } /** * 得到原始影像寬度 */ public int getSrcWidth() { return drawable.getIntrinsicWidth(); } /** * 設定物件範圍 */ public void setRect(Rect rect) { drawable.setBounds(rect); } /** * 設定物件範圍 */ public void setRect(int left, int top, int right, int bottom) { drawable.setBounds(left, top, right, bottom); } /** * 判斷物件使否與參數範圍相交 * 當相交時自動調整物件範圍 */ public boolean intersect(Rect r) { return drawable.getBounds().intersect(r); } /** * 判斷物件使否與參數範圍相交 * 當相交時自動調整物件範圍 */ public boolean intersect(GameObj obj) { return this.intersect(obj.getRect()); } /** * 判斷物件範圍是否包函與參數範圍 */ public boolean contains(Rect r) { return drawable.getBounds().contains(r); } /** * 判斷物件範圍是否包函與參數範圍 */ public boolean contains(GameObj obj) { return this.contains(obj.getRect()); } /** * 判斷物件範圍是否包函與參數點 */ public boolean contains(int x,int y) { return drawable.getBounds().contains(x, y); } }
程式:SnakeObj.java
package ccc.GameSnake; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; /** * @author Administrator * */ public class SnakeObj { private class exGameObj extends GameObj { /** *下次更新時的座標點位置 */ public PointF nextMove = new PointF(); /** * 歷史的座標點位置 */ public PointF[] logPath = new PointF[3]; public exGameObj(Drawable drawable) { super(drawable); init(); } public exGameObj(exGameObj gameObj, Drawable drawable) { super(gameObj, drawable); init(); } /** * 物件初始化 */ private void init() { for (int i = 0; i < logPath.length; i++) { logPath[i] = new PointF(); } } /** *進行座標點更新 */ public void updataMove() { // 取得位置移動向量 float dx = nextMove.x - logPath[0].x; float dy = nextMove.y - logPath[0].y; // 歷史座標更新 for (int i = logPath.length - 1; i > 0; i--) { logPath[i].set(logPath[i - 1].x, logPath[i - 1].y); } logPath[0].set(nextMove.x, nextMove.y); // 座標點更新 this.moveTo(nextMove.x - this.getWidth() / 2, nextMove.y - this.getHeight() / 2); // 判斷移動向量距離大於5以上進行角度更新 if (dx * dx + dy * dy > 4 * 4) { this.angle = (float) (Math.atan2(dy, dx) * 180 / Math.PI); } } } /** * 頭部物件 */ private exGameObj head; /** * 身體物件 */ private List<exGameObj> bodys = new ArrayList<exGameObj>(); /** * 尾部物件 */ private exGameObj tail; /** * 資源檔 */ private Resources rs; /** * 活動限制範圍 */ private Rect actRect; /** * 目標移動向量X */ private float dstVectorX = 1; /** * 目標移動向量Y */ private float dstVectorY = 0; public SnakeObj(Activity content, Rect actRect) { this.actRect = actRect; rs = content.getResources(); // 頭部影像資源 Drawable d_head = rs.getDrawable(R.drawable.head); // 身體影像資源 Drawable d_body = rs.getDrawable(R.drawable.body); // 尾部影像資源 Drawable d_tail = rs.getDrawable(R.drawable.tail); //初始化貪食蛇物件 head = new exGameObj(d_head); exGameObj body = new exGameObj(d_body); tail = new exGameObj(d_tail); init(head); init(body); init(tail); bodys.add(body); } /** * 設定物件起始位置 */ private void init(exGameObj obj) { float x = actRect.centerX(); float y = actRect.centerY(); obj.nextMove.set(x, y); for (int i = 0; i < obj.logPath.length; i++) { obj.logPath[i].set(x, y); } } /** * 得到目前身體長度 */ public int getLength() { return bodys.size() - 1; } /** * 畫出貪食蛇 */ public void draw(Canvas canvas) { tail.draw(canvas); for (int i = 0; i < bodys.size(); i++) { bodys.get(bodys.size() - 1 - i).draw(canvas); } head.draw(canvas); } /** * 進行貪食蛇更新 */ public void update() { //更新尾部位置 updataMove(bodys.get(bodys.size() - 1), tail); //更新身體位置 for (int i = bodys.size() - 1; i >= 0; i--) { exGameObj moveObj = bodys.get(i); if (i == 0) { updataMove(head, moveObj); } else { updataMove(bodys.get(i - 1), moveObj); } } //更新頭部位置 head.updataMove(); //頭與身體相撞處理 for (int i = 1; i < bodys.size(); i++) { Rect h = new Rect(head.getRect()); Rect b = new Rect(bodys.get(i).getRect()); //碰撞偵測微調 scaleRect(h, -5, -5); scaleRect(b, -10, -10); if (Rect.intersects(h, b)) { this.cut(); break; } } } //更新貪食蛇物件節點的移動 private void updataMove(exGameObj fd, exGameObj bk) { bk.updataMove(); PointF fwp = fd.logPath[fd.logPath.length - 1]; bk.nextMove.set(fwp.x, fwp.y); } /** * 範圍縮放長寬調整 * @param rect * @param scaleX * @param scaleY */ private void scaleRect(Rect rect, int scaleX, int scaleY) { rect.set(rect.left - scaleX, rect.top - scaleY, rect.right + scaleX, rect.bottom + scaleY); } /** * 範圍縮放長寬調整 */ private void scaleRect(RectF rect, int scaleX, int scaleY) { rect.set(rect.left - scaleX, rect.top - scaleY, rect.right + scaleX, rect.bottom + scaleY); } /** * 得到一個-180~180之間的角度 */ private float getAngle(float angle, float addAngle) { angle += addAngle; angle %= 360; if (angle > 180) angle -= 360; if (angle < -180) angle += 360; return angle; } /** * 設定移動向量 * @param dx * 移動向量X * @param dy * 移動向量Y */ public void move(float dx, float dy) { this.dstVectorX = dx; this.dstVectorY = dy; //目標旋轉角度 float rotateAngle = getAngleByXY(dx, dy); //限制更新角度大小 float limitAngle = 25; //左旋角度最大值(逆時鐘) float limitLeftAngle = getAngle(head.angle, limitAngle); //右旋角度最大值(順時鐘) float limitRightAngle = getAngle(head.angle, -limitAngle); //當更新目標點角度大於限制可選轉角度時 進行旋轉角度調整 if (Math.abs(getAngle(rotateAngle, -head.angle)) > limitAngle) { if (getAngle(rotateAngle, -head.angle) > 0) { //左旋時 rotateAngle = limitLeftAngle; } else { //右旋時 rotateAngle = limitRightAngle; } } //設定頭部方向 head.angle = rotateAngle; //取得頭部下次更新座標 double dreg = head.angle * Math.PI / 180; int moveDistance=6; dx = (float) Math.cos(dreg) * moveDistance; dy = (float) Math.sin(dreg) * moveDistance; float ndx = head.logPath[0].x + dx; float ndy = head.logPath[0].y + dy; //取得邊緣範圍 RectF limitRect = new RectF(actRect); //取得物件可移動範圍 scaleRect(limitRect, -head.getWidth() / 2, -head.getHeight() / 2); //進行邊緣碰撞偵測調整 if (!limitRect.contains(ndx, ndy)) { boolean isTouchEdge = false; if (ndx < limitRect.left) {//左邊邊緣偵測 if (head.angle < 0) head.angle = limitLeftAngle; else head.angle = limitRightAngle; ndx = limitRect.left; isTouchEdge = true; } if (ndx > limitRect.right) {//右邊邊緣偵測 if (head.angle > 0) head.angle = limitLeftAngle; else head.angle = limitRightAngle; ndx = limitRect.right; isTouchEdge = true; } if (ndy < limitRect.top) {//頂部邊緣偵測 if (head.angle > -90) head.angle = limitLeftAngle; else head.angle = limitRightAngle; ndy = limitRect.top; isTouchEdge = true; } if (ndy > limitRect.bottom) {//底部邊緣偵測 if (head.angle > 90) head.angle = limitLeftAngle; else head.angle = limitRightAngle; ndy = limitRect.bottom; isTouchEdge = true; } if (isTouchEdge) { //減短長度 this.cut(); //調整目標向量 this.dstVectorX = (float) Math.cos(head.angle * Math.PI / 180); this.dstVectorY = (float) Math.sin(head.angle * Math.PI / 180); } } //下次頭部移動點設置 head.nextMove.set(ndx, ndy); } //移動之前方向 public void move() { move(this.dstVectorX, this.dstVectorY); } //取得直角坐標角度 private float getAngleByXY(float dx, float dy) { return (float) (Math.atan2(dy, dx) * 180 / Math.PI); } //增加身體長度 public void add() { exGameObj newBody = new exGameObj(tail, rs.getDrawable(R.drawable.body)); newBody.nextMove.set(tail.nextMove.x, tail.nextMove.y); for (int i = 0; i < tail.logPath.length; i++) { newBody.logPath[i].set(tail.logPath[i].x, tail.logPath[i].y); tail.logPath[i].set(tail.nextMove.x, tail.nextMove.y); } bodys.add(newBody); } //從第N個開始剪斷 public void cut(int bodyIndex) { if (bodyIndex>0&&bodyIndex < bodys.size()) { exGameObj lastBody = bodys.get(bodyIndex-1); tail.setRect(lastBody.getRect()); tail.nextMove.set(lastBody.nextMove.x, lastBody.nextMove.y); for (int i = 0; i < tail.logPath.length; i++) { tail.logPath[i].set(lastBody.logPath[i].x, lastBody.logPath[i].y); } for (int i = bodyIndex; i < bodys.size(); i++) { bodys.remove(bodys.size() - 1); } } } //減少一個身體長度 public void cut() { cut(bodys.size() - 1); } //判斷是否有吃到蘋果 public boolean isEatApple(GameObj apple) { return Rect.intersects(apple.getRect(), head.getRect()); } }
程式:AppleObj.java
package ccc.GameSnake; import java.util.Random; import android.graphics.Rect; import android.graphics.drawable.Drawable; public class AppleObj extends GameObj{ private Random r=new Random(); private Rect actRect; public AppleObj(Drawable drawable,Rect limitRect) { super(drawable); this.actRect=limitRect; } /** * 物件移動到隨機區域 */ public void random(Rect limitRect){ this.actRect=limitRect; this.moveTo(actRect.left+r.nextInt(actRect.width()-this.getWidth()),actRect.top+r.nextInt(actRect.height()-this.getHeight())); } /** * 物件移動到隨機區域 */ public void random(){ this.random(this.actRect); } }
程式:GameStat.java
package ccc.GameSnake; import android.graphics.Canvas; import android.graphics.Paint; public class GameStat { private Long startTime=0l; private Long overTime=0l; private Long pauseTime=0l; private boolean isTimePause=false; private int gameScore; public GameStat(long gameOverTime){ this.startTime=System.currentTimeMillis(); this.overTime=gameOverTime; } public void updateScroe(int gameScore){ this.gameScore=gameScore; } public void draw(Canvas canvas){ Paint pt=new Paint(); pt.setARGB(150, 255, 0, 0); pt.setTextSize(24); canvas.drawText("分數:"+this.gameScore, 20, 40, pt); canvas.drawText("剩餘時間:"+getCountdownTime(), 20, 80, pt); } /** * 得到距離結束時間秒數 */ public int getCountdownTime(){ if(!isTimeOver()){ if(isTimePause) return (int)((this.overTime-pauseTime)/1000)+1; else return (int)((this.overTime-System.currentTimeMillis())/1000)+1; } else{ return 0; } } /** *增加時間 */ public void addTime(int addMicroseconds){ overTime+=addMicroseconds; } public boolean isTimeOver(){ if(isTimePause) return pauseTime>overTime; else return System.currentTimeMillis()>overTime; } /** * 時間暫停 */ public void timePause(){ if(!isTimePause){ pauseTime=System.currentTimeMillis(); } isTimePause=true; } /** * 得到是否為時間暫停狀態 */ public boolean isTimePause(){ return this.isTimePause; } /** * 時間繼續 */ public void timeResume(){ if(isTimePause){ overTime=System.currentTimeMillis()+overTime-pauseTime; } isTimePause=false; } }
程式:KeyHandler.java
package ccc.GameSnake; import java.util.HashMap; import java.util.Map; public class KeyHandler { public Map<Integer,Boolean> MapKeyDown=new HashMap<Integer, Boolean>(); public KeyHandler(){ } public void keyDown(int keyCode){ MapKeyDown.put(keyCode, true); } public void keyUp (int keyCode){ MapKeyDown.put(keyCode, false); } public boolean isKeyDown(int keyCode){ Boolean isKeyUp=MapKeyDown.get(keyCode); if(isKeyUp!=null) return isKeyUp; else return false; } public boolean isKeyUp(int keyCode){ Boolean isKeyUp=MapKeyDown.get(keyCode); if(isKeyUp!=null) return isKeyUp; else return true; } }
程式:TouchPoint.java
package ccc.GameSnake; import java.util.ArrayList; import java.util.List; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; public class TouchPoint { //最後偵測向量X public float lastVectorX; //最後偵測向量Y public float lastVectorY; //是否有改變向量 public boolean isChangeVector=false; //觸控點座標 List<PointF> points = new ArrayList<PointF>(); public TouchPoint(){ } //處理觸控點座標 public void update(android.view.MotionEvent event){ for (int i = 0; i < event.getHistorySize(); i+=3) { points.add(new PointF(event.getHistoricalX(i), event .getHistoricalY(i))); } changeVector(); } //改變偵測觸控向量 private void changeVector(){ if (points.size() > 1) {//感測2點以上 this.lastVectorX = points.get(points.size() - 1).x - points.get(0).x; this.lastVectorY = points.get(points.size() - 1).y - points.get(0).y; } isChangeVector=true; } //畫出觸控點路徑 public void draw(Canvas canvas){ if (points.size() > 1) {//感測2點以上 Paint p = new Paint(); p.setARGB(255, 0, 0, 0); p.setStrokeWidth(3); for (int i = 0; i < points.size() - 1; i++) { float x1=points.get(i).x; float y1=points.get(i).y; float x2=points.get(i+1).x; float y2=points.get(i+1).y; canvas.drawLine(x1,y1,x2,y2, p); } } this.resetPoint(); } //重新偵測觸控向量 public void resetPoint(){ isChangeVector=false; points.clear(); } }
AndroidManifest.xml為使用權限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="ccc.GameSnake" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name" > <activity android:name="GameSnake" 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.WAKE_LOCK" /> </manifest>
程式影片解說
程式手機執行影片
page revision: 17, last edited: 20 Sep 2011 14:23
想請問一下為什麼在資料夾中沒有layout/main.xml ??
我測試了一下遊戲好像跑不起來…
小弟是Android新手,為了寫專題在苦惱然後找到了你的貪食蛇
望請解答,謝謝:)
Post preview:
Close preview