Android实例——2048游戏

news2024/12/23 8:46:54

2048游戏

  • 项目简介
  • Config
  • Constants
  • GameActivity
  • GameItem
  • GameView
  • MainActivity
  • ScreenUtils
  • 布局
    • activity_game.xml
    • activity_main.xml

项目简介

选择难度,生成随机数字,通关上下左右滑动,合并相同的数字,直到达到目标数字即可通关游戏,选择界面如下

在这里插入图片描述

游戏界面如下

在这里插入图片描述

项目结构如下

在这里插入图片描述

Config

public class Config extends Application {

    private static SharedPreferences mSp;

    @Override
    public void onCreate() {
        super.onCreate();
        mSp = getSharedPreferences(Constants.SP_GAME, MODE_PRIVATE);
    }

    public int getTargetScore() {
        return mSp.getInt(Constants.KEY_Target_Score, Score.Score2048.getValue());
    }

    public void setTargetScore(int targetScore) {
        SharedPreferences.Editor editor = mSp.edit();
        editor.putInt(Constants.KEY_Target_Score, targetScore);
        editor.apply();
    }

    public int getGameLines() {
        return mSp.getInt(Constants.KEY_GAME_LINES, GameLines.GameLines4.getValue());
    }

    public void setGameLines(int gameLines) {
        SharedPreferences.Editor editor = mSp.edit();
        editor.putInt(Constants.KEY_GAME_LINES, gameLines);
        editor.apply();
    }

    public int getHighestScore() {
        return mSp.getInt(Constants.KEY_HIGHEST_SCORE, 0);
    }

    public void setHighestScore(int highestScore) {
        SharedPreferences.Editor editor = mSp.edit();
        editor.putInt(Constants.KEY_HIGHEST_SCORE, highestScore);
        editor.apply();
    }
}

Constants

public class Constants {
    public static final String PARA_GAME_LINES = "para_game_lines";
    public static final String PARA_TARGET_SCORE = "para_target_score";


    public static final String SP_GAME = "sp_game";
    public static final String KEY_HIGHEST_SCORE = "key_highest_score";
    public static final String KEY_GAME_LINES = "key_game_lines";
    public static final String KEY_Target_Score = "key_target_score";


    public static final GameLines DEFAULT_GAME_LINES = GameLines.GameLines4;
    public static final Score DEFAULT_SCORE = Score.Score2048;

    public enum GameLines {
        GameLines4(4), GameLines5(5);

        private int value;

        GameLines(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public enum Score {
        Score2048(2048), Score4049(4096);

        private int value;

        Score(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public enum STATE {
        FAILED, NORMAL, SUCCESS
    }
}

GameActivity

public class GameActivity extends AppCompatActivity implements View.OnClickListener, GameView.GameCallBack {

    private TextView mCurrentScore;
    private TextView mHighestScore;
    private TextView mTargetScore;
    private Button mRevert;
    private Button mRestart;
    private GameView mGame;
    private Config mConfig;
    private boolean isRevert = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);
        initView();
        initData();
    }

    private void initView() {
        mCurrentScore = findViewById(R.id.current_score);
        mHighestScore = findViewById(R.id.highest_score);
        mTargetScore = findViewById(R.id.target_score);
        mRevert = findViewById(R.id.revert);
        mRestart = findViewById(R.id.restart);
        mGame = findViewById(R.id.game);
    }

    private void initData() {
        mConfig = new Config();
        mRevert.setOnClickListener(this);
        mRestart.setOnClickListener(this);
        mGame.setOnGameCallBack(this);

        mCurrentScore.setText("当前分数: " + 0);
        mHighestScore.setText("最高分数: " + mConfig.getHighestScore());
        mTargetScore.setText("目标分数: " + mConfig.getTargetScore());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.revert:
                if (isRevert) {
                    mGame.revertGame();
                    isRevert = false;
                } else {
                    Toast.makeText(this, "只能撤销一次", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.restart:
                mGame.restartGame();
                break;
        }
    }

    @Override
    public void onScoreChange(int currentScore) {
        mCurrentScore.setText("当前分数: " + currentScore);
        mHighestScore.setText("最高分数: " + mConfig.getHighestScore());
    }

    @Override
    public void onCheckGameFinish(Constants.STATE state) {
        switch (state) {
            case SUCCESS:
                showFinishDialog("成功通关");
                break;
            case FAILED:
                showFinishDialog("挑战失败");
                break;
            case NORMAL:
                break;
        }
    }

    @Override
    public void onOpenRevert() {
        isRevert = true;
    }

    private void showFinishDialog(String msg) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(msg);
        builder.setCancelable(false);
        builder.setNegativeButton("再来一次", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mGame.restartGame();
                dialog.dismiss();
            }
        });
        builder.setPositiveButton("退出游戏", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                finish();
            }
        });
        builder.show();
    }
}

