转载请注明出处:http://blog.csdn.net/sw950729/article/details/52211315 本文出自:马云飞的博客 前天去osc原创会溜了一圈,结果因为G20找个住的地方都难- - !然后各种悲剧就发生了。昨天下午回家睡了一觉,原本晚上更新的,结果发生电脑充电器扔公司。什么鬼,fuck++,有史以来最惨的一个周末。(说好的一周最少一更的~~~~)好了话不多说,进入正题。 关于自定义view我们前面讲到了五子棋。这次讲个简单的,2048的实现。当然,如果你看懂了前面的自定义,今天的都不是问题。 首先需要自定义Gridlayout来实现自定义的几个方法,我们来看看初始化,设置每行最大数量以及颜色和手势滑动,代码如下:
private void initalgame() { setColumnCount(4);// 设置每行最多4个 setBackgroundColor(0xffbbada0); setOnTouchListener(new View.OnTouchListener() { private float startX, startY, changeX, changeY; public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX();// 起始的X坐标 startY = event.getY();// 起始的Y坐标 break; case MotionEvent.ACTION_UP: changeX = event.getX() - startX;// 改变的X坐标=现在的-起始的 changeY = event.getY() - startY;// 改变的Y坐标=现在的-起始的 // 若X的绝对值>Y的绝对值,则是左右移动,否则为上下移动,左上角坐标为(0,0) if (Math.abs(changeX) > Math.abs(changeY)) { if (changeX < -5) { Left(); } else if (changeX > 5) { Right(); } } else { if (changeY < -5) { Up(); } else if (changeY > 5) { Down(); } } break; } return true; } }); }我们需要一个卡片类来给Gridlayout的item设置内容和背景色:
public class Card extends FrameLayout { private TextView label; private int num = 0; public Card(Context context) { super(context); label = new TextView(getContext());// 新建个textview label.setTextSize(32);// 设置字体大小 label.setBackgroundColor(0x338B8B00);// 背景色 label.setTextColor(0x330D0D0D);// 设置字体颜色 label.setGravity(Gravity.CENTER);// 设置字体居中 // LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, // LayoutParams.MATCH_PARENT);// 铺满屏幕 LayoutParams lp = new LayoutParams(-1, -1); lp.setMargins(10, 10, 0, 0);// 间距10像素 addView(label, lp); setNum(0); } public int getNum() { return num; } public void setNum(int num) { this.num = num; label.setBackgroundColor(getBackColor(num));// 背景色 // 如果值为0,就不设置内容 if (num <= 0) { label.setText(""); } else { label.setText(num + ""); } } // 设置背景色 private int defaultBackColor = 0x338B8B00; private int getBackColor(int num) { int bgcolor = defaultBackColor; switch (num) { case 0: bgcolor = 0xffCCC0B3; break; case 2: bgcolor = 0xffEEE4DA; break; case 4: bgcolor = 0xffEDE0C8; break; case 8: bgcolor = 0xffF2B179;// #F2B179 break; case 16: bgcolor = 0xffF49563; break; case 32: bgcolor = 0xffF5794D; break; case 64: bgcolor = 0xffF55D37; break; case 128: bgcolor = 0xffEEE863; break; case 256: bgcolor = 0xffEDB04D; break; case 512: bgcolor = 0xffECB04D; break; case 1024: bgcolor = 0xffEB9437; break; case 2048: bgcolor = 0xffEA7821; break; default: bgcolor = 0xffEA7821; break; } return bgcolor; } // 判断2个数是否相等 public boolean equals(Card c) { return getNum() == c.getNum(); } }同时在自定义layout,我们需要计算出每个卡片的宽高:
private Card[][] cardsMap = new Card[4][4]; // 计算卡片的宽高 protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); int cardwidth = (Math.min(w, h) - 10) / 4; // 添加卡片 addCard(cardwidth, cardwidth); start();// 开始游戏 }开始游戏时,我们随机添加2个卡片。卡片内容为2或4,比例为9:1。
// 添加卡片 private void addCard(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); cardsMap[x][y] = c; } } } // 开始游戏 private void start() { MainActivity.getMainActivity().clear(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { cardsMap[x][y].setNum(0); } } // 添加随机数 addRandomNum(); addRandomNum(); } // 添加随机数 public void addRandomNum() { // 清空point point.clear(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { // 如果这个位置没有值。添加 if (cardsMap[x][y].getNum() <= 0) { point.add(new Point(x, y)); } } } // 随机移除一个点 Point p = point.remove((int) (Math.random() * point.size())); cardsMap[p.x][p.y].setNum(Math.random() > 0.1 ? 2 : 4); }剩下的就是判断滑动方向来进行数的位移和相加了:
private void Left() { boolean flag = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x + 1; x1 < 4; 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--; flag = true; } else if (cardsMap[x][y].equals(cardsMap[x1][y])) { cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity().add( cardsMap[x][y].getNum()); flag = true; } break; } } } } if (flag) { addRandomNum(); IsFinish(); } } private void Right() { Boolean flag = false; for (int y = 0; y < 4; y++) { for (int x = 3; 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++; flag = true; } else if (cardsMap[x][y].equals(cardsMap[x1][y])) { cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity().add( cardsMap[x][y].getNum()); flag = true; } break; } } } } if (flag) { addRandomNum(); IsFinish(); } } private void Up() { boolean flag = false; for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { for (int y1 = y + 1; y1 < 4; 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--; flag = true; } else if (cardsMap[x][y].equals(cardsMap[x][y1])) { cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity().add( cardsMap[x][y].getNum()); flag = true; } break; } } } } if (flag) { addRandomNum(); IsFinish(); } } private void Down() { boolean flag = false; for (int x = 0; x < 4; x++) { for (int y = 3; 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++; flag = true; } else if (cardsMap[x][y].equals(cardsMap[x][y1])) { cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity().add( cardsMap[x][y].getNum()); flag = true; } break; } } } } if (flag) { addRandomNum(); IsFinish(); } }最后我们每次滑动结束都是需要判断游戏是否结束,判断条件则是列表被铺满而且无法进行相加:
private void IsFinish() { boolean finish = true; ALL: for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; 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]))) { finish = false; break ALL; } } } if (finish) { new AlertDialog.Builder(getContext()) .setTitle("游戏结束!") .setMessage("您的得分为:" + MainActivity.score) .setPositiveButton("重来", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { start(); } }) .setNegativeButton("退出", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { MainActivity.getMainActivity().finish(); } }).show(); } }而我们需要一个类来保存我们的最高分,这里用了一个最简单的数据存储,Shareperference。代码很简单:
public class BestScode { private SharedPreferences sp; public BestScode(Context context){ sp = context.getSharedPreferences("bestscode", context.MODE_PRIVATE); } public int getBestScode(){ int bestscode = sp.getInt("bestscode", 0); return bestscode; } public void setBestScode(int bestScode){ Editor editor = sp.edit(); editor.putInt("bestscode", bestScode); editor.commit(); } }剩下的就是主activity了:
private TextView text; public static int score; private static MainActivity mainactivity = null; private TextView tv_bestScore; private int current_score = 0; private int currentBestScore; public MainActivity() { mainactivity = this; } public static MainActivity getMainActivity() { return mainactivity; } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inital(); } public void inital() { text = (TextView) findViewById(R.id.text); tv_bestScore = (TextView) findViewById(R.id.tv_bestScore); BestScode bs = new BestScode(this); currentBestScore = bs.getBestScode(); tv_bestScore.setText("" + currentBestScore); // WindowManager wm = (WindowManager) this // .getSystemService(Context.WINDOW_SERVICE); // int width = wm.getDefaultDisplay().getWidth(); // int height = wm.getDefaultDisplay().getHeight(); // iv=(ImageView) findViewById(R.id.image); // 生成图片 // iv.setImageResource(R.drawable.myname); // iv.setScaleType(ImageView.ScaleType.FIT_XY); // iv.setAdjustViewBounds(true); // iv.setMaxHeight(height);// 屏幕高度 // iv.setMaxWidth(width);// 屏幕宽度 } // 清空分数 public void clear() { score = 0; show(); } // 显示分数 public void show() { text.setText("" + score); } // 添加分数 public void add(int s) { score += s; show(); if (score > currentBestScore) { currentBestScore = score; BestScode bs = new BestScode(this); bs.setBestScode(currentBestScore); tv_bestScore.setText("" + currentBestScore); } } /** * 菜单、返回键响应 */ private long exitTime = 0; public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { if ((System.currentTimeMillis() - exitTime) > 2000) { Toast.makeText(this, "再按一次退出程序", 1000).show(); exitTime = System.currentTimeMillis(); } else { finish(); System.exit(0); } return true; } return super.onKeyDown(keyCode, event); }最后附上我的layout:
<LinearLayout 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="#bbada0" android:orientation="vertical" > <LinearLayout android:id="@+id/ll_best" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="最高纪录:" android:textColor="#FF0000" android:textSize="18sp" /> <TextView android:id="@+id/tv_bestScore" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textColor="#FF0000" android:textSize="20sp" /> </LinearLayout> <com.example.game2048.GameView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="4" > </com.example.game2048.GameView> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="得分:" android:textColor="#98F5FF" android:textSize="50sp" /> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="#98F5FF" android:textSize="50sp" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:text="作者:\n我就是马云飞" android:textColor="#90EE90" android:textSize="38sp" /> </LinearLayout> </LinearLayout>好了。有兴趣可以把这个demo进行延伸,写了等级划分啊,自定义背景啊~~~。 我的android交流群:232748032