0%

Android开发之2048安卓版

之前是在eclipse上写的,后面换成了android sudio。 2048游戏的UI整体可以采用线性布局,即LinearLayout,其中嵌套一个线性布局和一个GridLayout,内嵌的线性布局填充文本框,以显示分数,GridLayout中填充4x4的继承自FrameLayout的card类作为主要的游戏界面。由于大部分操作都在GridLayout中进行,可以自定义一个继承自GridLayout的类GameView,类中定义判定上下左右滑动的方法和每次滑动后自动添加一个随机数字的方法以及每次滑动后判断游戏是否可以继续进行的方法。 主布局activity_main.xml代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
//match_parent表示布局充满整个屏幕
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administractor.game2048.MainActivity"
//里面的组件垂直放置
android:orientation="vertical"
tools:ignore="MergeRootFrame">

<LinearLayout
//宽度充满整个屏幕,高度自适应。
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
//显示当前分数的文本框
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your Score:"/>
<TextView
android:id="@+id/tvScore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
//使用自定义的GridLayout
<com.example.administractor.game2048.GameView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/GameView" >
</com.example.administractor.game2048.GameView>
</LinearLayout>

GameView.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
package com.example.administrator.game2048;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;

public class GameView extends GridLayout {
//调用类构造方法
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//初始化游戏
InitGameView();
}

public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
InitGameView();
}

public GameView(Context context) {
super(context);
InitGameView();
}
private void InitGameView(){
//设置为4x4个方格
setColumnCount(4);
//设置背景颜色
setBackgroundColor(0xffeee4da);

//判定滑动方向
setOnTouchListener(new OnTouchListener() {
private float startx,starty,offsetx,offsety;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
startx=event.getX();
starty=event.getY();
break;
case MotionEvent.ACTION_UP:
offsetx=event.getX()-startx;
offsety=event.getY()-starty;
if(Math.abs(offsetx)>Math.abs(offsety)){
if(offsetx<-5){
swipeLeft();
}else if(offsetx>5){
swipeRight();
}
}else{
if(offsety<-5){
swipeUp();
}else if(offsetx>3){
swipeDown();
}
}
break;
}
return true;
}
});
}
//适应不同大小的屏幕
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int cardWidth=(Math.min(h, w))/4;
addCards(cardWidth,cardWidth);
startGame();
}
//在4x4的方格上添加满卡片
public void addCards(int cardwidth,int cardheight){
Card c;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
c=new Card(getContext());
c.setNum(0);
addView(c, cardwidth, cardheight);
cardmap[x][y]=c;
}
}
}
//游戏开始时每个卡片默认值设为0,并随机添加两张带数字的卡片
private void startGame(){
MainActivity.getMainActivity().clearScore();
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
cardmap[x][y].setNum(0);
}
}
addRandomNum();
addRandomNum();
}
private void addRandomNum() {
//使用emptypoints将数字为0的card提取出来,并随即选择一个空card赋值
emptyPoints.clear();
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if(cardmap[x][y].getNum()<=0){
emptyPoints.add(new Point(x,y));
}
}
}
Point p=emptyPoints.remove((int)(Math.random()*emptyPoints.size()));
//2和4出现的概率控制在1:9
cardmap[p.x][p.y].setNum(Math.random()>0.1?2:4);
}
//左滑方法
private void swipeLeft(){
//merge作为判断能否滑动的flag
boolean merge = false;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
for (int x1 = x+1; x1 <4; x1++) {
if(cardmap[x1][y].getNum()>0){
if(cardmap[x][y].getNum()<=0){
cardmap[x][y].setNum(cardmap[x1][y].getNum());
cardmap[x1][y].setNum(0);
merge=true;
x--;
}else if(cardmap[x][y].equal(cardmap[x1][y])){
cardmap[x][y].setNum(cardmap[x][y].getNum()*2);
cardmap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardmap[x][y].getNum());
merge=true;
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
//下滑
private void swipeDown(){

boolean merge = false;

for (int x = 0; x < 4; x++) {
for (int y = 3; y >=0; y--) {

for (int y1 = y-1; y1 >=0; y1--) {
if (cardmap[x][y1].getNum()>0) {

if (cardmap[x][y].getNum()<=0) {
cardmap[x][y].setNum(cardmap[x][y1].getNum());
cardmap[x][y1].setNum(0);

y++;
merge = true;
}else if (cardmap[x][y].equal(cardmap[x][y1])) {
cardmap[x][y].setNum(cardmap[x][y].getNum()*2);
cardmap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardmap[x][y].getNum());
merge = true;
}

break;
}
}
}
}

if (merge) {
addRandomNum();
checkComplete();
}
}
//上滑
private void swipeUp(){

boolean merge = false;

for (int x = 0; x < 4; x++) {
for (int y = 0; y < 4; y++) {

for (int y1 = y+1; y1 < 4; y1++) {
if (cardmap[x][y1].getNum()>0) {

if (cardmap[x][y].getNum()<=0) {
cardmap[x][y].setNum(cardmap[x][y1].getNum());
cardmap[x][y1].setNum(0);

y--;

merge = true;
}else if (cardmap[x][y].equal(cardmap[x][y1])) {
cardmap[x][y].setNum(cardmap[x][y].getNum()*2);
cardmap[x][y1].setNum(0);
MainActivity.getMainActivity().addScore(cardmap[x][y].getNum());
merge = true;
}

break;

}
}
}
}

if (merge) {
addRandomNum();
checkComplete();
}
}
//右滑
private void swipeRight(){
boolean merge = false;
for (int y = 0; y < 4; y++) {
for (int x = 3; x >=0; x--) {
for (int x1 = x-1; x1 >=0; x1--) {
if(cardmap[x1][y].getNum()>0){
if(cardmap[x][y].getNum()<=0){
cardmap[x][y].setNum(cardmap[x1][y].getNum());
cardmap[x1][y].setNum(0);
x++;
merge=true;
}else if(cardmap[x][y].equal(cardmap[x1][y])){
cardmap[x][y].setNum(cardmap[x][y].getNum()*2);
cardmap[x1][y].setNum(0);
MainActivity.getMainActivity().addScore(cardmap[x][y].getNum());
merge=true;
}
break;
}
}
}
}
if(merge){
addRandomNum();
checkComplete();
}
}
//如果有空卡片或者相邻的值相同卡片则游戏还能进行
public void checkComplete(){
boolean complete=true;
ALL:
for (int y = 0; y <4; y++) {
for (int x = 0; x <4; x++) {
if(cardmap[x][y].getNum()==0||
x>0&&cardmap[x][y].equal(cardmap[x-1][y])||
x<3&&cardmap[x][y].equal(cardmap[x+1][y])||
y>0&&cardmap[x][y].equal(cardmap[x][y-1])||
y<3&&cardmap[x][y].equal(cardmap[x][y+1])){
complete=false;
break ALL;
}
}
}
//游戏结束弹出alert提示窗口
if(complete){
new AlertDialog.Builder(getContext()).setTitle("大林哥温馨提示").setMessage("游戏结束").setPositiveButton("重来",new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface arg0, int arg1) {
startGame();
}
}).show();
}

}
private Card[][] cardmap=new Card[4][4];
private List<Point> emptyPoints=new ArrayList<Point>();
}

