( ) 101.06
遊 戲 名 稱 圖 片 縮 放 相 關 類 別 與 元 件 程 式 與 執 行 結 果 遊 戲 名 稱 記 憶 遊 戲 相 關 類 別 與 元 件 程 式 與 執 行 結 果 參 考 文 件 - 元 件 宣 告 類 別 2
控 制 桌 面 上 的 圖 片 可 任 意 的 移 動 不 破 壞 方 位 可 縮 放 的 功 能 3 遊 戲 原 始 碼 來 源 :http://mate.idc.scu.edu.tw/android/
- 開 始 初 始 化 的 圖 片 經 過 縮 小 及 移 動 後 的 圖 示 4
-1 android.app.activity; //Eclipse 自 動 import 導 入 的 類 別 android.os.bundle; //Eclipse 自 動 import 導 入 的 類 別 android.content.context;// 使 用 監 聽 器 android.graphics.bitmap;// 點 陣 圖 基 本 操 作 類 別, 以 實 現 對 點 陣 圖 的 操 作 android.graphics.bitmapfactory;// 可 說 是 做 I/O 類 別 android.graphics.canvas;// 在 螢 幕 上 做 繪 圖 圖 案 動 作 等 android.graphics.matrix;// 控 制 圖 片, 例 如 做 縮 放 和 旋 轉 處 理 5
-2 android.util.attributeset;// 與 XML 檔 案 中 的 連 結 標 記 android.util.displaymetrics;// 來 描 述 畫 面 顯 示, 如 它 的 大 小, 密 度, 字 體 縮 放, 顯 示 一 般 資 訊 android.view.motionevent;// 用 於 觸 碰 螢 幕 的 軌 跡 時 的 感 應 類 別 android.view.scalegesturedetector; // 當 觸 碰 感 應 有 動 作 時, 即 回 傳 android.view.view; // 用 於 創 建 通 用 佈 局 中 的 組 件 之 間 的 差 距 android.view.window; // 使 用 螢 幕 android.view.windowmanager; // 視 窗 管 理 6
-1 /* 宣 告 函 數 */ private BitmapmIcon; // 圖 案 private floatmposx; // 在 這 設 成 圖 案 座 標 X private floatmposy; // 在 這 設 成 圖 案 座 標 Y private floatmlasttouchx; // 當 觸 碰 螢 幕 時 的 座 標 X private floatmlasttouchy; // 當 觸 碰 螢 幕 時 的 座 標 X private ScaleGestureDetector mscaledetector; // 當 觸 碰 螢 幕 時 回 傳, 回 傳 的 值 放 入 mscaledetector private float mscalefactor = 1.f; // 比 例 係 數 private static final int INVALID_POINTER_ID = -1; private intmactivepointerid = INVALID_POINTER_ID; // 重 新 啟 動 指 標 private int screenwidth, screenheight; // 螢 幕 長 寬 private float mdegrees= 0.f; private Matrix matrix; 7
-2 /* 控 制 桌 面 */ public class ScalePicture extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); /* 變 成 全 螢 幕 */ requestwindowfeature(window.feature_no_title); getwindow().setflags(windowmanager.layoutparams.flag_fullscreen, WindowManager.LayoutParams.FLAG_FULLSCREEN); setcontentview(new ScalePictureView(this, null, 0)); //ScalePictureView 設 定 圖 片 初 始 8
-3 /* 圖 片 像 素, 又 稱 大 小 */ public ScalePictureView(Context context, AttributeSet attrs, int defstyle) { super(context, attrs, defstyle); micon = BitmapFactory.decodeResource(context.getResources(), R.drawable.android); mscaledetector = new ScaleGestureDetector(context, new ScaleListener()); DisplayMetrics dm = new DisplayMetrics(); getwindowmanager().getdefaultdisplay().getmetrics(dm); screenwidth = dm.widthpixels; screenheight = dm.heightpixels; } 9
/* 圖 片 位 置 大 小 縮 放 功 能 */ public ScalePictureView(Context context, AttributeSet attrs, int defstyle) { super(context, attrs, defstyle); // 使 用 監 聽 器 XML 連 結 宣 告 整 數 變 數 defstyle micon = BitmapFactory.decodeResource(context.getResources(), R.drawable.android); // 取 得 放 在 圖 庫 裡 的 圖 案 mscaledetector = new ScaleGestureDetector(context, new ScaleListener()); // 開 始 監 聽 DisplayMetrics dm = new DisplayMetrics(); // 將 畫 面 的 資 訊 放 置 到 dm 裡 getwindowmanager().getdefaultdisplay().getmet rics(dm); screenwidth = dm.widthpixels; // 圖 片 的 寬 度 screenheight = dm.heightpixels; // 圖 片 的 高 度 } 10 執 行 結 果 畫 面 設 定 圖 片 高 寬
-4 @Override public boolean ontouchevent(motionevent ev) { //ontouchevent() 的 動 作 主 要 分 為 :Down, Up, Move.. 等 mscaledetector.ontouchevent(ev); // 另 外 也 可 以 直 接 設 定 某 個 觸 碰 點 的 動 作, 而 ACTION_DOWN 通 常 是 指 第 一 個 觸 碰 點 final int action = ev.getaction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { // 手 指 接 觸 螢 幕 final float x = ev.getx(); // 取 得 座 標 final float y = ev.gety(); mlasttouchx = x; mlasttouchy = y; mactivepointerid = ev.getpointerid(0); break; } 11
/* 變 更 圖 片 位 置 */ case MotionEvent.ACTION_MOVE: { // 手 指 移 動 final int pointerindex = ev.findpointerindex(mactivepointerid); final float x = ev.getx(pointerindex); final float y = ev.gety(pointerindex); // 記 錄 觸 碰 點 移 動 時 的 座 標, 與 先 前 記 錄 的 觸 碰 點 做 比 較, 算 出 移 動 距 離 執 行 結 果 畫 面 移 動 後 更 改 X Y if (!mscaledetector.isinprogress()) { // 因 為 在 做 雙 指 縮 放 動 作 的 時 候 也 會 觸 發 ACTION_MOVE, 所 以 使 用 一 個 if 條 件 與 縮 放 動 作 做 區 隔 final float dx = x - mlasttouchx; final float dy = y - mlasttouchy; mposx += dx; mposy += dy; 12
/* 防 止 移 動 出 界 */ if (mposx < 0 mposx > screenwidth - micon.getwidth() * mscalefactor mposy < 0 mposy > screenheight - micon.getheight() * mscalefactor) { mposx -= dx; mposy -= dy; } invalidate(); // 刷 新 頁 面 } mlasttouchx = x; // 將 碰 觸 的 新 X 值, 放 入 mlasttouchx mlasttouchy = y; // 將 碰 觸 的 新 X 值, 放 入 mlasttouchy break; } 執 行 結 果 畫 面 將 圖 片 牢 牢 地 鎖 在 畫 面 裡! 13
-5 /* 計 算 移 動 向 量 */ case MotionEvent.ACTION_POINTER_UP: { final int pointerindex = (ev.getaction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int pointerid = ev.getpointerid(pointerindex); if (pointerid == mactivepointerid) { final int newpointerindex = pointerindex == 0? 1 : 0; mlasttouchx = ev.getx(newpointerindex); mlasttouchy = ev.gety(newpointerindex); mactivepointerid = ev.getpointerid(newpointerindex); } break; } 14
-6 @Override public void ondraw(canvas canvas) { // 在 畫 面 上 做 動 作 時 super.ondraw(canvas); canvas.save();//scale(): 延 展 canvas canvas.translate(mposx, mposy);//translate(): 移 動 canvas canvas.scale(mscalefactor, mscalefactor); canvas.drawbitmap(micon, 0, 0, null); // 如 果 位 置 與 圖 案 不 同 解 析 度, 此 功 能 自 動 同 步 解 析 度 canvas.restore(); } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { // 用 來 偵 測 雙 指 縮 放 動 作, 限 制 縮 放 大 小 ScaleGestureDetector 15
This image cannot currently be displayed. @Override public boolean onscale(scalegesturedetector detector) { 執 行 結 果 畫 面 限 制 圖 片 縮 放 大 小 mscalefactor *= detector.getscalefactor(); // 將 變 數 mscalefactor 同 時 代 入 canvas.scale(x, y) 的 x 跟 y, 即 可 得 到 長 寬 皆 等 比 例 縮 放 的 效 果 // 防 止 縮 放 過 大 使 圖 片 出 界 if (mposx + micon.getwidth() * mscalefactor > screenwidth mposy + micon.getheight() * mscalefactor > screenheight) { mscalefactor /= detector.getscalefactor(); } mscalefactor = Math.max(0.1f, Math.min(mScaleFactor, 3.0f)); // 限 制 縮 放 大 小 invalidate(); return true; 16
自 動 翻 牌 判 斷 確 認 性 遊 戲 初 始 化 17
- 記 住 翻 開 的 每 張 牌 位 置! 18
-1 import java.util.arraylist; // 陣 列 表 單, 作 為 目 錄 使 用 import java.util.list; // 表 單 import java.util.random; // 隨 機 函 數 import java.util.timer; // 時 間 import java.util.timertask; // 設 定 定 時 器 import android.app.activity; //Eclipse 自 動 import 導 入 的 類 別 import android.app.dialog; // 對 話 框, 用 於 顯 示 文 字, 或 輸 入 import android.content.context; // 使 用 監 聽 器, 監 聽 畫 面 import android.graphics.drawable.drawable; // 用 於 繪 製 圖 形 水 平 翻 轉 import android.os.bundle; //Eclipse 自 動 import 導 入 的 類 別 import android.os.handler; // 用 於 處 理 程 序, 排 隊 import android.os.message; 19
-2 import android.os.systemclock; // 系 統 時 間 import android.view.gravity; // 陀 螺 儀 import android.view.menu; // 清 單 選 單 import android.view.menuitem; import android.view.view; // 用 於 創 建 通 用 佈 局 中 的 組 件 之 間 的 差 距 import android.view.view.onclicklistener; // 監 聽 器 import android.widget.button; // 使 用 按 鈕 函 數 import android.widget.chronometer; // 計 時 器 import android.widget.tablelayout; // 用 於 控 制 佈 局 import android.widget.tablerow; //TableLayout 的 子 類 別, 也 是 用 於 佈 局 import android.widget.toast; 20
-1 /* 宣 告 變 數 */ private Chronometer chronometer; private static int rowcount= 4; // 宣 告 牌 數 private static int columecount= 4; // 宣 告 牌 數 private static int items; // 用 於 紀 錄 可 配 對 數 private Context context; private Drawable backimage; private int cards; // 宣 告 卡 片 陣 列 private List<Drawable> images; private Card firstcard; private Card seconedcard; private ButtonListener buttonlistener; private static Object lock = new Object(); Int paircount; private TableLayout maintable; private UpdateCardsHandler handler; 21
-2 /* 設 定 遊 戲 開 始 畫 面 */ private void initilizegame() { cards = new int[columecount][rowcount];// 使 用 陣 列 將 數 字 卡 片 放 入 items = (rowcount * columecount) / 2; // 記 錄 可 配 對 個 數 maintable.removeallviews(); // 遊 戲 4*4 宮 格 for (int y = 0; y < rowcount; y++) { maintable.addview(createrow(y)); } firstcard = null; loadcards(); // 產 生 卡 片 paircount = 0; chronometer.setbase(systemclock.elapsedrealtime()); chronometer.start(); } 22
/* */ @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); handler = new UpdateCardsHandler(); // 將 更 新 卡 片 後 的 處 理 loadimages(); // 載 入 圖 像 setcontentview(r.layout.main); backimage = getresources().getdrawable(r.drawable.empty); // 起 始 時 讀 取 問 號 的 圖 片 buttonlistener = new ButtonListener(); // 按 鈕 監 聽 maintable = (TableLayout) findviewbyid(r.id.mytablelayout); context = maintable.getcontext(); chronometer = (Chronometer) findviewbyid(r.id.mychronometer); // 使 用 時 間 計 時 chronometer.setformat(" 遊 戲 時 間 : %s"); initilizegame(); // 初 始 化 遊 戲 } 執 行 結 果 畫 面 遊 戲 開 始 畫 面 23
/* 載 入 數 字 畫 面 */ 24 private void loadimages() { images = new ArrayList<Drawable>(); images.add(getresources().getdrawable(r.drawab le.item01)); images.add(getresources().getdrawable(r.drawab le.item02)); images.add(getresources().getdrawable(r.drawab le.item03)); images.add(getresources().getdrawable(r.drawab le.item04)); images.add(getresources().getdrawable(r.drawab le.item05)); images.add(getresources().getdrawable(r.drawab le.item06)); images.add(getresources().getdrawable(r.drawab le.item07)); images.add(getresources().getdrawable(r.drawab le.item08)); } 執 行 結 果 畫 面 產 生 1~8 的 數 字 畫 面
-3 /* 產 生 數 字 並 隨 機 亂 數 */ private void loadcards() { try { int size = rowcount * columecount; ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < size; i++) { list.add(new Integer(i)); // 加 入 所 有 卡 片 編 號 } Random r = new Random(); for (int i = size - 1; i >= 0; i--) { int t = 0; if (i > 0) { t = r.nextint(i); // 隨 機 取 得 編 號 } t = list.remove(t).intvalue(); // 從 list 中 取 出 編 號 cards[i % columecount][i / columecount] = t % (size / 2); // 將 編 號 放 入 指 定 位 置 } 25
-4 /* 再 次 洗 牌 */ for (int i = 0; i < rowcount; i++) for (int j = 0; j < columecount; j++) { int rc = r.nextint(rowcount); int cc = r.nextint(columecount); int temp; temp = cards[i][j]; cards[i][j] = cards[rc][cc]; cards[rc][cc] = temp; } /* 計 時 器 */ Timer t = new Timer(false); // 按 下 按 鈕 後, 延 遲 t.schedule(tt, 500); // 停 頓 0.5 秒 26
-5 27 private TableRow createrow(int y) { TableRow row = new TableRow(context); row.sethorizontalgravity(gravity.center); for (int x = 0; x < columecount; x++) { row.addview(createimagebutton(x, y)); } return row; } private View createimagebutton(int x, int y) { // 按 下 卡 片 按 鈕 動 作 Button button = new Button(context); button.setbackgrounddrawable(backimage); button.setid(100 * x + y); button.setonclicklistener(buttonlistener); return button; }
-6 private void turncard(button button, int x, int y) { // 當 卡 片 配 對 成 功 或 失 敗 時 的 動 作 button.setbackgrounddrawable(images.get( cards[x][y])); if (firstcard == null) { firstcard = new Card(button, x, y); } else { if (firstcard.x == x && firstcard.y == y) { return; // 選 到 相 同 的 卡 片 則 不 動 作 } seconedcard = new Card(button, x, y); TimerTask tt = new TimerTask() { @Override public void run() { try { synchronized (lock) { handler.sendemptymessage(0); 28
/* 按 下 按 鈕 後 做 結 果 判 斷 */ public void checkcards() { if (cards[seconedcard.x][seconedcard.y] == cards[firstcard.x][firstcard.y]) { 執 行 結 果 畫 面 配 對 成 功 畫 面 firstcard.button.setenabled(false); seconedcard.button.setenabled(false); Toast.makeText(getApplicationContext(), " 配 對 成 功!", Toast.LENGTH_SHORT).show(); paircount++; // 配 對 數 再 加 一 if (paircount >= items) { // 如 果 配 對 數 大 於 原 本 未 配 對 數 時 執 行 chronometer.stop(); 配 對 成 功 29
This image cannot currently be displayed. /* 按 下 按 鈕 後 做 結 果 判 斷 */ seconedcard.button.setbackgrounddrawable (backimage); firstcard.button.setbackgrounddrawable(ba ckimage); Toast.makeText(getApplicationContext(), " 配 對 錯 誤...", Toast.LENGTH_SHORT).show(); } firstcard = null; seconedcard = null; // 清 除 空 白 執 行 結 果 畫 面 配 對 錯 誤 畫 面 配 對 錯 誤 30
-7 Button button = new Button(MemoryGame.this); button.settext(" 確 定 "); final Dialog dialog = new Dialog(MemoryGame.this); dialog.settitle(" 恭 喜 你 完 成 所 有 配 對!"); dialog.setcontentview(button); dialog.show(); button.setonclicklistener(new OnClickListener() { public void onclick(view v) { dialog.dismiss(); 31
32
( 取 自 維 基 百 科 ) 33