GameItem

public class GameItem extends FrameLayout {
    private int mNum;
    private TextView mNumCard;
    private LayoutParams mParams;
    private Config mConfig;

    public GameItem(@NonNull Context context) {
        this(context, null);
    }

    public GameItem(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GameItem(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public GameItem(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initCardItem();
    }

    private void initCardItem() {
        mConfig = new Config();
        setBackgroundColor(Color.GRAY);
        mNumCard = new TextView(getContext());
        switch (mConfig.getGameLines()) {
            case 4:
                mNumCard.setTextSize(35);
                break;
            case 5:
                mNumCard.setTextSize(25);
                break;
            default:
                mNumCard.setTextSize(20);
                break;
        }
        TextPaint tp = mNumCard.getPaint();
        tp.setFakeBoldText(true);
        mNumCard.setGravity(Gravity.CENTER);
        mParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mParams.setMargins(5, 5, 5, 5);
        addView(mNumCard, mParams);
    }

    public void setNum(int num) {
        this.mNum = num;
        if (num == 0) {
            mNumCard.setText("");
        } else {
            mNumCard.setText(String.valueOf(num));
        }
        switch (num) {
            case 0:
                mNumCard.setBackgroundColor(0x00000000);
                break;
            case 2:
                mNumCard.setBackgroundColor(0xffeee5db);
                break;
            case 4:
                mNumCard.setBackgroundColor(0xffeee0ca);
                break;
            case 8:
                mNumCard.setBackgroundColor(0xfff2c17a);
                break;
            case 16:
                mNumCard.setBackgroundColor(0xfff59667);
                break;
            case 32:
                mNumCard.setBackgroundColor(0xfff38c6f);
                break;
            case 64:
                mNumCard.setBackgroundColor(0xfff66e3c);
                break;
            case 128:
                mNumCard.setBackgroundColor(0xffedcf74);
                break;
            case 256:
                mNumCard.setBackgroundColor(0xffedcc64);
                break;
            case 512:
                mNumCard.setBackgroundColor(0xffedc854);
                break;
            case 1024:
                mNumCard.setBackgroundColor(0xffedc54f);
                break;
            case 2048:
                mNumCard.setBackgroundColor(0xffedc32e);
                break;
            default:
                mNumCard.setBackgroundColor(0xff3c4a34);
                break;
        }
    }

    public int getNum() {
        return mNum;
    }
}

GameView

public class GameView extends GridLayout implements View.OnTouchListener {

    private static final String TAG = "GameView";
    private int mHistoryScore;
    private int mCurrentScore;
    private int mGameLines;
    private GameItem[][] mGameMatrix;
    private int[][] mGameMatrixHistory;
    private ArrayList<Point> mBlankItem;
    private int mStartX;
    private int mStartY;
    private int mEndX;
    private int mEndY;
    private int mTargetScore;
    private Config mConfig;
    private GameCallBack mCallBack;
    private int mHistoryHighestScore;

    public GameView(Context context) {
        this(context, null);
    }

    public GameView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initConfig();
        initView();
        initData();
        initGame();
    }

    private void initConfig() {
        mConfig = new Config();
        mGameLines = mConfig.getGameLines();
        mTargetScore = mConfig.getTargetScore();

        Log.d(TAG, "initConfig: mGameLines = " + mGameLines);
        Log.d(TAG, "initConfig: mTargetScore = " + mTargetScore);
    }

    private void initView() {
        removeAllViews();
        setColumnCount(mGameLines);
        setRowCount(mGameLines);
        setOnTouchListener(this);
    }

    private void initData() {
        mGameMatrix = new GameItem[mGameLines][mGameLines];
        mGameMatrixHistory = new int[mGameLines][mGameLines];
        mBlankItem = new ArrayList<Point>();
    }

    private void initGame() {
        GameItem item;
        for (int i = 0; i < mGameLines; i++) {
            for (int j = 0; j < mGameLines; j++) {
                item = new GameItem(getContext());
                item.setNum(0);
                addView(item, ScreenUtils.getScreenWidthPixels(getContext()) / mGameLines, ScreenUtils.getScreenWidthPixels(getContext()) / mGameLines);
                mGameMatrix[i][j] = item;
                mBlankItem.add(new Point(i, j));
            }
        }
        addRandomNum();
        addRandomNum();
        updateScore();
    }

    private void addRandomNum() {
        getBlanks();
        if (mBlankItem.size() > 0) {
            int randomNum = (int) (Math.random() * mBlankItem.size());
            Point randomPoint = mBlankItem.get(randomNum);
            mGameMatrix[randomPoint.x][randomPoint.y].setNum(Math.random() > 0.2d ? 2 : 4);
            animCreate(mGameMatrix[randomPoint.x][randomPoint.y]);
        }
    }

    private void addSuperNum(int superNum) {
        getBlanks();
        if (mBlankItem.size() > 0) {
            int randomNum = (int) (Math.random() * mBlankItem.size());
            Point randomPoint = mBlankItem.get(randomNum);
            mGameMatrix[randomPoint.x][randomPoint.y].setNum(superNum);
            animCreate(mGameMatrix[randomPoint.x][randomPoint.y]);
        }
    }

    private void animCreate(GameItem item) {
        ScaleAnimation sa = new ScaleAnimation(0.1f, 1, 0.1f, 1,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        sa.setDuration(100);
        item.startAnimation(sa);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.d(TAG, "onTouch: ");
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartX = (int) event.getX();
                mStartY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                mEndX = (int) event.getX();
                mEndY = (int) event.getY();
                Log.d(TAG, "onTouch: start = (" + mStartX + "," + mStartY + ")");
                Log.d(TAG, "onTouch: end = (" + mEndX + "," + mEndY + ")");
                judgeDirection(mEndX - mStartX, mEndY - mStartY);
                if (isMoved()) {
                    updateScore();
                }
                break;
            default:
                break;
        }
        return true;
    }

    private void updateScore() {
        for (GameItem[] gameMatrix : mGameMatrix) {
            for (GameItem matrix : gameMatrix) {
                if (matrix.getNum() > mCurrentScore) {
                    mCurrentScore = matrix.getNum();
                }
            }
        }
        if (mCurrentScore > mConfig.getHighestScore()) {
            mConfig.setHighestScore(mCurrentScore);
        }
        if (mCallBack != null) {
            mCallBack.onOpenRevert();
            mCallBack.onScoreChange(mCurrentScore);
            mCallBack.onCheckGameFinish(checkCompleted());
        }
    }

    private void judgeDirection(int offsetX, int offsetY) {
        Log.d(TAG, "judgeDirection: offsetX = " + offsetX);
        Log.d(TAG, "judgeDirection: offsetY = " + offsetY);
        int density = ScreenUtils.getScreenMetrics(getContext());
        int slideDis = 5 * density;
        int maxDis = ScreenUtils.getScreenWidthPixels(getContext()) - 50;
        Log.d(TAG, "judgeDirection: slideDis = " + slideDis);
        Log.d(TAG, "judgeDirection: maxDis = " + maxDis);
        boolean flagNormal = (Math.abs(offsetX) > slideDis || Math.abs(offsetY) > slideDis)
                && Math.abs(offsetX) < maxDis
                && Math.abs(offsetY) < maxDis;
        boolean flagSuper = Math.abs(offsetX) > maxDis || Math.abs(offsetY) > maxDis;
        Log.d(TAG, "judgeDirection: flagNormal = " + flagNormal);
        Log.d(TAG, "judgeDirection: flagSuper = " + flagSuper);
        if (flagNormal || flagSuper) {
            saveHistoryMatrix();
        }
        if (flagNormal && !flagSuper) {
            if (Math.abs(offsetX) > Math.abs(offsetY)) {
                if (offsetX > slideDis) {
                    swipeRight();
                } else {
                    swipeLeft();
                }
            } else {
                if (offsetY > slideDis) {
                    swipeDown();
                } else {
                    swipeUp();
                }
            }
            addRandomNum();
        } else if (flagSuper) {
            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            EditText et = new EditText(getContext());
            builder.setTitle("Back Door")
                    .setView(et)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (!TextUtils.isEmpty(et.getText())) {
                                addSuperNum(Integer.parseInt(et.getText().toString()));
                                if (mCallBack != null) {
                                    mCallBack.onCheckGameFinish(checkCompleted());
                                }
                            }
                        }
                    })
                    .setNegativeButton("ByeBye", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).create().show();
        }
    }

    private void swipeLeft() {
        for (int i = 0; i < mGameLines; i++) {
            int baseNum = -1;
            List<Integer> tempList = new ArrayList<>();
            for (int j = 0; j < mGameLines; j++) {
                int currentNum = mGameMatrix[i][j].getNum();
                if (currentNum != 0) {
                    if (baseNum == -1) {    //选取第一个非0数字作为基准
                        baseNum = currentNum;
                        continue;
                    }
                    if (baseNum == currentNum) {    //如果当前数字等于前一个数字,则合并
                        tempList.add(baseNum * 2);
                        baseNum = -1;
                    } else {    //如果当前数字不等于前一个数字,则基准数字后移
                        tempList.add(baseNum);
                        baseNum = currentNum;
                    }
                }
            }
            if (baseNum != -1) {
                tempList.add(baseNum);
            }
            for (int j = 0; j < mGameLines; j++) {
                if (j < tempList.size()) {
                    mGameMatrix[i][j].setNum(tempList.get(j));
                } else {
                    mGameMatrix[i][j].setNum(0);
                }
            }
        }
    }

    private void swipeRight() {
        for (int i = 0; i < mGameLines; i++) {
            int baseNum = -1;
            List<Integer> tempList = new ArrayList<>();
            for (int j = mGameLines - 1; j >= 0; j--) {
                int currentNum = mGameMatrix[i][j].getNum();
                if (currentNum != 0) {
                    if (baseNum == -1) {    //选取第一个非0数字作为基准
                        baseNum = currentNum;
                        continue;
                    }
                    if (baseNum == currentNum) {    //如果当前数字等于前一个数字,则合并
                        tempList.add(baseNum * 2);
                        baseNum = -1;
                    } else {    //如果当前数字不等于前一个数字,则基准数字后移
                        tempList.add(baseNum);
                        baseNum = currentNum;
                    }
                }
            }
            if (baseNum != -1) {
                tempList.add(baseNum);
            }
            for (int j = 0; j < mGameLines; j++) {
                if (j < tempList.size()) {
                    mGameMatrix[i][mGameLines - 1 - j].setNum(tempList.get(j));
                } else {
                    mGameMatrix[i][mGameLines - 1 - j].setNum(0);
                }
            }
        }
    }

    private void swipeDown() {
        for (int i = 0; i < mGameLines; i++) {
            int baseNum = -1;
            List<Integer> tempList = new ArrayList<>();
            for (int j = mGameLines - 1; j >= 0; j--) {
                int currentNum = mGameMatrix[j][i].getNum();
                if (currentNum != 0) {
                    if (baseNum == -1) {    //选取第一个非0数字作为基准
                        baseNum = currentNum;
                        continue;
                    }
                    if (baseNum == currentNum) {    //如果当前数字等于前一个数字,则合并
                        tempList.add(baseNum * 2);
                        baseNum = -1;
                    } else {    //如果当前数字不等于前一个数字,则基准数字后移
                        tempList.add(baseNum);
                        baseNum = currentNum;
                    }
                }
            }
            if (baseNum != -1) {
                tempList.add(baseNum);
            }
            for (int j = 0; j < mGameLines; j++) {
                if (j < tempList.size()) {
                    mGameMatrix[mGameLines - 1 - j][i].setNum(tempList.get(j));
                } else {
                    mGameMatrix[mGameLines - 1 - j][i].setNum(0);
                }
            }
        }
    }

    private void swipeUp() {
        for (int i = 0; i < mGameLines; i++) {
            int baseNum = -1;
            List<Integer> tempList = new ArrayList<>();
            for (int j = 0; j < mGameLines; j++) {
                int currentNum = mGameMatrix[j][i].getNum();
                if (currentNum != 0) {
                    if (baseNum == -1) {    //选取第一个非0数字作为基准
                        baseNum = currentNum;
                        continue;
                    }
                    if (baseNum == currentNum) {    //如果当前数字等于前一个数字,则合并
                        tempList.add(baseNum * 2);
                        baseNum = -1;
                    } else {    //如果当前数字不等于前一个数字,则基准数字后移
                        tempList.add(baseNum);
                        baseNum = currentNum;
                    }
                }
            }
            if (baseNum != -1) {
                tempList.add(baseNum);
            }
            for (int j = 0; j < mGameLines; j++) {
                if (j < tempList.size()) {
                    mGameMatrix[j][i].setNum(tempList.get(j));
                } else {
                    mGameMatrix[j][i].setNum(0);
                }
            }
        }
    }

    private void saveHistoryMatrix() {
        mHistoryScore = mCurrentScore;
        mHistoryHighestScore = mConfig.getHighestScore();
        for (int i = 0; i < mGameLines; i++) {
            for (int j = 0; j < mGameLines; j++) {
                mGameMatrixHistory[i][j] = mGameMatrix[i][j].getNum();
            }
        }
    }

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

    public void revertGame() {
        int sum = 0;
        for (int[] element : mGameMatrixHistory) {
            for (int i : element) {
                sum += i;
            }
        }
        if (sum != 0) {
            mCurrentScore = mHistoryScore;
            mConfig.setHighestScore(mHistoryHighestScore);
            if (mCallBack != null) {
                mCallBack.onScoreChange(mCurrentScore);
            }
            for (int i = 0; i < mGameLines; i++) {
                for (int j = 0; j < mGameLines; j++) {
                    mGameMatrix[i][j].setNum(mGameMatrixHistory[i][j]);
                }
            }
        }
    }

    public void restartGame() {
        removeAllViews();
        mCurrentScore = 0;
        mHistoryScore = 0;
        for (int i = 0; i < mGameMatrixHistory.length; i++) {
            for (int j = 0; j < mGameMatrixHistory.length; j++) {
                mGameMatrixHistory[i][j] = 0;
            }
        }
        mBlankItem.clear();
        initGame();
    }

    private void getBlanks() {
        mBlankItem.clear();
        for (int i = 0; i < mGameLines; i++) {
            for (int j = 0; j < mGameLines; j++) {
                if (mGameMatrix[i][j].getNum() == 0) {
                    mBlankItem.add(new Point(i, j));
                }
            }
        }
    }

    private STATE checkCompleted() {
        for (int i = 0; i < mGameLines; i++) {
            for (int j = 0; j < mGameLines; j++) {
                if (mGameMatrix[i][j].getNum() == mTargetScore) {
                    return STATE.SUCCESS;
                }
            }
        }
        getBlanks();
        if (mBlankItem.size() == 0) {
            for (int i = 0; i < mGameLines; i++) {
                for (int j = 0; j < mGameLines; j++) {
                    if (j < mGameLines - 1) {
                        if (mGameMatrix[i][j].getNum() == mGameMatrix[i][j + 1].getNum()) {
                            return STATE.NORMAL;
                        }
                    }
                    if (i < mGameLines - 1) {
                        if (mGameMatrix[i][j].getNum() == mGameMatrix[i + 1][j].getNum()) {
                            return STATE.NORMAL;
                        }
                    }
                }
            }
            return STATE.FAILED;
        }
        return STATE.NORMAL;
    }

    public interface GameCallBack {
        void onScoreChange(int currentScore);

        void onCheckGameFinish(STATE state);

        void onOpenRevert();
    }

    public void setOnGameCallBack(GameCallBack callBack) {
        mCallBack = callBack;
    }
}

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView mRegionSelector;
    private TextView mTargetScoreSelector;
    private TextView mBack;
    private TextView mStartGame;

    private GameLines mGameLines = Constants.DEFAULT_GAME_LINES;
    private Score mTargetScore = Constants.DEFAULT_SCORE;
    private Config mConfig;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initListener();
    }

    private void initView() {
        mRegionSelector = findViewById(R.id.game_lines_selector);
        mTargetScoreSelector = findViewById(R.id.target_score_selector);
        mBack = findViewById(R.id.back);
        mStartGame = findViewById(R.id.startGame);
    }

    private void initData() {
        mConfig = new Config();
        mRegionSelector.setText(mGameLines.getValue() + " × " + mGameLines.getValue());
        mTargetScoreSelector.setText(String.valueOf(mTargetScore.getValue()));
    }

    private void initListener() {
        mRegionSelector.setOnClickListener(this);
        mTargetScoreSelector.setOnClickListener(this);
        mBack.setOnClickListener(this);
        mStartGame.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.game_lines_selector:
                if (mGameLines == GameLines.GameLines4) {
                    mGameLines = GameLines.GameLines5;
                } else if (mGameLines == GameLines.GameLines5) {
                    mGameLines = GameLines.GameLines4;
                }
                mRegionSelector.setText(mGameLines.getValue() + " × " + mGameLines.getValue());
                break;
            case R.id.target_score_selector:
                if (mTargetScore == Score.Score2048) {
                    mTargetScore = Score.Score4049;
                } else if (mTargetScore == Score.Score4049) {
                    mTargetScore = Score.Score2048;
                }
                mTargetScoreSelector.setText(String.valueOf(mTargetScore.getValue()));
                break;
            case R.id.back:
                finish();
                break;
            case R.id.startGame:
                //GameActivity.startGameActivity(this, mGameLines.getValue(), mTargetScore.getValue());
                mConfig.setGameLines(mGameLines.getValue());
                mConfig.setTargetScore(mTargetScore.getValue());
                mConfig.setHighestScore(0);
                startActivity(new Intent(this, GameActivity.class));
                break;
        }
    }
}

