I have to develop the ultimate esoteric 2048

Disclaimer: This article is a blogger original article, shall not be reproduced without the consent of bloggers. https://blog.csdn.net/x359981514/article/details/24582957

The tutorial before the interval with a lot of time Kazakhstan, a little forgotten recommend that you look at the front of the familiar, and today I am going to put this to the end of 2048, dragged on for so long.


By convention, we have the preparatory work has been done. Today, this part of the large amount of information, but also the core of the whole game, so I am prepared to function in terms of points. Finally, we look at the source code combination will not feel too hard.


1, initialization game

Initialization, we should be doing it, first of all depends on the configuration. Configuring a few lines, and then draw a good panel. Then give two randomly generated numbers Item on the panel. This involves two methods, a panel is initialized, a random number is added

private void initGameView(int cardSize) {
	removeAllViews();
	GameItem card;
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		card = new GameItem(getContext(), 0);
		addView(card, cardSize, cardSize);
		// 初始化GameMatrix所有为0 空格List为所有
		gameMatrix[i][j] = card;
		blanks.add(new Point(i, j));
	    }
	}
	// 加入随机数字
	addRandomNum();
	addRandomNum();
    }

private void addRandomNum() {
	getBlanks();
	if (blanks.size() > 0) {
	    int randomNum = (int) (Math.random() * blanks.size());
	    Point randomPoint = blanks.get(randomNum);
	    gameMatrix[randomPoint.x][randomPoint.y].setNum(Math.random() > 0.2d ? 2 : 4);
	    Game.getGameActivity().getAnimationLayer().animcreate(gameMatrix[randomPoint.x][randomPoint.y]);
	}
    }

2,4 inferring generated, we used the method generally random number generation range. Specifies the same time the proportion of 2 and 4 in 1: 4, of course, we can change based on need


2, the detailed initialization parameters

This relatively simple. Directly on the code. We should all be able to understand

private void initGameMatrix() {
	// 初始化矩阵
	removeAllViews();
	scoreHistory = 0;
	Config.Scroe = 0;
	Config.GameLines = Config.sp.getInt(Config.KEY_GameLines, 4);
	gameLines = Config.GameLines;
	gameMatrix = new GameItem[gameLines][gameLines];
	gameMatrixHistory = new int[gameLines][gameLines];
	calList = new ArrayList<Integer>();
	blanks = new ArrayList<Point>();
	highScore = Config.sp.getInt(Config.KEY_HighScore, 0);
	setColumnCount(gameLines);
	setRowCount(gameLines);
	setOnTouchListener(this);
	// 初始化View參数
	DisplayMetrics metrics = new DisplayMetrics();
	WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
	Display display = wm.getDefaultDisplay();
	display.getMetrics(metrics);
	Config.ItemSize = metrics.widthPixels / Config.GameLines;
	initGameView(Config.ItemSize);
    }

This part might look better in conjunction with the source code, clear gaze


3, the touch event

Touch when inferring four directions, this is basic common wording, not much to say

public boolean onTouch(View v, MotionEvent event) {
	switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN:
	    saveHistoryMatrix();
	    startX = (int) event.getX();
	    startY = (int) event.getY();
	    break;
	case MotionEvent.ACTION_MOVE:
	    break;
	case MotionEvent.ACTION_UP:
	    endX = (int) event.getX();
	    endY = (int) event.getY();
	    judgeDirection(endX - startX, endY - startY);
	    if (isMoved()) {
		addRandomNum();
		// 改动显示分数
		Game.getGameActivity().setScore(Config.Scroe, 0);
	    }
	    int result = checkCompleted();
	    if (result == 0) {
		if (Config.Scroe > highScore) {
		    Editor editor = Config.sp.edit();
		    editor.putInt(Config.KEY_HighScore, Config.Scroe);
		    editor.commit();
		}
		Toast.makeText(getContext(), "lose", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    } else if (result == 2) {
		Toast.makeText(getContext(), "success", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    }
	    break;
	default:
	    break;
	}
	return true;
    }
Among offset estimation method

private void judgeDirection(int offsetX, int offsetY) {
	if (Math.abs(offsetX) > Math.abs(offsetY)) {
	    if (offsetX > 10) {
		swipeRight();
	    } else {
		swipeLeft();
	    }
	} else {
	    if (offsetY > 10) {
		swipeDown();
	    } else {
		swipeUp();
	    }
	}
    }

The following us, 2048 is the ultimate esoteric. Is the implementation of the algorithm, detailed algorithm has been explained in the first article about the process. I see the point . Below we choose a direction in terms of how to achieve

private void swipeLeft() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		int currentNum = gameMatrix[i][j].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < calList.size(); j++) {
		gameMatrix[i][j].setNum(calList.get(j));
	    }
	    for (int m = calList.size(); m < gameLines; m++) {
		gameMatrix[i][m].setNum(0);
	    }
	    // 重置行參数
	    keyItemNum = -1;
	    calList.clear();
	}
    }

