1
崑山科技大學
電機工程系
實務專題製作報告
手機 APP 開發-2D 繪圖-井字遊戲
指導教授:謝承道
組員:洪健翔 4060J057
蔡易宏 4060J080
林聖淮 4060J083
中華民國 109 年 6 月
3
目錄
1.專題摘要---Page 4 2.核心能力 VS.實務專題工作內容---Page 5 3.Android 的特點---Page 6 4.Android 系統架構---Page 8 5.Android 執行環境---Page 9 6.Java 語言與 XML 文件的基礎---Page 10 6-1.認識 Java 語言---Page 106-2.Android 與 Java 語言---Page 10
6-3.Android 與 XML 文件---Page 11 7.製作方法及進行步驟---Page 12 8.完成結果---Page24 9.計劃管理---Page 25 10.專題海報---Page26 11.完成工作項目及成果---Page27 12.儀器及設備配置---Page28 13.人力配置---Page29 14.參考文獻---Page30
4
一、 專題摘要 :
Android 是一套使用 Linux 作業系統為基礎開發的開放原始碼 (Open Source)作業系統,最初主要是針對手機等行動裝置使用的作 業系統,現在 Android 已經逐漸擴充到帄板電腦和其他領域,例如 : 電子書閱讀器、MP4、播放器、和 Internet 電視等。 Linux 最強大的部份就在於作為伺服器帄台以及作為軟體開發帄台, 這兩項帄台的運作上面,很多時候維護人員或開發人員都是使用遠端 登入 Linux 系統, 然後透過文字界面來操作所需要的指令與任務, 進一步完成自己的工作。所以,文字界面的認識與操作,是相當重要 的。 而我們這次主題是 Android 的 2D 圖形處理函式庫主要是通過graphics 類來顯示 2D 圖形的,其中 graphics 中包括了 Canvas、Paint、 Color、Bitmap 等類。graphics 具有繪製點、線、顏色、2D 幾何圖
5
二、 核心能力 VS.實務專題工作內容 :
核心能力 實務專題工作內容 1、運用數學、科學及電機工程知 識之能力。 利用 Android Studio 的元件配置來設計 版面。 2、設計與執行實驗,以及分析與 解釋數據之能力。 利用 Java 語言建立畫筆、建立畫布以及 遊戲板。 3、執行電機工程實務所需之知 識、技術以及使用軟硬體工具 之能力。使用 Android Studio 以及 Java 語言軟硬 體工具之能力。 4、分析或設計電機工程系統、元 件或製程之能力。 分析事件處理方法,並加以執行。 5、計畫管理、有效溝通與團隊合 作之能力。 利用計畫執行、溝通討論、分工合作, 建立遊戲板。 6、發掘、分析及處理電機實務問 題之能力。 分析方法、類別、事件判斷是否執行當 中。 7、認識時事議題,瞭解電機工程 技術對環境、社會及全球的影 響,並培養持續學習的習慣與 能力。
利用 Android Studio 以及 Java 語言來學 習 2D 繪圖,進而瞭解繪圖對環境、社 會及全球的影響,並且培養持續學習的
習慣與能力。 8、瞭解電機相關產業與技術發展
趨勢之能力。
瞭解 Android Studio 以及 Java 語言對於 2D 繪圖的基礎。
9、理解專業倫理及社會責任。
相信大家對於井字遊戲並不陌生,但我 們這次的主題是利用 Java 語言內的 2D
6
三、 Android 的特點 :
Android 行動作業系統並沒有固定搭配的硬體配備或軟體,可 以讓使用 Android 系統的製造廠商自行客製化行動裝置,依成本、 市場定位和功能來搭配所需軟硬體,其特點入下 : ★ 硬體 : 支援數位相機、GPS、數位羅盤、加速感應器、重力感 測器、趨近感測器、陀螺儀和環境光線感測器等(不是每一種行動 裝置都具備完整的硬體支援,可能只有其中幾項)。 ★ 通訊與網路 : 支援 GSM/EDGE、IDEN、GPRS、CDMA、EV-DO 、UMTS、藍牙、NFC、WiFi、LTE 和 WiMAX 等。 ★ 簡訊 : 支援 SMS 和 MMS 簡訊。 ★ 瀏覽器 : 整合開放原始碼 WebKit 瀏覽器,支援 Chrome 的 JavaScript 引擎。 ★ 多媒體 : 支援常用音效、視訊和圖形格式,包含 MPEG4、 H.264、AMR、AAC、MP3、MIDI、Ogg Vorbis、WAV、JPEG、 PNG、GIF 和 BMP 等。 ★ 資料儲存 : 支援 SQLite 資料庫,一種輕量化的關聯式資料 庫。 ★ 繪圖 : 支援 2D 函數庫的最佳化繪圖,和 3D 繪圖 OpenGL ES7
規格。
★ 其他 : 支援多點觸控、Flash、多工和可攜式無線基地台等。
Android 的應用程式(APP) 都是利用 Android 軟體開發工具包(SDK) 編寫的,通常是 JAVA 語言,Java 可以與 C 語言或 C++結合使用,並 且可以選擇非默認的執行時函式庫共享,以允許獲得更好的 C++支 援。
SDK 包含一套全面的開發工具,包括除錯器、函式庫、基於虛擬機 器鏡像的仿真器、文件,範例代碼和教程。簡單的說 SDK 提供相關 工具和 APIs(Application Programming Interfaces),可以讓我們使用 Java 語言開發在 Android 作業系統上執行的 Android 應用程式。
Android 擁有越來越多第三方應用程式的選擇,使用者可以透過下載 和安裝應用程式的 APK(Android 應用程式包),或利用應用程式商 店來下載,允許使用者在那裡進行安裝、更新和移除。
8
四、 Android 系統架構
上述堆疊的最上層是應用程式(Applicaytion,簡稱 Apps),在
中間層的中介軟體包含應用程式框架(Application
Framework)、函數庫(Libraries)和 Android 執行環境(Android
Runtime),最底層 Linux 核心(Linux Kernel) 。
使用者 應用程式(applications) 瀏覽器 連絡人 日曆 其它 應用程式框架(applications framework) 活動管理 資源管理 內容提供者 其它 函數庫(libraries) WebKit OpenGel SQLite 其它 Android 執行環境 Dalvik VK/ART 虛擬機器 核心 Java 函數庫
Linux 核心(Linux Kernel)
顯示驅動 相機驅動 Wifi 驅動 其它
9
五、 Android 執行環境
Android 執行環境是由虛擬機器和核心 Java 函數庫組成。
★ 虛擬機器 : Android 虛擬機器是 Google 針對行動裝置實作的 Java 執行環境,因為 Android 應用程式是使用 Java 撰寫和編譯,並 且在虛擬機器上執行,4.4 之前版本是使用 Dalvil VM 虛擬機,在 4.4 版新增更有效率的 ART(Android Runtime),需要自行切換使用,5.x 之後版本預設 ART。所以,Java 程式碼在編譯成 Java 類別檔後, 還需轉換成 Android 虛擬機器的格式,才能在 Dalvik VM 或 ART 虛 擬機執行。
★ 核心 Java 函數庫 : 核心 Java 函數庫,Android 支援的 Java API 是 Java SE API 的子集,刪除一些不需要的套件,例如 : 列印、視窗 Swing 或 AWT 等。
★ Linux 核心 : Android 作業系統是架構在 Linux 作業系統之上, Linux 核心在 Android 系統架構中扮演硬體與其他軟體堆疊之間的 抽象層(Abstraction Layer),負責提供系統的核心服務,包含 : 執行 序、低階的記憶體管理、網路、行程管理、電源管理(Power management) 和硬體的驅動程式。
10
六、 Java 語言與 XML 文件的基礎
Android 原生開發語言是 Java,支援 Java SE 語法和部分 Java
API 函數庫,Android 開發者必須對 Java 語言有一定的認
識,才能著手進行 Android 應用程式開發。
XML 是定義 Android 應用程式的資源和使用介面,可以讓
我們使用宣告方式,不用撰寫一行 Java 程式碼,就可以建
立使用介面、語系、佈景和版面配置。
6-1
、
認識 Java 語言
「Java」(爪哇)是一個結合編譯和直譯優點的程式語言,一種
在軟體帄台上執行的語言,Java 帄台與硬體無關且跨作業系
統,它是由 JAM 和 Java API 元件組成。
「帄台」(Platform)是一種結合硬體和軟體的程式執行環境。
6-2、 Android 與 Java 語言
Android 應用程式是使用 Java 語言建立的程式,我們是使
用物件導向的觀念和語法,繼承和擴充 Android 框架的 Java
現成類別(Android 和 Java 程式的執行方式是完全的不同!)。
11
6-3、 Android 與 XML 文件
Android 是一套支援多國語系和不同螢幕尺寸行動裝置的作
業系統,為了簡化和方便管理使用在不同語系和尺寸的資源,
Android 切割使用介面和程式邏輯控制,採用 XML 文件來
管理程式介面和相關的眾多資源,例如 : 圖示和背景圖形。
XML 是一種類似 HTML(Web 網頁的原始碼)的標記語言,
可以直接使用文字內容的標籤來定義 Android 使用介面的
位置、尺寸、和外觀,就像佈置房間時,描述桌子放在哪裡、
衣櫃在哪裡和床面在哪個方向等。
Android Studio 在編譯時會將定義使用介面的 XML 文件編
譯轉換成 Java 程式碼,開發者使用 Android Studio 的 Design
設計編輯器拖拉建介面元件,並不用自行撰寫 Java 程式碼。
商業邏輯的 JAVA 類別 檔
使用介面的 JAVA 類別 檔
完整 Android App 的 Java 程式
XML 文件定義的使用 介面元件
12
七、 製作方法及進行步驟 :
1.
認識類別
Paint 類 : 是 Android 圖形函式庫中最重要的類別,裡面包含用來 繪圖所需的相關資訊,包括繪出文字、圖形等等。
Color 類 : Android 中顏色被四個數值所代表:ARGB (Alpha、 Red、 Green、Blue),Android 的程式碼使用一個整數來代表顏色, 而不是產生一個 Color 類別的實體. RGB 三個數值不需說明即可 瞭解,,但 Alpha 這數值是代表透明度,最低值為 0,代表顏色完 全透明, 不管 RGB 的值為何,假如 A 是 0 就是整個看不見,最 高值為 255,也就是不透明,中間值用來代表透亮、半透明、有 顏色,可以稍微看到所繪物件底下有什麼東西。 Canvas 類 : Canvas 即是畫布,代表可讓你“繪圖”的表面,一開 始裡面是空無內容,Canvas 類別中的方法可以讓你在表面上畫出 線、方形、圓圈、與任意圖形,而在 Android 中,一般來說 Canvas 會在每一個 View 的 onDraw 方法中看到每個 View 在顯示之前都 會透過 View.onDraw 來繪製畫面。
Bitmap 類 :是點陣圖檔案,是由畫素組成的,點陣圖也稱 為點陣圖影象、點陣影象、資料影象、數碼影象。一個畫
13 素點可以由 1、4、16、24、32bit 來表示,畫素點的色彩越 豐富,自然影象的效果就越好了。
2.
開啟和建立一個 Android Studio 專案。
啟動 Android Studio 開啟專案3.
建立 Activity 活動執行井字遊戲 MainActivity 活動
類別是在覆寫 onCreate()方法顯示 MainBoard 物件
的井字形遊戲板,
即 setContentView()方法,如下所示:
public class MainActivity extends AppCompatActivity { @Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MainBoard(this)); } }
4.
建立井字形遊戲板 MainBoard 類別
MainBoard 類別是在 View 物件上繪出井字形的遊
戲板,由上而下;由左至右繪出 4 條線來建立井字
形,我們將這 4 條線繪在 Bitmap 物件。 MainBoard
14
類別繼承 View 類別,在類別宣告開頭是成員
Bitmap 、 Canvas 、 Paint 、 Ponit 和 CellBoard 物
件變數,如下所示:
class MainBoard extends View { private int h, w;
private Bitmap bitmap; private Canvas buffer; private Paint paint;
private boolean isDrawX;
private Point[] hLine01, hLine02, vLine01, vLine02; private CellBoard cellBoard;
private Context test;
在建構子首先呼叫父類別的建構子,參數是 Context 物件,
然後建立 Paint 物件的畫筆,色彩為黑色,樣式為
STROKE,旗標變數 isDrawX 是用來輪流繪出 O 和 X
圖形,如下所示:
public MainBoard(Context context) { super(context);
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE); isDrawX = true;
test=context; }
15
在覆寫 onDraw()方法使用 Canvas 物件的 drawBitmap()
方法繪出 Bitmap 物件,我們是在此物件上繪出 4 條直線,
如下所示:
@Override
protected void onDraw(Canvas canvas) { canvas.drawBitmap(bitmap, 0, 0, paint); }
在覆寫 onMeasure()方法取得螢幕的可用空間,即
方法傳入的 2 個參數,我們需要使用 View,MeasureSpec
類別的 getSize()方法來取得尺寸,如下所示:
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { h = View.MeasureSpec.getSize(heightMeasureSpec); w = View.MeasureSpec.getSize(widthMeasureSpec); setMeasuredDimension(w, h);
上述程式碼呼叫 setMeasuredDimension()方法儲存
View 物件的寬和高,然後建立此尺寸的 Bitmap 物件,
建構子參數依序是寬、高和類別常數指定 1 個點使用 4
個位元組來儲存,如下所示:
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); buffer = new Canvas(bitmap);calculateLinePlacements(); drawBoard();
16
上述程式碼 Canvas 物件 buffer,其建構子參數
就是 Bitmap 物件,最後呼叫 calculateLinePlacements()
方法計算繪出井字形
4 條線的座標,然後呼叫 drawBoard()方法繪出井字形。
在自訂 calculateLinePlacements()方法計算 4 條線上、下
和左、右端點的座標,首先將寬和高除以 3 來計算儲存
格尺寸,然後計算出座標,它是使用 4 個 Point 物件陣
列儲存座標,hLine01[]和 hLine02[]是水帄的 2 條線;
vLine01[]和 vLine02[]是垂直的 2 條線,每一個 Point 陣
列有 2 個元素,陣列索引 0 是起點;1 是終點,如下
所示:
private void calculateLinePlacements() { int cellH = h / 3;
int cellW = w / 3;
hLine01 = new Point[2];
Point p1 = new Point(0, cellH); Point p2 = new Point(w, cellH); hLine01[0] = p1;
hLine01[1] = p2;
hLine02 = new Point[2]; p1 = new Point(0, 2 * cellH);
p2 = new Point(w, 2 * cellH); hLine02[0] = p1;
hLine02[1] = p2;
vLine01 = new Point[2]; p1 = new Point(cellW, 0); p2 = new Point(cellW, h);
17
vLine01[0] = p1; vLine01[1] = p2;
vLine02 = new Point[2]; p1 = new Point(2 * cellW, 0); p2 = new Point(2 * cellW, h); vLine02[0] = p1;
vLine02[1] = p2;
cellBoard = new CellBoard(cellW, cellH);
上述方法最後使用 1/3 寬和高來建立 CellBoard 物件。
在覆寫 onTouchEvent()事件處理方法處理使用者觸摸螢
幕操作,可以在儲存格繪出 X 或 O 圖形, if 條件判
斷是否 ACTION_
DOWN 操作,AlertDialog.Builder 則是產生對話方塊,以
此來判斷玩家是否勝利,如下所示:
@Overridepublic boolean onTouchEvent(MotionEvent event) {
AlertDialog.Builder builder = new AlertDialog.Builder(test); if (event.getAction() == MotionEvent.ACTION_DOWN) {
RectF position = cellBoard.getCellToFill(event.getX(), event.getY(),isDrawX);
上述程式碼呼叫 CellBoard 物件的 getCellToFill()方法
取的繪圖長方形的 RectF 物件,參數是螢幕上觸摸位置
的座標,然後使用 if 條件判斷 isDrawX 變數來決定繪
18
出 X 或 O 圖形,如下所示:
if (position != null) { if (isDrawX) {buffer.drawLine(position.left, position.top, position.right, position.bottom, paint); buffer.drawLine(position.right, position.top, position.left, position.bottom, paint); } else { buffer.drawOval(position, paint); } isDrawX = !isDrawX; invalidate(); } } if (cellBoard.isWin()==1) { builder.setTitle("遊戲結束"); builder.setMessage("玩家 X 獲勝"); builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) { } }); builder.show(); } else if (cellBoard.isWin()==2) { builder.setTitle("遊戲結束"); builder.setMessage("玩家 O 獲勝"); builder.setPositiveButton("確定", new
19
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog Interface, int i) { } }); builder.show(); } return true; }
在自訂 drawBoard ()方法使用 calculateLinePlacements()方法
計算出的座標來繪出遊戲的井字形,我們是呼叫 drawLine()
方法繪出 4 條線,如下所示:
private void drawBoard() {
buffer.drawLine(hLine01[0].x, hLine01[0].y, hLine01[1].x, hLine01[1].y, paint); buffer.drawLine(hLine02[0].x, hLine02[0].y, hLine02[1].x, hLine02[1].y, paint); buffer.drawLine(vLine01[0].x, vLine01[0].y, vLine01[1].x, vLine01[1].y, paint); buffer.drawLine(vLine02[0].x, vLine02[0].y, vLine02[1].x, vLine02[1].y, paint); invalidate(); }
20
5.
建立邏輯儲存格的 Cell 類別
class CellBoard { private int w; private int h;
protected Cell[] position; private int[] draw;
在建構子取得井字形儲存格的尺寸 w 和 h 後,呼叫
initialBoardCells()建立 9 個元素的 Cell 物件陣列
position[],如下所示:
public CellBoard(int cellWidth, int cellHeight) { w = cellWidth; h = cellHeight; initialBoardCells(); }
Cell 內層類別建立的物件是繪出 X 或 O 圖形的長方
形,圖形是在此長方形的範圍內繪出,類別繼承 RectF 類
別,RectF 類別可以儲存長方形的 4 個浮點數座標,如
下所示:
private class Cell extends RectF { private boolean filled;
public Cell(float left, float top, float right, float bottom) {
super(left, top, right, bottom); filled = false;
21
上述建構子參數依序是長方形左上角(x , y)座標,和右下
角(x , y)座標,指定成員變數 filled 值為 false,表示沒有
在其中繪出 X 或 O 圖形,如果有繪出,可以呼叫
setFilled()方法來指定已填入,如下所示:
public void setFilled(boolean filled) { this.filled = filled;}
public boolean isFilled() { return filled; } }
上述 isFilled()方法判斷是否有填入 X 或 O 圖形。自訂
initialBoardCells()方卡可以計算 Cell 物件陣列各儲存格
的座標,首先指定位移量 offset ,因為 Cell 物件的長方
形比井字形的儲存格小 offset 尺寸,如下所示:
private void initialBoardCells() { int offset = 15;
position = new Cell[9];
position[0] = new Cell(0 + offset, 0 + offset, w - offset, h - offset); position[1] = new Cell(w + offset, 0 + offset, 2 * w - offset, h - offset);
position[2] = new Cell(2 * w + offset, 0 + offset, 3 * w - offset, h – offset); position[3] = new Cell(0 + offset, h + offset, w - offset, 2 * h - offset); position[4] = new Cell(w + offset, h + offset, 2 * w - offset, 2 * h – offset); position[5] = new Cell(2 * w + offset, h + offset, 3 * w - offset, 2 * h –
22
position[6] = new Cell(0 + offset, 2 * h + offset, w - offset, 3 * h – offset); position[7] = new Cell(w + offset, 2 * h + offset, 2 * w - offset, 3 * h –
offset); position[8] = new Cell(2 * w + offset, 2 * h + offset, 3 * w - offset, 3 *
h - offset); draw = new int[9];
for (int i = 0; i < 9; ++i) draw[i] = 0;
}
自訂 getCellToFill()方法可以依據參數的座標,傳回填入
X 和 O 圖形的 RectF 物件,方法是使用 foreach 迴圈
走訪每一個 postion[]陣列元素的 Cell 物件,如下所示:
public RectF getCellToFill(float x, float y, booleanisDrawX) {
for (int i = 0; i < 9; ++i) { if (position[i].contains(x, y) && !position[i].isFilled()) {
RectF retCell = new RectF(position[i]); position[i].setFilled(true); if (isDrawX) draw[i] = 1; else draw[i] = 2; return retCell; } } return null; }
public int isWin() {
if ( draw[0] == 1 && draw[1] == 1 && draw[2] == 1 || draw[3] == 1 && draw[4] == 1 && draw[5] == 1 || draw[6] == 1 && draw[7] == 1 && draw[8] == 1 ||
23
draw[0] == 1 && draw[3] == 1 && draw[6] == 1 || draw[1] == 1 && draw[4] == 1 && draw[7] == 1 || draw[2] == 1 && draw[5] == 1 && draw[8] == 1 || draw[0] == 1 && draw[4] == 1 && draw[8] == 1 || draw[2] == 1 && draw[4] == 1 && draw[6] == 1) return 1;
else if (draw[0] == 2 && draw[1] == 2 && draw[2] == 2 || draw[3] == 2 && draw[4] == 2 && draw[5] == 2 || draw[6] == 2 && draw[7] == 2 && draw[8] == 2 || draw[0] == 2 && draw[3] == 2 && draw[6] == 2 || draw[1] == 2 && draw[4] == 2 && draw[7] == 2 || draw[2] == 2 && draw[5] == 2 && draw[8] == 2 || draw[0] == 2 && draw[4] == 2 && draw[8] == 2 || draw[2] == 2 && draw[4] == 2 && draw[6] == 2) return 2; else return 0; } }
上述自訂 isWin()方法建立獲勝方法,得以判斷玩家是否
獲勝
24
八、 完成結果
25
九、 計劃管理
甘特圖
月份 9 10 11 12 3 4 5 6 起初發想 概念討論 資料蒐集 研究設計 報告呈現26
十、 專題海報
27
十一、 完成工作項目及成果 :
第一階段
熟悉 Android Studio 及 Java 語言
第二階段
利用 2D 繪圖建立井字形遊戲版面
第三階段
利用 2D 繪圖建立井字形遊戲版面
28
十二、 儀器及設備配置 :
儀器/程式名稱
用途及說明
29
十三、 人力配置 :
姓名 學號 工作項目 蔡易宏 4060J080版面配置、資料蒐集、程式開發
林聖淮 4060J083版面配置、資料蒐集、程式開發
洪健翔 4060J057版面配置、資料蒐集、程式開發
30