ScreenUtils

public class ScreenUtils {
    public static DisplayMetrics getDisplayMetrics(Context context) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        display.getMetrics(metrics);
        return metrics;
    }

    public static int getScreenMetrics(Context context) {
        return (int) getDisplayMetrics(context).density;
    }

    public static int getScreenWidthPixels(Context context) {
        return getDisplayMetrics(context).widthPixels;
    }

    public static int getScreenHeightPixels(Context context) {
        return getDisplayMetrics(context).heightPixels;
    }
}

布局

activity_game.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ll_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <TextView
            android:id="@+id/current_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="当前分数"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/highest_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="最高分数"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/target_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="目标分数"
            android:textSize="15sp" />
    </LinearLayout>

    <com.demo.demo0.GameView
        android:id="@+id/game"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/ll_btns"
        android:layout_below="@id/ll_title" />


    <LinearLayout
        android:id="@+id/ll_btns"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center">

        <Button
            android:id="@+id/revert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="撤销"
            android:textSize="30sp" />

        <Button
            android:id="@+id/restart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="重来"
            android:textSize="30sp" />
    </LinearLayout>

</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ll_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <TextView
            android:id="@+id/current_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="当前分数"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/highest_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="最高分数"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/target_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="#33000000"
            android:padding="10dp"
            android:text="目标分数"
            android:textSize="15sp" />
    </LinearLayout>

    <com.demo.demo0.GameView
        android:id="@+id/game"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/ll_btns"
        android:layout_below="@id/ll_title" />


    <LinearLayout
        android:id="@+id/ll_btns"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center">

        <Button
            android:id="@+id/revert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="撤销"
            android:textSize="30sp" />

        <Button
            android:id="@+id/restart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:background="#33000000"
            android:text="重来"
            android:textSize="30sp" />
    </LinearLayout>