overall; in summary. Is to select a reference, one by one comparison, another arrangement

The code is very clear. We look to know. The key is how to sum up the algorithm.


4, the following is inferred when the game needs to join a new digital Item

When the structure of the current digital matrix domain of the last occurrence of a difference, we have to add a new Item of digital

private boolean isMoved() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrixHistory[i][j] != gameMatrix[i][j].getNum()) {
		    return true;
		}
	    }
	}
	return false;
    }

This place we used a matrix to a history of the stored digital matrix


5, the last is how to infer an end

Item currently assume there is a space, it will definitely not over, if the adjacent figures are not the same number, the inevitable end, if Goal configuration occurs, win

private int checkCompleted() {
	getBlanks();
	if (blanks.size() == 0) {
	    for (int i = 0; i < gameLines; i++) {
		for (int j = 0; j < gameLines; j++) {
		    if (j < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i][j + 1].getNum()) {
			    return 1;
			}
		    }
		    if (i < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i + 1][j].getNum()) {
			    return 1;
			}
		    }
		}
	    }
	    return 0;
	}
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrix[i][j].getNum() == 2048) {
		    return 2;
		}
	    }
	}
	return 1;
    }

Some finally released the following picture:



Because just changed jobs, commuting time doubled, so the less time writing code, in fact, about the game I have not done very much the idea. This version of 2048, compared with the version number of the Internet, more undo the last move function. More ability to customize the function of the dimension of the game, more than the ability to configure the target of 2048, I was very low configuration requirements of the version number, the version number is compared to cocos2dx, greatly reducing the power consumption, configurable stronger. These are in the course of my playing. Think unhappy place, then improved. Some other ideas. Right now not to do it. Usually work to do the android framework, and application layer will study a little, and I hope that we can improve the code. Make better 2048.

1, adding debug function, also known as cheating the back door, I had wanted to, how much distance when the finger sliding over, a new method call. Under Settings adding the position and size of random numbers, I now use this code is very well implemented, should only change addRandom method, write a debugRandom method is OK

2, sharing. The use ShareSdk on it, play games Well, that was fun to play with everyone. Not without social game

3, the replacement of 2,4,8,16 ...... digital background. This online very much. We can also define your own set of background, Item of this implementation is relatively simple, just put this class inside GameItem background to join a set method to ok

the above. end

Hereinafter, the code brush

package com.xys.game2048.view;

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

import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.GridLayout;
import android.widget.Toast;

import com.xys.game2048.activity.Game;
import com.xys.game2048.bean.GameItem;
import com.xys.game2048.config.Config;

public class GameView extends GridLayout implements OnTouchListener {

    // GameView相应矩阵
    private GameItem[][] gameMatrix;
    // 空格List
    private List<Point> blanks;
    // 矩阵行列数
    private int gameLines;
    // 记录坐标
    private int startX, startY, endX, endY;
    // 辅助数组
    private List<Integer> calList;
    private int keyItemNum = -1;
    // 历史记录数组
    private int[][] gameMatrixHistory;
    // 历史记录分数
    private int scoreHistory;
    // 最高记录
    private int highScore;

    public GameView(Context context) {
	super(context);
	initGameMatrix();
    }

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

    public void startGame() {
	initGameMatrix();
	initGameView(Config.ItemSize);
    }

