今天写的博客是2048,说实话我是开始要写2048的时候才下一个来玩一下,之前是不懂的,玩了之后发现简单易入迷。下面直入主题,
一开始,首先要熟悉2048这个游戏,最好写一下规则说明书,这里我就不列出来了。
效果图展示:开始界面——>功能选择界面——>游戏界面
功能介绍:
开始界面:五秒之后进入功能选择界面
功能选择界面:根据不同的按钮来选择游戏的模式,可以选择不同模式,对应会有不同的图片进入游戏界面就开始播放背景音乐
游戏界面:1.记录分数;2.保留最高分;3.游戏区域符合游戏规则;4.背景音乐的播放开始暂停和停止;5.移动合并的声音 ; 6.游戏重来; 7.赢或者输跳出对话框
核心思想:(可以看完代码再来体会,或者体会完能有所启发后自己写)
做完这个2048后,给我最大的感觉就是把游戏界面当做一个自定义组件来实现,就像是系统自给的组件,比如按钮,按钮有自己的颜色大小外观,你点击按钮会有点击事件(切换图片显示下按效果),那么一个游戏界面也是这样的,有自己的颜色大小外观,和响应事件,那么这些内容就要我们自己来实现。
其次就是2048的游戏逻辑,移动、合并、判断输赢,这些都要好好思考算法。经典地用到了二维数组来存储卡片位置,便于增删的链表来记录空位置。
再然后,如何打造个性化的2048,就是把数字变成自己喜欢的图片咯~数字逻辑转换为图像逻辑时,运用到了数组,算是比较笨的方法,但也是最容易想到的。
最后是传参问题,一是方式,activity之间的跳转用intent来传参;一般的用getxx,setxx来传参;自定义组件上下文context不用传构造函数里有。二是先后顺序,一开始我把获取参数放在GameView的构造函数里,这样GameView在初始化时已经执行了获取参数,参数来不及传过来的。
实现流程:
java代码:
</pre><pre name="code" class="java">/**
* @author Clark Xu
*
* 五秒之后跳转到功能选择界面
*
*/
public class WelcomeActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
setContentView(R.layout.welcome);
skip();
}
// 5秒之后跳转到第二个页面
// time计时器
public void skip() {
final Intent it = new Intent(WelcomeActivity.this, ChooseActivity.class); // 你要转向的Activity
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
startActivity(it); // 执行
}
};
timer.schedule(task, 1000 * 5);
}
}
/**
* @author Clark Xu
*
* 功能选择界面:根据不同的按钮来选择游戏的模式,进入游戏界面就开始播放对应的背景音乐
*
*/
public class ChooseActivity extends Activity {
private int row = 4, column = 4;
private int model = 1;
private Button Btn3x3;
private Button Btn4x4;
private Button Btn5x5;
private Button Btn6x6;
private Button NormalBtn;
private Button DigitBtn;
private Button QilongzhuBtn;
private Button HuoyinBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
setContentView(R.layout.choose);
getView();
setListeners();
}
public void getView() {
Btn3x3 = (Button) findViewById(R.id.Btn3x3);
Btn4x4 = (Button) findViewById(R.id.Btn4x4);
Btn5x5 = (Button) findViewById(R.id.Btn5x5);
Btn6x6 = (Button) findViewById(R.id.Btn6x6);
NormalBtn = (Button) findViewById(R.id.NormalBtn);
DigitBtn = (Button) findViewById(R.id.DigitBtn);
QilongzhuBtn = (Button) findViewById(R.id.QilongzhuBtn);
HuoyinBtn = (Button) findViewById(R.id.HuoyinBtn);
}
//多个按钮添加监听事件用这种格式简洁明了
public void setListeners() {
Button button[] = { Btn3x3, Btn4x4, Btn5x5, Btn6x6, NormalBtn,
DigitBtn, QilongzhuBtn, HuoyinBtn };
// 创一个事件处理类
ButtonListener bl = new ButtonListener();
for (int i = 0; i < 8; i++) {
button[i].setOnClickListener(bl);
}
}
class ButtonListener implements OnClickListener{
//他们都要发生跳转,然后各自传不同的参数
@Override
public void onClick(View v) {
if(v instanceof Button){
//发生跳转
Intent intent =new Intent(ChooseActivity.this,MainActivity.class);
//传不同参
int btnId=v.getId();
switch (btnId) {
case R.id.Btn3x3:
column = 3;
row = 3;
break;
case R.id.Btn4x4:
column = 4;
row = 4;
break;
case R.id.Btn5x5:
column = 5;
row = 5;
break;
case R.id.Btn6x6:
column = 6;
row = 6;
break;
case R.id.NormalBtn:
model = 1;
break;
case R.id.DigitBtn:
model = 2;
break;
case R.id.QilongzhuBtn:
model = 3;
break;
case R.id.HuoyinBtn:
model = 4;
break;
default:
break;
}
intent.putExtra("column", column);
intent.putExtra("row", row);
intent.putExtra("model", model);
intent.putExtra("music", true);
startActivity(intent);
}
}
}
}
/**
* @author Clark Xu
* 把自定义组件GameView添加到这上面,
* 获取传过来的各种参数,执行不同的模式
*
*/
public class MainActivity extends Activity {
private int score = 0;
private TextView tvScore;
private TextView tvBestScore;
private int column = 4;
private int row = 4;
private int model = 1;
private MediaPlayer mp;
private boolean music = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button resbtn = (Button) findViewById(R.id.resbtn);
tvScore = (TextView) findViewById(R.id.scoreView2);
tvBestScore = (TextView) findViewById(R.id.scoreView4);
Intent intent = this.getIntent();
row = intent.getIntExtra("row", 4);
column = intent.getIntExtra("column", 4);
model = intent.getIntExtra("model", 1);
switch (model) {
case 1:// 数字版
mp = MediaPlayer.create(this, R.raw.infectious);
break;
case 2:// 数码版
mp = MediaPlayer.create(this, R.raw.braveheart);
break;
case 3:// 七龙珠版
mp = MediaPlayer.create(this, R.raw.qilongzhu);
break;
case 4:// 火影版
mp = MediaPlayer.create(this, R.raw.huoyin);
break;
}
try {
mp.prepare();// 让mp对象准备
} catch (Exception e) {
e.printStackTrace();
}
// 一进来就播放音乐
music = intent.getBooleanExtra("music", false);
if (music && (null != mp)) {
mp.start();
mp.setLooping(true);
}
// 开始游戏的逻辑
GameView.getGameView().initGameView();
// 获取三个按钮
Button butStart = (Button) this.findViewById(R.id.startBtn);
Button butPause = (Button) this.findViewById(R.id.pauseBtn);
Button butStop = (Button) this.findViewById(R.id.stopBtn);
// 实例化事件处理类
MusicListener ml = new MusicListener();
// 给事件源添加动作监听方法,指定事件处理类对象ml
butStart.setOnClickListener(ml);
butPause.setOnClickListener(ml);
butStop.setOnClickListener(ml);
resbtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
GameView.getGameView().startGame();
clearScore();
}
});
}
class MusicListener implements OnClickListener {
@Override
public void onClick(View v) {
Button btn = (Button) v;
String text = btn.getText().toString();
if (text.equals("START")) {
if (null != mp)
mp.start();
mp.setLooping(true);
} else if (text.equals("PAUSE")) {
if (null != mp)
mp.pause();
} else if (text.equals("STOP")) {
// stop的话就完全结束了,还不如用pause,再调用seekTo时间调为0
try {
mp.pause();
mp.seekTo(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public int getColumn() {
return column;
}
public int getRow() {
return row;
}
public int getModel() {
return model;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void clearScore() {
score = 0;
showScore();
}
public void showScore() {
tvScore.setText(score + "");
}
public void addScore(int s) {
score += s;
showScore();
int maxScore = Math.max(score, getBestScore());
saveBestScore(maxScore);
showBestScore(maxScore);
}
// 保存分数
public void saveBestScore(int s) {
Editor e = getPreferences(MODE_PRIVATE).edit();
e.putInt("bestScore", s);
e.commit();
}
public int getBestScore() {
return getPreferences(MODE_PRIVATE).getInt("bestScore", 0);
}
public void showBestScore(int s) {
tvBestScore.setText(s + "");
}
// 销毁Activity时执行的,重写此方法表示Activity的生命周期结束不要一直播放占用资源
protected void onDestroy() {
super.onDestroy();
if (null != mp)
try {
mp.release();
} catch (Exception e) {
e.getStackTrace();
}
}
}
/**
* @author Clark Xu
* 游戏自定义组件:设置大小颜色模式,
* 根据响应实现游戏逻辑
* 继承表格布局更合适
*/
public class GameView extends GridLayout {
private float startX, startY, endX, endY, offX, offY;
private int row = 4, colunm = 4;// 行row对应y,列colunm对应x,默认开始都为4
private CardView[][] cardsMap = new CardView[10][10];// 用一个二维数组来存
private List<Point> emptyPoints = new ArrayList<Point>();// 链表方便增加删除
private static GameView gview = null;
private MainActivity my2048;
private CardAnim ca = new CardAnim();
private int cw;
// 在xml中能够访问则要添加构造方法
// 以防万一三个构造方法都要写:对应参分别为上下文,属性,样式
public GameView(Context context) {
super(context);
gview = this;
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
gview = this;
}
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
gview = this;
}
public static GameView getGameView() {
return gview;
}
// 由于手机可能不同,我们需要动态地获取卡片的宽高,所以要重写下面这个方法获取当前布局的宽高,
// 为了让手机不会因倒过来改变宽高,要去mainifest里配置
// 只会在手机里第一次运行的时候执行,之后不会改变
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int cardWidth = (Math.min(w, h) - 10) / colunm;
addCards(cardWidth, cardWidth);// 把参数传过去
startGame();
}
public void startGame() {
for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
cardsMap[x][y].setNum(0);
}
}
my2048.addScore(0);
my2048.clearScore();
addRandomNum();
addRandomNum();
}
private void addCards(int cardWidth, int cardHeigth) {
CardView c;
cw = cardWidth;
for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
// 并不知道getContext是什么意思
c = new CardView(getContext());
// 先都初始画0号图片
c.setNum(0);
addView(c, cardWidth, cardHeigth);
// 把所有的卡片都记录下来
cardsMap[x][y] = c;
}
}
}
// 添加随机数的时候要先遍历
private void addRandomNum() {
emptyPoints.clear();
for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
if (cardsMap[x][y].getNum() <= 0) {
emptyPoints.add(new Point(x, y));// 把空位给emptypoints链表
}
}
}
// 随机把emptyPoints中的一个赋值,生成2的概率为9,4为1
Point p = emptyPoints
.remove((int) (Math.random() * emptyPoints.size()));
// 2号图片和4号图片
cardsMap[p.x][p.y].setNum(Math.random() > 0.1 ? 2 : 4);
//动画生成效果
ca.createScaleTo1(cardsMap[p.x][p.y]);
}
// GameView实现的功能
public void initGameView() {
my2048 = (MainActivity) this.getContext();
colunm = my2048.getColumn();
row = my2048.getRow();
setColumnCount(colunm);// 设置表格为4列
setBackgroundColor(Color.BLUE);
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();// 获取触屏的动作
switch (action) {
// 按下获取起始点
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
// 松开获取终止点,通过比较位移来判断滑动方向
// 要处理一下滑动偏的,看offx和offy哪个绝对值大就按照哪个来
case MotionEvent.ACTION_UP:
endX = event.getX();
endY = event.getY();
offX = startX - endX;
offY = startY - endY;
if (Math.abs(offX) >= Math.abs(offY)) {
if (offX >= 5)
moveLeft();// System.out.println("左");
else if (offX < -5)
moveRight();// System.out.println("右");
} else if (Math.abs(offX) <= Math.abs(offY)) {
if (offY >= 5)
moveUp();// System.out.println("上");
else if (offY < -5)
moveDown();// System.out.println("下");
}
break;
}
// !!!要改为true,否则ACTION_UP不会执行
return true;
}
});
}
private void moveLeft() {
boolean merge = false;
for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
// 遍历当前位置的右边,如果有数字,如果当前位置没有数字,则合并到当前位置
for (int x1 = x + 1; x1 < colunm; x1++) {
// 每个右边的位置只判断执行一次
if (cardsMap[x1][y].getNum() > 0) {
if (cardsMap[x][y].getNum() <= 0) {
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
x--;// 填补空位后,还要再次判断有没相同的可以合并的
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_MOVE);
break;
} else if (cardsMap[x][y].equals(cardsMap[x1][y])) {
cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
cardsMap[x1][y].setNum(0);
my2048.addScore(cardsMap[x][y].getNum());
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_CANCEL);
break;
}
break;
}
}
}
}
if (merge) {
addRandomNum();
checkComplete();
}
}
private void moveRight() {
boolean merge = false;
for (int y = 0; y < row; y++) {
for (int x = colunm - 1; x >= 0; x--) {
// 遍历当前位置的右边,如果有数字,如果当前位置没有数字,则合并到当前位置
for (int x1 = x - 1; x1 >= 0; x1--) {
// 每个右边的位置只判断执行一次
if (cardsMap[x1][y].getNum() > 0) {
if (cardsMap[x][y].getNum() <= 0) {
cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
cardsMap[x1][y].setNum(0);
x++;// 填补空位后,还要再次判断有没相同的可以合并的
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_MOVE);
break;
} else if (cardsMap[x][y].equals(cardsMap[x1][y])) {
cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
cardsMap[x1][y].setNum(0);
my2048.addScore(cardsMap[x][y].getNum());
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_CANCEL);
break;
}
break;
}
}
}
}
if (merge) {
addRandomNum();
checkComplete();
}
}
private void moveUp() {
boolean merge = false;
for (int x = 0; x < colunm; x++) {
for (int y = 0; y < row; y++) {
// 遍历当前位置的右边,如果有数字,如果当前位置没有数字,则合并到当前位置
for (int y1 = y + 1; y1 < row; y1++) {
// 每个右边的位置只判断执行一次
if (cardsMap[x][y1].getNum() > 0) {
if (cardsMap[x][y].getNum() <= 0) {
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
cardsMap[x][y1].setNum(0);
y--;// 填补空位后,还要再次判断有没相同的可以合并的
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_MOVE);
break;
} else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
cardsMap[x][y1].setNum(0);
my2048.addScore(cardsMap[x][y].getNum());
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_CANCEL);
break;
}
break;
}
}
}
}
if (merge) {
addRandomNum();
checkComplete();
}
}
private void moveDown() {
boolean merge = false;
for (int x = 0; x < colunm; x++) {
for (int y = row - 1; y >= 0; y--) {
// 遍历当前位置的右边,如果有数字,如果当前位置没有数字,则合并到当前位置
for (int y1 = y - 1; y1 >= 0; y1--) {
// 每个右边的位置只判断执行一次
if (cardsMap[x][y1].getNum() > 0) {
if (cardsMap[x][y].getNum() <= 0) {
cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
cardsMap[x][y1].setNum(0);
y++;// 填补空位后,还要再次判断有没相同的可以合并的
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_MOVE);
break;
} else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
cardsMap[x][y1].setNum(0);
my2048.addScore(cardsMap[x][y].getNum());
merge = true;
MyPlayer.playTone(getContext(),
MyPlayer.INDEX_SONG_CANCEL);
break;
}
break;
}
}
}
}
if (merge) {
addRandomNum();
checkComplete();
}
}
// 判断结束
private void checkComplete() {
boolean complete = true;
for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
if (cardsMap[x][y].getNum() == 2048)
new AlertDialog.Builder(getContext())
.setTitle("你好")
.setMessage("游戏胜利")
.setPositiveButton("重来",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,
int which) {
startGame();
}
}).show();
}
}
ALL: for (int y = 0; y < row; y++) {
for (int x = 0; x < colunm; x++) {
// 如果还有空位,或者四个方向上还有相同的
if (cardsMap[x][y].getNum() == 0
|| (x > 0 && cardsMap[x][y].equals(cardsMap[x - 1][y]))
|| (x < 3 && cardsMap[x][y].equals(cardsMap[x + 1][y]))
|| (y > 0 && cardsMap[x][y].equals(cardsMap[x][y - 1]))
|| (y < 3 && cardsMap[x][y].equals(cardsMap[x][y + 1]))) {
complete = false;
break ALL;// 如果出现这种情况,跳出双重循环,只写一个break只能跳出当前循环
}
}
}
if (complete) {
new AlertDialog.Builder(getContext())
.setTitle("你好")
.setMessage("游戏结束")
.setPositiveButton("重来",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
startGame();
}
}).show();
}
}
}
/**
* @author Clark Xu
* 卡片自定义组件,添加到GameView上
*
*/
public class CardView extends FrameLayout {
private int num = 0;
// 只显示数字的话可以用Textview,要是用图片的话要用imview
private TextView label;
private ImageView pic;
private int[] picArray = new int[3000];
private MainActivity my2048;
private int model = 1;
private LayoutParams lp;
public CardView(Context context) {
super(context);
putPic();
pic = new ImageView(getContext());
lp = new LayoutParams(-1, -1);// -1,-1就是填充完父类容器的意思
lp.setMargins(10, 10, 0, 0);// 用来设置边框很管用
addView(pic, lp);// 把imageView加到CardView上
setNum(0);
}
//把数字逻辑实现的2048转化为图片逻辑,只需要把数字定位数组序数,数字对应图片,并保持一一对应关系
public void putPic() {
picArray[0] = R.drawable.num0;
picArray[2] = R.drawable.pic2;
picArray[4] = R.drawable.pic4;
picArray[8] = R.drawable.pic8;
picArray[16] = R.drawable.pic16;
picArray[32] = R.drawable.pic32;
picArray[64] = R.drawable.pic64;
picArray[128] = R.drawable.pic128;
picArray[256] = R.drawable.pic256;
picArray[512] = R.drawable.pic512;
picArray[1024] = R.drawable.pic1024;
picArray[2048] = R.drawable.pic2048;
// 数字版+7
picArray[7] = R.drawable.num0;
picArray[9] = R.drawable.num2;
picArray[11] = R.drawable.num4;
picArray[15] = R.drawable.num8;
picArray[23] = R.drawable.num16;
picArray[39] = R.drawable.num32;
picArray[71] = R.drawable.num64;
picArray[135] = R.drawable.num128;
picArray[263] = R.drawable.num256;
picArray[519] = R.drawable.num512;
picArray[1031] = R.drawable.num1024;
picArray[2055] = R.drawable.num2048;
// 七龙珠版+10
picArray[10] = R.drawable.num0;
picArray[12] = R.drawable.wk1;
picArray[14] = R.drawable.wk2;
picArray[18] = R.drawable.wk3;
picArray[26] = R.drawable.wk4;
picArray[42] = R.drawable.wk5;
picArray[74] = R.drawable.wk6;
picArray[128] = R.drawable.wk7;
picArray[266] = R.drawable.wk8;
picArray[522] = R.drawable.wk9;
picArray[1034] = R.drawable.wk10;
picArray[2058] = R.drawable.wk11;
// 其他版+17
picArray[17] = R.drawable.num0;
picArray[19] = R.drawable.hy1;
picArray[21] = R.drawable.hy2;
picArray[25] = R.drawable.hy3;
picArray[33] = R.drawable.hy4;
picArray[49] = R.drawable.hy5;
picArray[81] = R.drawable.hy6;
picArray[145] = R.drawable.hy7;
picArray[273] = R.drawable.hy8;
picArray[529] = R.drawable.hy9;
picArray[1041] = R.drawable.hy10;
picArray[2065] = R.drawable.hy11;
}
// 数字:数字相当于图片id
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
my2048 = (MainActivity) this.getContext();
model = my2048.getModel();
System.out.println(">>>>>>>>>>" + model);
switch (model) {
case 1:// 普通模式
pic.setBackgroundResource(picArray[num + 7]);
break;
case 2:// 数码模式
pic.setBackgroundResource(picArray[num]);
break;
case 3:// 七龙珠模式
pic.setBackgroundResource(picArray[num + 10]);
break;
case 4:// 火影模式
pic.setBackgroundResource(picArray[num + 17]);
break;
}
}
// 判断数字是否相同
public boolean equals(CardView cv) {
return getNum() == cv.getNum();
}
}
/**
* @author Clark Xu
* 音效播放类MyPlayer,
* 因为是放在asset目录下读取方式有所不同
*
*/
public class MyPlayer {
public final static int INDEX_SONG_MOVE = 0;
public final static int INDEX_SONG_CANCEL = 1;
public final static int INDEX_SONG_BEGIN = 2;
private final static String[] SONG_NAMES = { "cancel.mp3", "move.mp3",
"braveheart.mp3" };
// 音效播放
private static MediaPlayer[] mToneMediaPlayer = new MediaPlayer[SONG_NAMES.length];
/*
* 播放声音效果 cancel move
*/
public static void playTone(Context context, int index) {
// 加载声音
AssetManager assetManager = context.getAssets();
if (mToneMediaPlayer[index] == null) {
mToneMediaPlayer[index] = new MediaPlayer();
try {
AssetFileDescriptor fileDescriptor = assetManager
.openFd(SONG_NAMES[index]);
mToneMediaPlayer[index].setDataSource(
fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
mToneMediaPlayer[index].prepare();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
mToneMediaPlayer[index].start();
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- 主界面的布局方式 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.65"
android:orientation="horizontal" >
<TextView
android:id="@+id/scoreView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/score"
android:textSize="22sp" />
<TextView
android:id="@+id/scoreView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22sp" />
<TextView
android:id="@+id/scoreView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bestscore"
android:textSize="22sp" />
<TextView
android:id="@+id/scoreView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22sp" />
</LinearLayout>
<!-- 把自定义组件的全路径写下来 -->
<com.lanjie.game2048.GameView
android:id="@+id/GameView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/startBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/startBtn" />
<Button
android:id="@+id/pauseBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/pauseBtn" />
<Button
android:id="@+id/stopBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/stopBtn" />
</LinearLayout>
<Button
android:id="@+id/resbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/restart" />
</LinearLayout>
over