</RelativeLayout>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MAC环境编译Android环境下的FFmpeg6.0版本

文章目录 一. 下载FFmpeg源码二、对FFmpeg进行安装编译三、进行JNI接口编写代码四、在Android 项目中调用.so库五、FFmpeg的代码学习技巧1、整体学习步骤2、FFmpeg的代码学习步骤 六、参考链接: 一. 下载FFmpeg源码 该项目是基于FFmpeg6.0环境编写。文中涉及代码在不同版本可能…

配置MySQL保存Hive元数据

Hive默认使用自带&#xff08;内嵌&#xff09;的Derby进行元数据存储&#xff0c;这个就意味着无法实现多个hive shell并发连接Hive。如果需要支持多用户登录Hive&#xff0c;必须配置一个独立的数据库。上一节我们已经将MySQL数据库安装到Linux上&#xff0c;本节我们将讲解一…

微服务架构基础--第1章认识微服务架构

第1章认识微服务架构 一.预习笔记 1.为什么需要微服务架构 传统的单体应用架构都是模块化的设计逻辑&#xff0c;易于开发和调试&#xff0c;也易于部署。但是随着用户量的增加&#xff0c;就无法满足系统的负载&#xff0c;虽然也可以进行单体架构的拓展&#xff0c;但是随着…