主类MainActivity.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.administrator.game2048;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

public MainActivity(){
mainActivity=this;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvscore = (TextView) findViewById(R.id.tvScore);
}
public void clearScore(){
score=0;
showScore();
}
public void showScore(){
tvscore.setText(score+"");
}
public void addScore(int s){
score+=s;
showScore();
}
private TextView tvscore;
private int score=0;
public static MainActivity mainActivity=null;
public static MainActivity getMainActivity() {
return mainActivity;
}
}

Card.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.example.administrator.game2048;

import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;

public class Card extends FrameLayout {

public Card(Context context) {
super(context);
LayoutParams lp = null;

View background = new View(getContext());
//参数-1表示layoutparams填充满整个父容器
lp = new LayoutParams(-1, -1);
//设置卡片之间有10像素的间隔
lp.setMargins(10, 10, 0, 0);
background.setBackgroundColor(0x33ffffff);
addView(background, lp);

label = new TextView(getContext());
label.setTextSize(28);
label.setGravity(Gravity.CENTER);

lp = new LayoutParams(-1, -1);
lp.setMargins(10, 10, 0, 0);
addView(label, lp);

setNum(0);
}



private int n=0;
public int getNum(){
return n;
}
//设置数字及对应的背景颜色
public void setNum(int n){
this.n=n;
if(n<=0){
label.setText("");
}else{
label.setText(n+"");
}
switch (n) {
case 0:
label.setBackgroundColor(0x00000000);
break;
case 2:
label.setBackgroundColor(0xffeee4da);
break;
case 4:
label.setBackgroundColor(0xffede0c8);
break;
case 8:
label.setBackgroundColor(0xfff2b179);
break;
case 16:
label.setBackgroundColor(0xfff59563);
break;
case 32:
label.setBackgroundColor(0xfff67c5f);
break;
case 64:
label.setBackgroundColor(0xfff65e3b);
break;
case 128:
label.setBackgroundColor(0xffedcf72);
break;
case 256:
label.setBackgroundColor(0xffedcc61);
break;
case 512:
label.setBackgroundColor(0xffedc850);
break;
case 1024:
label.setBackgroundColor(0xffedc53f);
break;
case 2048:
label.setBackgroundColor(0xffedc22e);
break;
default:
label.setBackgroundColor(0xff3c3a32);
break;
}
}
//判断卡片是否相等
public boolean equal(Card o){
return getNum()==o.getNum();
}
private TextView label;
}