    private void initGameView(int cardSize) {
	removeAllViews();
	GameItem card;
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		card = new GameItem(getContext(), 0);
		addView(card, cardSize, cardSize);
		// 初始化GameMatrix所有为0 空格List为所有
		gameMatrix[i][j] = card;
		blanks.add(new Point(i, j));
	    }
	}
	// 加入随机数字
	addRandomNum();
	addRandomNum();
    }

    /**
     * 撤销上次移动
     */
    public void revertGame() {
	if (gameMatrixHistory.length != 0) {
	    Game.getGameActivity().setScore(scoreHistory, 0);
	    Config.Scroe = scoreHistory;
	    for (int i = 0; i < gameLines; i++) {
		for (int j = 0; j < gameLines; j++) {
		    gameMatrix[i][j].setNum(gameMatrixHistory[i][j]);
		}
	    }
	}
    }

    /**
     * 加入随机数字
     */
    private void addRandomNum() {
	getBlanks();
	if (blanks.size() > 0) {
	    int randomNum = (int) (Math.random() * blanks.size());
	    Point randomPoint = blanks.get(randomNum);
	    gameMatrix[randomPoint.x][randomPoint.y].setNum(Math.random() > 0.2d ?

2 : 4); Game.getGameActivity().getAnimationLayer().animcreate(gameMatrix[randomPoint.x][randomPoint.y]); } } /** * 获取空格Item数组 */ private void getBlanks() { blanks.clear(); for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { if (gameMatrix[i][j].getNum() == 0) { blanks.add(new Point(i, j)); } } } } /** * 初始化View */ private void initGameMatrix() { // 初始化矩阵 removeAllViews(); scoreHistory = 0; Config.Scroe = 0; Config.GameLines = Config.sp.getInt(Config.KEY_GameLines, 4); gameLines = Config.GameLines; gameMatrix = new GameItem[gameLines][gameLines]; gameMatrixHistory = new int[gameLines][gameLines]; calList = new ArrayList<Integer>(); blanks = new ArrayList<Point>(); highScore = Config.sp.getInt(Config.KEY_HighScore, 0); setColumnCount(gameLines); setRowCount(gameLines); setOnTouchListener(this); // 初始化View參数 DisplayMetrics metrics = new DisplayMetrics(); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); display.getMetrics(metrics); Config.ItemSize = metrics.widthPixels / Config.GameLines; initGameView(Config.ItemSize); } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: saveHistoryMatrix(); startX = (int) event.getX(); startY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: endX = (int) event.getX(); endY = (int) event.getY(); judgeDirection(endX - startX, endY - startY); if (isMoved()) { addRandomNum(); // 改动显示分数 Game.getGameActivity().setScore(Config.Scroe, 0); } int result = checkCompleted(); if (result == 0) { if (Config.Scroe > highScore) { Editor editor = Config.sp.edit(); editor.putInt(Config.KEY_HighScore, Config.Scroe); editor.commit(); } Toast.makeText(getContext(), "lose", Toast.LENGTH_LONG).show(); Config.Scroe = 0; } else if (result == 2) { Toast.makeText(getContext(), "success", Toast.LENGTH_LONG).show(); Config.Scroe = 0; } break; default: break; } return true; } /** * 保存历史记录 */ private void saveHistoryMatrix() { scoreHistory = Config.Scroe; for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { gameMatrixHistory[i][j] = gameMatrix[i][j].getNum(); } } } /** * 依据偏移量推断移动方向 * * @param offsetX * @param offsetY */ private void judgeDirection(int offsetX, int offsetY) { if (Math.abs(offsetX) > Math.abs(offsetY)) { if (offsetX > 10) { swipeRight(); } else { swipeLeft(); } } else { if (offsetY > 10) { swipeDown(); } else { swipeUp(); } } } /** * 推断是否结束 * * @return 0:结束 1:正常 2:成功 */ private int checkCompleted() { getBlanks(); if (blanks.size() == 0) { for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { if (j < gameLines - 1) { if (gameMatrix[i][j].getNum() == gameMatrix[i][j + 1].getNum()) { return 1; } } if (i < gameLines - 1) { if (gameMatrix[i][j].getNum() == gameMatrix[i + 1][j].getNum()) { return 1; } } } } return 0; } for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { if (gameMatrix[i][j].getNum() == 2048) { return 2; } } } return 1; } /** * 推断是否移动过(是否须要新增Item) * * @return */ private boolean isMoved() { for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { if (gameMatrixHistory[i][j] != gameMatrix[i][j].getNum()) { return true; } } } return false; } /** * 滑动事件:上 */ private void swipeUp() { for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { int currentNum = gameMatrix[j][i].getNum(); if (currentNum != 0) { if (keyItemNum == -1) { keyItemNum = currentNum; } else { if (keyItemNum == currentNum) { calList.add(keyItemNum * 2); Config.Scroe += keyItemNum * 2; keyItemNum = -1; } else { calList.add(keyItemNum); keyItemNum = currentNum; } } } else { continue; } } if (keyItemNum != -1) { calList.add(keyItemNum); } // 改变Item值 for (int j = 0; j < calList.size(); j++) { gameMatrix[j][i].setNum(calList.get(j)); } for (int m = calList.size(); m < gameLines; m++) { gameMatrix[m][i].setNum(0); } // 重置行參数 keyItemNum = -1; calList.clear(); } } /** * 滑动事件:下 */ private void swipeDown() { for (int i = gameLines - 1; i >= 0; i--) { for (int j = gameLines - 1; j >= 0; j--) { int currentNum = gameMatrix[j][i].getNum(); if (currentNum != 0) { if (keyItemNum == -1) { keyItemNum = currentNum; } else { if (keyItemNum == currentNum) { calList.add(keyItemNum * 2); Config.Scroe += keyItemNum * 2; keyItemNum = -1; } else { calList.add(keyItemNum); keyItemNum = currentNum; } } } else { continue; } } if (keyItemNum != -1) { calList.add(keyItemNum); } // 改变Item值 for (int j = 0; j < gameLines - calList.size(); j++) { gameMatrix[j][i].setNum(0); } int index = calList.size() - 1; for (int m = gameLines - calList.size(); m < gameLines; m++) { gameMatrix[m][i].setNum(calList.get(index)); index--; } // 重置行參数 keyItemNum = -1; calList.clear(); index = 0; } } /** * 滑动事件:左 */ private void swipeLeft() { for (int i = 0; i < gameLines; i++) { for (int j = 0; j < gameLines; j++) { int currentNum = gameMatrix[i][j].getNum(); if (currentNum != 0) { if (keyItemNum == -1) { keyItemNum = currentNum; } else { if (keyItemNum == currentNum) { calList.add(keyItemNum * 2); Config.Scroe += keyItemNum * 2; keyItemNum = -1; } else { calList.add(keyItemNum); keyItemNum = currentNum; } } } else { continue; } } if (keyItemNum != -1) { calList.add(keyItemNum); } // 改变Item值 for (int j = 0; j < calList.size(); j++) { gameMatrix[i][j].setNum(calList.get(j)); } for (int m = calList.size(); m < gameLines; m++) { gameMatrix[i][m].setNum(0); } // 重置行參数 keyItemNum = -1; calList.clear(); } } /** * 滑动事件:右 */ private void swipeRight() { for (int i = gameLines - 1; i >= 0; i--) { for (int j = gameLines - 1; j >= 0; j--) { int currentNum = gameMatrix[i][j].getNum(); if (currentNum != 0) { if (keyItemNum == -1) { keyItemNum = currentNum; } else { if (keyItemNum == currentNum) { calList.add(keyItemNum * 2); Config.Scroe += keyItemNum * 2; keyItemNum = -1; } else { calList.add(keyItemNum); keyItemNum = currentNum; } } } else { continue; } } if (keyItemNum != -1) { calList.add(keyItemNum); } // 改变Item值 for (int j = 0; j < gameLines - calList.size(); j++) { gameMatrix[i][j].setNum(0); } int index = calList.size() - 1; for (int m = gameLines - calList.size(); m < gameLines; m++) { gameMatrix[i][m].setNum(calList.get(index)); index--; } // 重置行參数 keyItemNum = -1; calList.clear(); index = 0; } } }




PS please leave a message needs to source code


PS please leave a message needs to source code

Guess you like

Origin www.cnblogs.com/ldxsuanfa/p/10959859.html