设备指纹系列--基础篇

基础概念 618还没开始&#xff0c;但是又好像已经结束了…在这种电商大促的大节日前&#xff0c;电商行业客户一般会提前找到合适的设备指纹产品&#xff0c;去防止被“薅秃”。因为&#xff0c;黑灰产拥有专业的设备牧场&#xff0c;通过使用模拟器、刷机改机等手段&#xff…

算法与数据结构-数组

文章目录 什么是数组线性表连续的内存空间和相同类型的数据 为什么数组的插入和删除是低效的插入删除 容器与数组的区别 什么是数组 数组&#xff08;Array&#xff09;是一种线性表数据结构。它用一组连续的内存空间&#xff0c;来存储一组具有相同类型的数据。 这个定义里有几…

Pytest自动化测试框架生成allure的报告

一、前言 最近通过群友了解到了allure这个报告&#xff0c;开始还不以为然&#xff0c;但还是逃不过真香定律。 经过试用之后&#xff0c;发现这个报告真的很好&#xff0c;很适合自动化测试结果的展示。下面说说我的探索历程吧。 选用的项目为Selenium自动化测试Pytest框架实…

IntelliJ IDEA彻底删除

我们在用idea的时候&#xff0c;idea的环境出现了莫名其妙的问题&#xff0c;怎么也找不到问题原因的时候可以试着把idea卸载重新安装。但是如果你卸载的时候没有删除干净注册表里的信息。就算再次安装回来也还是解决不了问题。 如何删除干净IDEA 将所有jetbrains软件关闭退出…

