編輯:關於Android編程
在學完了Android的基礎之後,我開始嘗試著寫一些小項目練練手,同時進一步鞏固自己的基礎知識,而我選的的第一個項目就是做一個簡單的人人對戰的五子棋小游戲。
首先,我們要新建一個自定義控件類Panel,這基本上涵蓋著整個項目的大部分操作,比如棋盤的設計等等,下面開始Panel的編寫,代碼如下:
1 public class Chess_Panel extends View{
2 private int myPanelWidth ; //棋盤寬度
3 private float myLineHeight; //行寬
4 private int maxLine = 10; //行數
5
6 private Paint myPaint; //畫筆
7 private Bitmap myWhitePice; //白棋子
8 private Bitmap myBlackPice; //黑棋子
9 private float ratioPieceOfLineHight = 3 * 1.0f / 4; //棋子為行寬的3/4;
10
11 private boolean isGemOver; //游戲結束
12 public static int WHITE_WIN = 0; //勝利為白方標志
13 public static int BLACK_WIN = 1; //勝利為黑方標志
14 private boolean isWhite = true; //判斷是否是白棋先手,或當前為白棋下子
15
16 private List myWhiteArray = new ArrayList(); //白棋子位置信息
17 private List myBlackArray = new ArrayList(); //黑棋子位置信息
18
19 private onGameListener onGameListener; //回調接口
20 private int mUnder; //dialog的Y坐標
21
22 public Chess_Panel(Context context) {
23 this(context, null);
24 }
25
26 public Chess_Panel(Context context ,AttributeSet attributeSet){ //構造函數
27 super(context , attributeSet);
28
29 init();
30 }
31
32 //初始化函數
33 private void init() {
34 myPaint = new Paint();
35 myPaint.setColor(0X44ff0000); //給畫筆設置顏色
36 myPaint.setAntiAlias(true); //設置畫筆是否使用抗鋸齒
37 myPaint.setDither(true); //設置畫筆是否防抖動
38 myPaint.setStyle(Paint.Style.STROKE); //設置畫筆樣式,這裡使用描邊
39
40 myWhitePice = BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2); //設置棋子圖片
41 myBlackPice = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1);
42
43 }
44
所謂自定義控件(或稱組件)也就是編寫自己的控件類型,而非Android中提供的標准的控件。構造函數中,使用AttributeSet來完成控件類的構造函數。
Paint類:Android中的畫筆類,用於繪制圖形,它包含了很多方法對其屬性進行設置,如下:
setAntiAlias: 設置畫筆的鋸齒效果。
setColor: 設置畫筆顏色
setARGB: 設置畫筆的a,r,p,g值。
setAlpha: 設置Alpha值
setTextSize: 設置字體尺寸。
setStyle: 設置畫筆風格,空心或者實心。
setStrokeWidth: 設置空心的邊框寬度。
getColor: 得到畫筆的顏色
getAlpha: 得到畫筆的透明度。
Bitmap指的是一張位圖,而BitmapFactory是從文件,數據流,數組等的資源中生成一個Bitmap對象。 BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1)正是從資源中獲取一張圖片生成一個Bitmap對象的方法。當然,還有其他的方法可以用來生成Bitmap對象,這裡就不一一列舉了。
設置好畫筆屬性之後,我們就開始來設計我們的棋盤布局,以及棋盤的觸摸動作等,代碼如下:
1 //觸發動作
2 public boolean onTouchEvent(MotionEvent event){
3 if (isGemOver) {
4 return false;
5 }
6
7 int action = event.getAction();
8 if (action == MotionEvent.ACTION_UP) { //判斷觸摸動作,ACTION_UP為單點觸摸離開
9 int x = (int) event.getX();
10 int y = (int) event.getY();
11 Point p = getVaLidPiont(x,y); //獲取當前的坐標
12
13 if (myWhiteArray.contains(p)|| myBlackArray.contains(p)) {
14 return false;
15 }
16
17 if (isWhite) {
18 myWhiteArray.add(p);
19 }else {
20 myBlackArray.add(p);
21 }
22 invalidate(); //invalidate()是用來刷新View的,必須在UI線程中使用
23 isWhite = !isWhite;
24 }
25 return true;
26 }
27
28
29 private Point getVaLidPiont(int x , int y){
30 return new Point((int)(x/myLineHeight),(int)(y/myLineHeight));
31 }
32
33 //計算布局大小
34 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
35 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
36 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
37
38 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
39 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
40
41 int width = Math.min(widthSize, heightSize);
42
43 if (widthMode == MeasureSpec.UNSPECIFIED) { //MeasureSpec.UNSPECIFIED表示未知大小
44 width = heightSize;
45 }else if (heightMode == MeasureSpec.UNSPECIFIED) {
46 width = widthSize;
47 }
48
49 setMeasuredDimension(width, width);
50
51 }
52
53 protected void onSizeChanged(int w, int h ,int oldw , int oldh) { //當View大小發生改變的時候會被系統自動回調
54 super.onSizeChanged(w, h, oldw, oldh);
55 myPanelWidth = w;
56 myLineHeight = myPanelWidth*1.0f/maxLine;
57 mUnder = h - (h - myPanelWidth) / 2;
58
59 int pieceWidth = (int) (myLineHeight*ratioPieceOfLineHight); //棋子大小占行寬的3/4
60 myWhitePice = Bitmap.createScaledBitmap(myWhitePice, pieceWidth, pieceWidth, false); //以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。
61 myBlackPice = Bitmap.createScaledBitmap(myBlackPice, pieceWidth, pieceWidth, false);
62 }
要學好android觸控,就要先了解MotionEvent,同時要對所用的MotionEvent常用的API要比較深入的了解。掌握MotionEvent事件是自定義控件中一個十分重要的部分。
事件的主要動作類型有如下幾種:
public static final int ACTION_DOWN = 0;單點觸摸動作
public static final int ACTION_UP = 1;單點觸摸離開動作
public static final int ACTION_MOVE = 2;觸摸點移動動作
public static final int ACTION_CANCEL = 3;觸摸動作取消
public static final int ACTION_OUTSIDE = 4;觸摸動作超出邊界
public static final int ACTION_POINTER_DOWN = 5;多點觸摸動作
public static final int ACTION_POINTER_UP = 6;多點離開動作
以下是一些非touch事件
public static final int ACTION_HOVER_MOVE = 7;
public static final int ACTION_SCROLL = 8;
public static final int ACTION_HOVER_ENTER = 9;
public static final int ACTION_HOVER_EXIT = 10;
onMeasure()函數由包含這個View的具體的ViewGroup調用, onMeasure()當控件的父元素正要放置該控件時調用.onMesure向父元素中傳入兩個參數——widthMeasureSpec和heightMeasureSpec,這兩個參數是由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同決定,其中包含了Size和Mode信息。
widthMeasureSpec和heightMeasureSpec的讀取如下:
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
pecMode一共有三種可能:
MeasureSpec.EXACTLY:父視圖希望子視圖的大小應該是specSize中指定的。
MeasureSpec.AT_MOST:子視圖的大小最多是specSize中指定的值,也就是說不建議子視圖的大小超過specSize中給定的值。
MeasureSpec.UNSPECIFIED:我們可以隨意指定視圖的大小。
onSizeChanged(int w, int h ,int oldw , int oldh):當View大小發生改變(比如分辨率變化)的時候會被系統自動回調。
Bitmap.createScaledBitmap(src,float, float, false) :以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。 接下來就開始設計棋盤線,代碼如下:
1 protected void onDraw(Canvas canvas) { //Canvas類相當於一塊畫布
2 super.onDraw(canvas);
3 drawBroad(canvas);
4 drawPiece(canvas);
5 checkGameOver();
6 }
7
8 private void drawBroad(Canvas canvas){ //畫出棋盤線
9 int w = myPanelWidth;
10 float lineHeight = myLineHeight;
11 int startX = (int) (lineHeight/2); //棋盤線起始X坐標
12 int endX = (int)(w-lineHeight/2); //棋盤終止X坐標
13 for(int i = 0; i< maxLine; i++){
14 int y = (int)((i+1.5)*lineHeight); //y坐標
15
16 canvas.drawLine(startX, y, endX, y, myPaint); //畫棋盤橫向線
17 canvas.drawLine(y, startX, y, endX, myPaint); //畫棋盤縱向線
18 }
19 }
20
21 //畫棋子
22 private void drawPiece(Canvas canvas) {
23 int n1 = myWhiteArray.size();
24 int n2 = myBlackArray.size();
25 for(int i =0; i< n1 ;i++){
26 Point whitePoint = myWhiteArray.get(i);
27 canvas.drawBitmap(myWhitePice, (whitePoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight,
28 (whitePoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null);
29 //drawBitmap(Bitmap bitmap, float left, float top, Paint paint);Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置
30 }
31
32 for(int i =0; i< n2 ;i++){
33 Point blackPoint = myBlackArray.get(i);
34 canvas.drawBitmap(myBlackPice, (blackPoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight,
35 (blackPoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null);
36 }
37 }
在Android中,Canvas類相當於畫布,另外它也是顯示位圖(Bitmap類)的核心類,它的屬性方法如下:
Canvas(): 創建一個空的畫布,可以使用setBitmap()方法來設置繪制具體的畫布。
Canvas(Bitmap bitmap): 以bitmap對象創建一個畫布,則將內容都繪制在bitmap上,因此bitmap不得為null。
Canvas(GL gl): 在繪制3D效果時使用,與OpenGL相關。
drawColor: 設置Canvas的背景顏色。
setBitmap: 設置具體畫布。
clipRect: 設置顯示區域,即設置裁剪區。 isOpaque:檢測是否支持透明。 rotate: 旋轉畫布 translate:移動畫布 scale:縮放畫布
setViewport: 設置畫布中顯示窗口。
skew: 設置偏移量。 restore: 用來恢復上一次save之前的狀態 save:用來保存Canvas的當前狀態
注意: save方法、restore方法一般是成對出現的,save方法可多於restore方法,但restore方法不能多於save方法
drawBitmap(Bitmap bitmap, float left, float top, Paint paint) Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置,panit為我們設計的畫筆
接下來的就是游戲中的一些判斷動作了:
1 //檢測游戲是否結束
2 private void checkGameOver(){
3 boolean whiteWin = checkFiveInLine(myWhiteArray);
4 boolean blackWin = checkFiveInLine(myBlackArray);
5
6 if (whiteWin || blackWin) {
7 isGemOver = true;
8 if (onGameListener != null) {
9 onGameListener.onGameOver(whiteWin ? WHITE_WIN : BLACK_WIN);
10 }
11 }
12 }
13 //回調一個int數據用於設置Dialog的位置
14 public int getUnder() {
15
16 return mUnder;
17 }
18
19 //檢測是否存在五棋子相連的情況
20 private boolean checkFiveInLine(List myArray){
21 for(Point p : myArray){
22 int x = p.x;
23 int y = p.y;
24
25 boolean win_flag = //判斷是否存在五子相連情況
26 checkHorizontal(x , y ,myArray)||checkVertical(x,y,myArray)
27 ||checkLeftDiagonal(x,y,myArray)||checkRightDiagonal(x,y,myArray);
28 if (win_flag) {
29 return true;
30 }
31 }
32 return false;
33 }
34
35 //橫向檢查是否滿足五子相連
36 private boolean checkHorizontal(int x ,int y ,List myArray){
37 int count = 1;
38 for(int i = 1;i < 5; i++){
39 if (myArray.contains(new Point(x+i,y))) {
40 count++;
41 }else {
42 break;
43 }
44 }
45 if (count == 5) {
46 return true;
47 }
48 for(int i = 1;i < 5; i++){
49 if (myArray.contains(new Point(x-i,y))) {
50 count++;
51 }else {
52 break;
53 }
54
55
56 if (count == 5) {
57 return true;
58 }
59 }
60 return false;
61 }
62
63 //縱向檢查是否滿足五子相連
64 private boolean checkVertical(int x ,int y ,List myArray){
65 int count = 1;
66 for(int i = 1;i < 5; i++){
67 if (myArray.contains(new Point(x,y+i))) {
68 count++;
69 }else {
70 break;
71 }
72
73 }
74 if (count == 5) {
75 return true;
76 }
77 for(int i = 1;i < 5; i++){
78 if (myArray.contains(new Point(x,y-i))) {
79 count++;
80 }else {
81 break;
82 }
83 if (count == 5) {
84 return true;
85 }
86 }
87 return false;
88 }
89
90 //左斜向檢查是否滿足五子相連
91 private boolean checkLeftDiagonal(int x ,int y ,List myArray){
92 int count = 1;
93 for(int i = 1;i < 5; i++){
94 if (myArray.contains(new Point(x-i,y+i))) {
95 count++;
96 }else {
97 break;
98 }
99
100 }
101 if (count == 5) {
102 return true;
103 }
104 for(int i = 1;i < 5; i++){
105 if (myArray.contains(new Point(x+i,y-i))) {
106 count++;
107 }else {
108 break;
109 }
110 if (count == 5) {
111 return true;
112 }
113 }
114 return false;
115 }
116
117 //右斜向檢查是否滿足五子相連
118 private boolean checkRightDiagonal(int x ,int y ,List myArray){
119 int count = 1;
120 for(int i = 1;i < 5; i++){ //切記,i = 1 開始,否則就會只檢測到三個子相連就結束了
121 if (myArray.contains(new Point(x-i,y-i))) {
122 count++;
123 }else {
124 break;
125 }
126 }
127 if (count == 5) {
128 return true;
129 }
130 for(int i = 1;i < 5; i++){
131 if (myArray.contains(new Point(x+i,y+i))) {
132 count++;
133 }else {
134 break;
135 }
136 if (count == 5) {
137 return true;
138 }
139 }
140 return false;
141 }
142
143 //重新開始游戲
144 protected void restartGame(){
145 myWhiteArray.clear();
146 myBlackArray.clear();
147 isGemOver = false;
148 isWhite = false;
149 invalidate(); //刷新
150 }
invalidate()是android中用於刷新View顯示的一個方法。
可以說重載onMeasure(),onLayout(),onDraw()三個函數構建了自定義View的外觀形象。再加上onTouchEvent()等重載視圖的行為,可以構建任何我們需要的可感知到的自定義View。
另外,我們還應該暴露我們自定義的控件的接口,以方便調用:
1 // 用於回調的接口
2 public interface onGameListener {
3 void onGameOver(int i);
4 }
5
6 //自定義接口,用於顯示dialog
7 public void setOnGameListener(Chess_Panel.onGameListener onGameListener) {
8 this.onGameListener = onGameListener;
9 }
那麼,完整的Chess_Panel代碼如下所示:
1 package com.example.fivechess;
2
3
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import android.content.Context;
8 import android.graphics.Bitmap;
9 import android.graphics.BitmapFactory;
10 import android.graphics.Canvas;
11 import android.graphics.Paint;
12 import android.graphics.Point;
13 import android.util.AttributeSet;
14 import android.view.MotionEvent;
15 import android.view.View;
16
17 public class Chess_Panel extends View{
18 private int myPanelWidth ; //棋盤寬度
19 private float myLineHeight; //行寬
20 private int maxLine = 10; //行數
21
22 private Paint myPaint; //畫筆
23 private Bitmap myWhitePice; //白棋子
24 private Bitmap myBlackPice; //黑棋子
25 private float ratioPieceOfLineHight = 3 * 1.0f / 4; //棋子為行寬的3/4;
26
27 private boolean isGemOver; //游戲結束
28 public static int WHITE_WIN = 0; //勝利為白方標志
29 public static int BLACK_WIN = 1; //勝利為黑方標志
30 private boolean isWhite = true; //判斷是否是白棋先手,或當前為白棋下子
31
32 private List myWhiteArray = new ArrayList(); //白棋子位置信息
33 private List myBlackArray = new ArrayList(); //黑棋子位置信息
34
35 private onGameListener onGameListener; //回調接口
36 private int mUnder; //dialog的Y坐標
37
38 public Chess_Panel(Context context) {
39 this(context, null);
40 }
41
42 public Chess_Panel(Context context ,AttributeSet attributeSet){ //構造函數
43 super(context , attributeSet);
44
45 init();
46 }
47
48 // 用於回調的接口
49 public interface onGameListener {
50 void onGameOver(int i);
51 }
52
53 //自定義接口,用於顯示dialog
54 public void setOnGameListener(Chess_Panel.onGameListener onGameListener) {
55 this.onGameListener = onGameListener;
56 }
57
58 //初始化函數
59 private void init() {
60 myPaint = new Paint();
61 myPaint.setColor(0X44ff0000); //給畫筆設置顏色
62 myPaint.setAntiAlias(true); //設置畫筆是否使用抗鋸齒
63 myPaint.setDither(true); //設置畫筆是否防抖動
64 myPaint.setStyle(Paint.Style.STROKE); //設置畫筆樣式,這裡使用描邊
65
66 myWhitePice = BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2); //設置棋子圖片
67 myBlackPice = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1);
68
69 }
70
71 //觸發事件
72 public boolean onTouchEvent(MotionEvent event){
73 if (isGemOver) {
74 return false;
75 }
76
77 int action = event.getAction();
78 if (action == MotionEvent.ACTION_UP) { //判斷觸摸動作,ACTION_UP為單點觸摸離開
79 int x = (int) event.getX();
80 int y = (int) event.getY();
81 Point p = getVaLidPiont(x,y);
82
83 if (myWhiteArray.contains(p)|| myBlackArray.contains(p)) {
84 return false;
85 }
86
87 if (isWhite) {
88 myWhiteArray.add(p);
89 }else {
90 myBlackArray.add(p);
91 }
92 invalidate(); //invalidate()是用來刷新View的,必須在UI線程中使用
93 isWhite = !isWhite;
94 }
95 return true;
96 }
97
98
99 private Point getVaLidPiont(int x , int y){
100 return new Point((int)(x/myLineHeight),(int)(y/myLineHeight));
101 }
102
103 //計算布局大小
104 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
105 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
106 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
107
108 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
109 int heightSize = MeasureSpec.getSize(heightMeasureSpec);
110
111 int width = Math.min(widthSize, heightSize);
112
113 if (widthMode == MeasureSpec.UNSPECIFIED) { //MeasureSpec.UNSPECIFIED表示未知大小
114 width = heightSize;
115 }else if (heightMode == MeasureSpec.UNSPECIFIED) {
116 width = widthSize;
117 }
118
119 setMeasuredDimension(width, width);
120
121 }
122
123 protected void onSizeChanged(int w, int h ,int oldw , int oldh) { //當View大小發生改變的時候會被系統自動回調
124 super.onSizeChanged(w, h, oldw, oldh);
125 myPanelWidth = w;
126 myLineHeight = myPanelWidth*1.0f/maxLine;
127 mUnder = h - (h - myPanelWidth) / 2;
128
129 int pieceWidth = (int) (myLineHeight*ratioPieceOfLineHight); //棋子大小占行寬的3/4
130 myWhitePice = Bitmap.createScaledBitmap(myWhitePice, pieceWidth, pieceWidth, false); //以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。
131 myBlackPice = Bitmap.createScaledBitmap(myBlackPice, pieceWidth, pieceWidth, false);
132 }
133
134 protected void onDraw(Canvas canvas) { //Canvas類相當於一塊畫布
135 super.onDraw(canvas);
136 drawBroad(canvas);
137 drawPiece(canvas);
138 checkGameOver();
139 }
140
141 private void drawBroad(Canvas canvas){ //畫出棋盤線
142 int w = myPanelWidth;
143 float lineHeight = myLineHeight;
144 int startX = (int) (lineHeight/2); //棋盤線起始X坐標
145 int endX = (int)(w-lineHeight/2); //棋盤終止X坐標
146 for(int i = 0; i< maxLine; i++){
147 int y = (int)((i+1.5)*lineHeight); //y坐標
148
149 canvas.drawLine(startX, y, endX, y, myPaint); //畫棋盤橫向線
150 canvas.drawLine(y, startX, y, endX, myPaint); //畫棋盤縱向線
151 }
152 }
153
154 //畫棋子
155 private void drawPiece(Canvas canvas) {
156 int n1 = myWhiteArray.size();
157 int n2 = myBlackArray.size();
158 for(int i =0; i< n1 ;i++){
159 Point whitePoint = myWhiteArray.get(i);
160 canvas.drawBitmap(myWhitePice, (whitePoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight,
161 (whitePoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null);
162 //drawBitmap(Bitmap bitmap, float left, float top, Paint paint);Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置
163 }
164
165 for(int i =0; i< n2 ;i++){
166 Point blackPoint = myBlackArray.get(i);
167 canvas.drawBitmap(myBlackPice, (blackPoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight,
168 (blackPoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null);
169 }
170 }
171
172 //檢測游戲是否結束
173 private void checkGameOver(){
174 boolean whiteWin = checkFiveInLine(myWhiteArray);
175 boolean blackWin = checkFiveInLine(myBlackArray);
176
177 if (whiteWin || blackWin) {
178 isGemOver = true;
179 if (onGameListener != null) {
180 onGameListener.onGameOver(whiteWin ? WHITE_WIN : BLACK_WIN);
181 }
182 }
183 }
184 //回調一個int數據用於設置Dialog的位置
185 public int getUnder() {
186
187 return mUnder;
188 }
189
190 //檢測是否存在五棋子相連的情況
191 private boolean checkFiveInLine(List myArray){
192 for(Point p : myArray){
193 int x = p.x;
194 int y = p.y;
195
196 boolean win_flag = //判斷是否存在五子相連情況
197 checkHorizontal(x , y ,myArray)||checkVertical(x,y,myArray)
198 ||checkLeftDiagonal(x,y,myArray)||checkRightDiagonal(x,y,myArray);
199 if (win_flag) {
200 return true;
201 }
202 }
203 return false;
204 }
205
206 //橫向檢查是否滿足五子相連
207 private boolean checkHorizontal(int x ,int y ,List myArray){
208 int count = 1;
209 for(int i = 1;i < 5; i++){
210 if (myArray.contains(new Point(x+i,y))) {
211 count++;
212 }else {
213 break;
214 }
215 }
216 if (count == 5) {
217 return true;
218 }
219 for(int i = 1;i < 5; i++){
220 if (myArray.contains(new Point(x-i,y))) {
221 count++;
222 }else {
223 break;
224 }
225
226
227 if (count == 5) {
228 return true;
229 }
230 }
231 return false;
232 }
233
234 //縱向檢查是否滿足五子相連
235 private boolean checkVertical(int x ,int y ,List myArray){
236 int count = 1;
237 for(int i = 1;i < 5; i++){
238 if (myArray.contains(new Point(x,y+i))) {
239 count++;
240 }else {
241 break;
242 }
243
244 }
245 if (count == 5) {
246 return true;
247 }
248 for(int i = 1;i < 5; i++){
249 if (myArray.contains(new Point(x,y-i))) {
250 count++;
251 }else {
252 break;
253 }
254 if (count == 5) {
255 return true;
256 }
257 }
258 return false;
259 }
260
261 //左斜向檢查是否滿足五子相連
262 private boolean checkLeftDiagonal(int x ,int y ,List myArray){
263 int count = 1;
264 for(int i = 1;i < 5; i++){
265 if (myArray.contains(new Point(x-i,y+i))) {
266 count++;
267 }else {
268 break;
269 }
270
271 }
272 if (count == 5) {
273 return true;
274 }
275 for(int i = 1;i < 5; i++){
276 if (myArray.contains(new Point(x+i,y-i))) {
277 count++;
278 }else {
279 break;
280 }
281 if (count == 5) {
282 return true;
283 }
284 }
285 return false;
286 }
287
288 //右斜向檢查是否滿足五子相連
289 private boolean checkRightDiagonal(int x ,int y ,List myArray){
290 int count = 1;
291 for(int i = 1;i < 5; i++){ //切記,i = 1 開始,否則就會只檢測到三個子相連就結束了
292 if (myArray.contains(new Point(x-i,y-i))) {
293 count++;
294 }else {
295 break;
296 }
297 }
298 if (count == 5) {
299 return true;
300 }
301 for(int i = 1;i < 5; i++){
302 if (myArray.contains(new Point(x+i,y+i))) {
303 count++;
304 }else {
305 break;
306 }
307 if (count == 5) {
308 return true;
309 }
310 }
311 return false;
312 }
313
314 //重新開始游戲
315 protected void restartGame(){
316 myWhiteArray.clear();
317 myBlackArray.clear();
318 isGemOver = false;
319 isWhite = false;
320 invalidate();
321 }
322 }
終於,完成我們的自定義控件設計之後,我們就進入Activity的編寫吧,代碼如下:
1 public class MainActivity extends Activity {
2
3 private Chess_Panel panel;
4 private AlertDialog.Builder builder;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_main);
10
11 Window window = getWindow();
12 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
13 panel = (Chess_Panel)findViewById(R.id.main_panel);
14 builder= new AlertDialog.Builder(MainActivity.this);
15 builder.setTitle("游戲結束");
16 builder.setNegativeButton("退出", new OnClickListener() {
17
18 @Override
19 public void onClick(DialogInterface dialogInterface, int which) {
20 MainActivity.this.finish();
21 }
22 });
23 builder.setPositiveButton("再來一局", new OnClickListener() {
24
25 @Override
26 public void onClick(DialogInterface interface1, int which) {
27
28 panel.restartGame();
29 }
30 });
31 panel.setOnGameListener(new Chess_Panel.onGameListener() {
32
33 @Override
34 public void onGameOver(int i) {
35 String str = "";
36 if (i== Chess_Panel.WHITE_WIN) {
37 str = "白方勝利!";
38 }else if (i== Chess_Panel.BLACK_WIN) {
39 str = "黑方勝利!";
40 }
41 builder.setMessage(str);
42 builder.setCancelable(false); //不可用返回鍵取消
43 AlertDialog dialog = builder.create();
44 Window dialogWindow = dialog.getWindow();
45 WindowManager.LayoutParams params = new WindowManager.LayoutParams();
46 params.x = 0;
47 params.y = panel.getUnder();
48 dialogWindow.setAttributes(params); //設置Dialog顯示的位置
49 dialog.setCanceledOnTouchOutside(false); //不可點擊取消
50 dialog.show();
51 }
52 } );
53
54 }
55 }
這兩句的作用是讓游戲滿屏顯示,即不顯示通知狀態欄:
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
另外注意,不要忘記在activity_main.xml中添加我們自定義的控件,代碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg"
tools:context="com.example.fivechess.MainActivity" >
<com.example.fivechess.Chess_Panel
android:id="@+id/main_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</RelativeLayout>
至此,我們的項目就完成了,接下來解釋下載安裝到手機上運行了,其效果如下:



Android逆向之旅---Android中的sharedUserId屬性詳解
一、前言今天我們來看一下Android中一個眾人熟悉的一個屬性:shareUserId,關於這個屬性可能大家都很熟悉了,最近在開發項目,用到了這個屬性,雖然知道一點知識,
miui8如何開啟多窗口模式 miui8微信多窗口模式
當我們在移動端閱讀文章時,總會有朋友發了一條微信給你。這時候,我是繼續看文章還是回微信呢?MIUI8的微信多窗口功能讓你徹底擺脫這個煩惱,多窗口模式能夠讓你
使用DrawerLayout組件實現側滑抽屜的功能
DrawerLayout組件同樣是V4包中的組件,也是直接繼承於ViewGroup類,所以這個類也是一個容器類。使用DrawerLayout可以輕松的實現抽屜效果,使用D
Android開發藝術探索學習筆記(一)—Activity的生命周期和啟動模式
學習章節:第一章 Activity的生命周期和啟動模式學習內容:1正常情況下Activity的生命周期分析先上一張經典圖片鎮樓:測試正常情況Activity生命周期的代碼