这是在自定义控件中练习中出现的产物。通过游戏界面,很明显主要就是一个表格布局,主要的自定义控件主要是两个GamePanel 和Card。
MainActivity代码如下:
public class AndroidGameActivity extends Activity implements GamePanel.OnChangeListener {
private TextView mTvScore;
private TextView mTvBestScore;
private Button mBtnNewGame;
private GamePanel mGamePanel;
private ResultDialog mDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_game);
initViews();
initData();
}
private void initViews() {
mTvScore = (TextView) findViewById(R.id.tv_current_score);
mTvBestScore = (TextView) findViewById(R.id.tv_best_score);
mBtnNewGame = (Button) findViewById(R.id.btn_new_game);
mBtnNewGame.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startNewGame();
}
});
mGamePanel = (GamePanel) findViewById(R.id.game_panel);
mGamePanel.setOnChangeListener(this);
}
private void initData() {
startNewGame();
}
@Override
public void onBackPressed() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
return;
}
super.onBackPressed();
}
private void setCurrentScore(int score) {
mTvScore.setText("SCORE\n" + score);
}
private void setBestScore(int score) {
mTvBestScore.setText("BEST\n" + score);
}
private void startNewGame() {
setCurrentScore(0);
setBestScore(Config.getBestScore(this));
mGamePanel.restartGame();
}
@Override
public void onChange() {
setCurrentScore(mGamePanel.getScore());
}
@Override
public void onGameOver(boolean isSuccess) {
if (mDialog == null) {
mDialog = new ResultDialog(AndroidGameActivity.this, new ResultDialog.OnOkListener() {
@Override
public void onOk() {
startNewGame();
}
@Override
public void onCancel() {
finish();
}
});
}
if (isSuccess) {
mDialog.setMsg("游戏闯关成功", "是否再来一局?");
} else {
mDialog.setMsg("游戏闯关失败", "是否再来一局?");
}
mDialog.show();
}
}
Card代码如下:
public class Card extends View {
private Paint mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int bgColor;
private int bgCorner = 4;
private static final int smallTextSize = 30;
private int textSize = 50;
private int textColor;
private int widthSize;
private int number = 0;
public Card(Context context) {
super(context);
init();
}
public Card(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
widthSize = AppUtils.getCardSize(getContext());
bgColor = GameColor.getCardBgColor(number);
textColor = GameColor.getCardFontColor(number);
}
public void setNumber(int number) {
this.number = number;
invalidate();
}
public int getNumber() {
return number;
}
public void setDoubleNumber() {
number = number * 2;
if (number >= 1024) {
mTextPaint.setTextSize(smallTextSize);
}
invalidate();
}
@Override
public void invalidate() {
bgColor = GameColor.getCardBgColor(number);
textColor = GameColor.getCardFontColor(number);
super.invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthSize, widthSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 设置圆角背景
mBgPaint.setColor(bgColor);
RectF bgRect = new RectF(0, 0, widthSize, widthSize);
canvas.drawRoundRect(bgRect, bgCorner, bgCorner, mBgPaint);
// 绘制分数
if (number > 0) {
String num = String.valueOf(number);
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
int textWidth = (int) mTextPaint.measureText(num);
int x = widthSize / 2 - textWidth / 2;
int y = (int) (widthSize - Math.abs(metrics.descent) + Math.abs(metrics.ascent)) / 2;
canvas.drawText(String.valueOf(number), x, y, mTextPaint);
}
}
}
GamePanel代码如下:
public class GamePanel extends ViewGroup {
//列数
public static final int DEFAULT_COLUMN = 4;
// 行数
public static final int DEFAULT_ROW = 4;
private Card[][] mGroup;
private int score = 0;
private int viewSize;
private float lastX;
private float lastY;
private int touchSlop;
private ArrayList<Integer> indexs = new ArrayList<Integer>();
private ArrayList<Point> positions = new ArrayList<Point>();
private OnChangeListener mListener;
public GamePanel(Context context) {
super(context);
init();
}
public GamePanel(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
touchSlop = (int) (ViewConfiguration.get(getContext()).getScaledTouchSlop() * 1.2f);
viewSize = AppUtils.getPanelSize(getContext());
mGroup = new Card[DEFAULT_ROW][DEFAULT_COLUMN];
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
mGroup[i][j] = new Card(getContext());
positions.add(new Point(i, j));
addView(mGroup[i][j]);
}
}
score = 0;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
mGroup[i][j].measure(widthMeasureSpec, heightMeasureSpec);
}
}
setMeasuredDimension(viewSize, viewSize);
}
@Override
protected void onLayout(boolean changed,
int l, int t, int r, int b) {
if (changed) {
int padding = AppUtils.dip2px(getContext(), 10);
int size = AppUtils.getCardSize(getContext());
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
int left = padding + j * (padding + size);
int top = padding + i * (padding + size);
mGroup[i][j].layout(left, top, left + size, top + size);
}
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (indexs != null && indexs.size() > 0) {
indexs.clear();
}
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_UP:
float tempX = x - lastX;
float tempY = y - lastY;
if (Math.abs(tempX) >= touchSlop && Math.abs(tempX) > Math.abs(tempY)) {
if (tempX > 0) {
goRight();
} else {
goLeft();
}
} else if (Math.abs(tempY) >= touchSlop && Math.abs(tempY) > Math.abs(tempX)) {
if (tempY > 0) {
goBottom();
} else {
goTop();
}
}
lastX = 0;
lastY = 0;
break;
case MotionEvent.ACTION_CANCEL:
lastX = 0;
lastY = 0;
break;
}
return true;
}
public void restartGame() {
score = 0;
if (mGroup != null) {
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
mGroup[i][j].setNumber(0);
}
}
}
getRandomItem();
getRandomItem();
}
// 随机生成一个item
public void getRandomItem() {
if (GameScore.isGameSuccess(mGroup)) {
Config.saveBestScore(getContext(), score + Config.GAME_SUCCESS_EXTRA);
if (mListener != null) {
mListener.onGameOver(true);
}
return;
} else if (positions.size() == 0 && !GameScore.isGameMerge(mGroup)) {
Config.saveBestScore(getContext(), score);
if (mListener != null) {
mListener.onGameOver(false);
}
return;
}
Point p = getRandomPos();
if (p != null) {
LogUtils.e("随机生成的pos,x:" + p.x + "y:" + p.y);
if (mGroup[p.x][p.y].getNumber() == 0) {
mGroup[p.x][p.y].setNumber(2);
} else {
getRandomItem();
}
}
}
private void buildPositions() {
positions.clear();
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
if (mGroup[i][j].getNumber() == 0) {
positions.add(new Point(i, j));
}
}
}
}
private Point getRandomPos() {
if (positions.size() == 0) {
return null;
}
Random random = new Random();
int pos = random.nextInt(positions.size());
Point p = positions.remove(pos);
return p;
}
/**
* 继续生成下一个随机位置
*/
private void getNextRandom() {
if (mListener != null) {
mListener.onChange();
}
buildPositions();
getRandomItem();
}
private void addScore(int newNumber) {
score += GameScore.addGameScore(newNumber);
}
/**
* 向左滑动
*/
private void goLeft() {
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
Card cur = mGroup[i][j];
if (cur.getNumber() > 0) {
mergeLeft(i, j);
if (indexs != null && indexs.size() > 0) {
mGroup[i][indexs.get(0)].setNumber(cur.getNumber());
if (!mergeLeft(i, indexs.get(0) - 1)) {
mergeLeft(i, indexs.get(0));
}
cur.setNumber(0);
indexs.remove(0);
}
} else {
indexs.add(j);
}
}
if (indexs != null && indexs.size() > 0) {
indexs.clear();
}
}
getNextRandom();
}
private boolean mergeLeft(int i, int j) {
if (i >= 0 && i < DEFAULT_ROW && j >= 0 && j < DEFAULT_COLUMN) {
Card cur = mGroup[i][j];
if (j < DEFAULT_COLUMN - 1) {
Card next = mGroup[i][j + 1];
if (next.getNumber() == cur.getNumber()) {
cur.setDoubleNumber();
addScore(cur.getNumber());
next.setNumber(0);
return true;
}
}
}
return false;
}
/**
* 向上滑动
*/
private void goTop() {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
for (int i = 0; i < DEFAULT_ROW; i++) {
Card cur = mGroup[i][j];
if (cur.getNumber() > 0) {
mergeTop(i, j);
if (indexs != null && indexs.size() > 0) {
mGroup[indexs.get(0)][j].setNumber(cur.getNumber());
if (!mergeTop(indexs.get(0) - 1, j)) {
mergeTop(indexs.get(0), j);
}
cur.setNumber(0);
indexs.remove(0);
}
} else {
indexs.add(i);
}
}
if (indexs != null && indexs.size() > 0) {
indexs.clear();
}
}
getNextRandom();
}
private boolean mergeTop(int i, int j) {
if (i >= 0 && i < DEFAULT_ROW && j >= 0 && j < DEFAULT_COLUMN) {
Card cur = mGroup[i][j];
if (i < DEFAULT_ROW - 1) {
Card next = mGroup[i + 1][j];
if (next.getNumber() == cur.getNumber()) {
cur.setDoubleNumber();
addScore(cur.getNumber());
next.setNumber(0);
return true;
}
}
}
return false;
}
/**
* 向右滑动
*/
private void goRight() {
for (int i = 0; i < DEFAULT_ROW; i++) {
for (int j = DEFAULT_COLUMN - 1; j >= 0; j--) {
Card cur = mGroup[i][j];
if (cur.getNumber() > 0) {
mergeRight(i, j);
if (indexs != null && indexs.size() > 0) {
mGroup[i][indexs.get(0)].setNumber(cur.getNumber());
if (!mergeRight(i, indexs.get(0) + 1)) {
mergeRight(i, indexs.get(0));
}
cur.setNumber(0);
indexs.remove(0);
}
} else {
indexs.add(j);
}
}
if (indexs != null && indexs.size() > 0) {
indexs.clear();
}
}
getNextRandom();
}
private boolean mergeRight(int i, int j) {
if (i >= 0 && i < DEFAULT_ROW && j >= 0 && j < DEFAULT_COLUMN) {
Card cur = mGroup[i][j];
if (j > 0) {
Card last = mGroup[i][j - 1];
if (last.getNumber() == cur.getNumber()) {
cur.setDoubleNumber();
addScore(cur.getNumber());
last.setNumber(0);
return true;
}
}
}
return false;
}
/**
* 向下滑动
*/
private void goBottom() {
for (int j = 0; j < DEFAULT_COLUMN; j++) {
for (int i = DEFAULT_ROW - 1; i >= 0; i--) {
Card cur = mGroup[i][j];
if (cur.getNumber() > 0) {
mergeBottom(i, j);
if (indexs != null && indexs.size() > 0) {
mGroup[indexs.get(0)][j].setNumber(cur.getNumber());
if (!mergeBottom(indexs.get(0) + 1, j)) {
mergeBottom(indexs.get(0), j);
}
cur.setNumber(0);
indexs.remove(0);
}
} else {
indexs.add(i);
}
}
if (indexs != null && indexs.size() > 0) {
indexs.clear();
}
}
getNextRandom();
}
private boolean mergeBottom(int i, int j) {
if (i >= 0 && i < DEFAULT_ROW && j >= 0 && j < DEFAULT_COLUMN) {
Card cur = mGroup[i][j];
if (i > 0) {
Card last = mGroup[i - 1][j];
if (last.getNumber() == cur.getNumber()) {
cur.setDoubleNumber();
addScore(cur.getNumber());
last.setNumber(0);
return true;
}
}
}
return false;
}
public int getScore() {
return score;
}
public void setOnChangeListener(OnChangeListener l) {
mListener = l;
}
public interface OnChangeListener {
void onChange();
void onGameOver(boolean isSuccess);
}
}