嵌入式软件工程师招聘

当您招聘嵌入式软件工程师时&#xff0c;以下是一些建议和关键要点&#xff0c;可以帮助您吸引和筛选合适的候选人&#xff1a; 职位描述&#xff1a;清晰地定义嵌入式软件工程师的职责和要求。包括对硬件和软件开发经验的要求、熟练掌握的编程语言&#xff08;如C、C、Python等…

一文学会MoveIt Setup Assistant搭建moveit2机械臂模型

文章目录 前言一、MoveIt Setup Assistant 是什么&#xff1f;二、搭建步骤拉取相关repo创建项目文档编辑moveit_description文件夹编辑moveit_config文件夹 MoveIt Setup Assistant 配置Launch moveit_setup_assistant配置干涉关系配置planning groups配置ros2 controller配置…

一个 TCP 连接可以发送多少个 HTTP 请求

第一个问题 第二个问题 第三个问题 第四个问题 第五个问题 曾经有这么一道面试题&#xff1a;从 URL 在浏览器被被输入到页面展现的过程中发生了什么&#xff1f; 相信大多数准备过的同学都能回答出来&#xff0c;但是如果继续问&#xff1a;收到的 HTML 如果包含几十个图…

优质高效!阿里内部超高质量的k8s+Jenkins笔记,技术与实战齐飞

