zoukankan      html  css  js  c++  java
  • 我也来开发2048之终极奥义

    版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/x359981514/article/details/24582957

    本次教程跟之前隔了不少时间哈,有点忘记了的建议先看看前面的熟悉下,今天我准备把这个2048给结束了,拖了这么久。


    依照惯例,我们已经把准备工作都做好了。今天这一部分信息量比較大,也是整个游戏的核心所在,所以我准备分功能来讲。最后大家结合源代码来看就不会感觉太吃力了。


    1、初始化游戏

    初始化的时候,我们要干嘛呢,首先要看配置。配置了几行,然后先画好面板。然后要给在面板上随机生成2个数字Item。这涉及到2个方法,一个是初始化面板,一个是加入随机数字

    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的时候,我们使用了通常产生范围随机数的方法。同一时候指定2和4的比例在1:4,当然这个大家能够依据须要更改


    2、详细參数等初始化

    这个比較简单了。直接上代码。大家应该都看得懂

    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);
        }

    这部分不妨结合源代码看比較好,凝视清晰


    3、触摸事件

    触摸的时候推断4个方向,这个基本也是通用的写法了,不多说了

    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 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();
    	    }
    	}
        }

    以下我们来讲2048的终极奥义了。就是算法的实现,详细的算法在第一篇中已经解说了大概的过程。点我去看。以下我们选一个方向来讲怎样实现

    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();
    	}
        }

    概括来说。就是选取基准,挨个比較,又一次排列

    代码非常清晰。大家看看就知道了。关键是怎样总结出这个算法。


    4、以下就是推断游戏什么时候须要新加入一个数字Item

    当当前的数字矩阵结构域上次的结构发生区别的时候,我们就要add一个新的数字Item了

    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;
        }

    这个地方我们使用了一个历史矩阵来存储上一次的数字矩阵


    5、最后就是怎样推断结束了

    假设当前还有空格的Item,则必然没有结束,若相邻的数字都没有同样的数字,则必然结束,若出现配置的Goal,则赢了

    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;
        }

    以下放出一些终于的图片:



    因为刚换了工作,上下班时间倍增,所以写代码的时间也少了,事实上关于这个游戏我还有非常多想法没做。这个版本号的2048,比网上的版本号,多了撤销上次移动功能。多了能够定制游戏维数的功能,多了配置目标值的功能,我这个版本号的2048,配置要求极低,相比cocos2dx版本号的来说,极大的减少了电量消耗,可配置性更强。这些都是我在玩的过程中。认为不爽的地方,然后改进的。另一些想法。眼下还没有去做。平时工作去做android的framework了,应用层也就研究的少了,希望大家能改进我的代码。做出更好的2048。

    1、加入debug功能,也称作弊后门,我原来是想,当手指滑动超过多少距离后,调用一个新方法。设置加入的随机数的位置和大小,这个用我如今的代码是非常好实现的,仅仅要把addRandom方法改下,写一个debugRandom方法就OK了

    2、分享功能。这个用ShareSdk就能够了,玩游戏嘛,就是要大家一起玩才好玩。无社交不游戏

    3、更换2、4、8、16……数字的背景。这个网上非常多了。我们也能够自己定义一套背景,这个实现也是比較简单的,仅仅要把GameItem这个类里面的Item的背景加入一个set方法就ok了

    以上。终了

    以下,刷代码

    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 须要源代码的请留言


    PS 须要源代码的请留言
查看全文
  • 相关阅读:
    SqlServer 查看数据库中所有存储过程
    SqlServer 查看数据库中所有视图
    SqlServer 查询表的详细信息
    SqlServer 遍历修改字段长度
    net core 操作Redis
    Tuning SharePoint Workflow Engine
    Open With Explorer
    Download language packs for SharePoint 2013
    Change Maximum Size For SharePoint List Template when Saving
    Six ways to store settings in SharePoint
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10959859.html
  • Copyright © 2011-2022 走看看