什么是k8s? Kubernetes是一个用于容器集群的自动化部署、扩容以及运维的开源平台。 k8s孕育的初衷是培育出一个组件及工具的生态&#xff0c;帮助大家减轻在公有云及私有云上运行应用的负担&#xff0c;换言之&#xff0c;使得大型分布式应用的构建和运维变得更加简单&#…

⛳前端进阶:SEO 全方位解决方案

&#x1f33b; 前言 SEO 代表搜寻引擎最佳化/搜寻引擎优化(英文全名Search Engine Optimization&#xff0c;简称SEO)&#xff0c;是指通过了解搜寻引擎的自然排名的算法逻辑&#xff0c;以提高目标网站在有关搜寻引擎内排名的方式。 网站的 SEO 至关重要&#xff0c;它可以让…

基于springboot的大学外卖系统源码数据库

源码资源在这里 https://download.csdn.net/download/2301_76965813/87881744 1 系统分析 1.1 需求分析 该系统的开发&#xff0c;主要是用在了各个订餐网站的系统&#xff0c;用户可以通过网站进行外卖订餐的信息挂了&#xff0c;并能够对客户进行外卖菜品的订单提交等。该…

X509证书解析详解

上传的证书文件&#xff0c;如何判断这个证书是否满足X509标准格式的呢&#xff1f; 下面是我阅读jdk源码&#xff0c;总结出的解析步骤。 jdk版本&#xff1a;jdk11 方法的入口 这是整个方法的起点&#xff0c;下面的步骤是根据这里方法调用跟踪到的&#xff0c;需要注意的是…

100种思维模型之细节效率思维模型-74

提及细节效率&#xff1f;也许很多人会有疑问&#xff0c;“效率”怎么跟“细节”挂上钩&#xff0c;注重“细节”了&#xff0c;还能有“高率”&#xff1f; 是的&#xff0c;细节能提高效率&#xff0c;注意某些细节&#xff0c;效率事半功倍。 01、何谓细节效率思维模型 一…

truncate导致慢查询根因竟然是“多此一举”

基本信息&#xff1a; 线上一个库5.7.25库经常出现大量慢查询&#xff0c;在再次出现时登陆数据库进行分析&#xff0c;通过show engine innodb status 内容&#xff0c;发线程全部在等一个锁&#xff0c;这个锁极可能来源于这个truncate table动作&#xff1a; ---TRANSACTIO…

【Flutter】widgets (5) Flutter 理解 Flutter 的 Stateful Widget 有状态组件

文章目录 一、前言二、Stateful Widget三、StatefulWidget和State类的关系四、创建StatefulWidget五、完整代码示例六、总结一、前言 在之前的教程中,我们掌握了Stateless Widgets,也就是无状态组件的基本用法。 但是,应用程序不是静态不变的,我们需要界面中用户的操作,…

OCP浸没式液冷基本规范(概述和信号完整性部分)

液冷技术概述和浸没式液体标准化的需求 数据中心行业主要考虑两种类型的液体冷却技术来推动节能和可持续发展&#xff0c;分别是冷板式和浸没式&#xff0c;每一种技术里的液体又包含单相和双相两种规格&#xff1a; 冷板技术与浸没技术的主要区别之一是&#xff0c;在浸没的情…

操作系统原理 —— 什么是基本分页存储管理?(二十二)

在操作系统中&#xff0c;一个新的进程需要载入内存当中执行&#xff0c;在装入的时候需要给该进程分配一定的运行内存&#xff0c;在之前的章节中讲解了连续分配的几种方式&#xff0c;比如&#xff1a;单一连续分配、固定分区分配、动态分区分配&#xff0c;还讲解了对应的动…

MySQL表相关操作

一、存储引擎介绍 存储引擎即表类型&#xff0c;mysql根据不同的表类型会有不同的处理机制 1、什么是存储引擎 mysql中建立的库 > 文件夹 库中建立的表 > 文件 现实生活中我们用来存储数据的文件有不同的类型&#xff0c;每种文件类型对应各自不同的处理机制&#x…