package com.my2048;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

/**
2048简单实现的小游戏 —> 在布局里的引用下就可以了
*/

public class My2048View extends View {

//TODO 先画出一个整体的视图出来  --> 整体的一个图案画出来//TODO 创建画笔,缓存一个数组,记录数字以便下一次计算//TODO 创建四个方向的计算算法 上下左右不同的移动的计算(最核心的)  ---> 关联手势//TODO 绘制//TODO 这里主要使用了一个二维数组进行对方格的数字管理,进行一个变化//TODO 例如:进行一个右移,我对二维数组的第一个以为数组进行处理 ---> 即判断数是否要相加//这里没有做回退上一步的功能,你可以用一个ArrayList储存 每一步的 数组arr就可以Paint strokePaint; //画线的笔Paint textPaint;  //画数字的笔int width; //记录屏幕容器给我分配的宽int height; //记录屏幕容器分配的高int gridWidth; //格子的宽高  --->一般为屏幕宽度的四分之一int[][] arr = new int[4][4]; //对格子的数进行对应int textSize = 50;  //数字的大小,这里没采用sp,最好可以采用sp单位float textHeight;   //记录数字大小文本的高度public My2048View(Context context) {    this(context, null);}public My2048View(Context context, AttributeSet attrs) {    this(context, attrs, 0);}public My2048View(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    init(); //初始化一些配置}private void init() { //初始化一些配置    strokePaint = new Paint();    strokePaint.setAntiAlias(true); //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢    strokePaint.setColor(Color.GRAY); //设置颜色为灰色    strokePaint.setStrokeCap(Paint.Cap.ROUND);//设置线开始和结束点为圆弧样式    strokePaint.setStyle(Paint.Style.STROKE); //设置为线条样式    textPaint = new Paint();    textPaint.setAntiAlias(true); //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢    textPaint.setColor(Color.BLUE); //设置颜色为蓝色    textPaint.setStyle(Paint.Style.STROKE); //设置线条样式    textPaint.setTextSize(textSize); //最好可以转成sp    textPaint.setFakeBoldText(true);//设置文本为粗体    textPaint.setTextAlign(Paint.Align.CENTER);//设置为画文字的x轴为中心点,y轴向下扩展 所以后面y轴向下点才可以    Rect rect=new Rect();    textPaint.getTextBounds(arr[0][0]+"", 0, 1, rect);    textHeight = rect.height();//文本的高度    randomNumber();//随机位置生成数}@Override//布局protected void onLayout(boolean changed, int left, int top, int right, int bottom) {    super.onLayout(changed, left, top, right, bottom);}@Override//测量protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);}int startX;int startY;int endX;int endY;@Override//测量之后调用的方法  ----> 一般在这里得到view的宽高protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    width = w; //屏幕分配给我的width    height = h; //屏幕分配给我的height    gridWidth = w / 4;  //设置为宽度的四分之一,可以自己更改    startX = (width - gridWidth * 4) / 2;  //记录我开始画框的坐标点 -->X轴    startY = 0;  //记录我开始画框的坐标点 -->Y轴    endX = w - startX; //记录我结束画框的坐标点 -->X轴    endY = 4 * gridWidth;  //记录我结束画框的坐标点 -->Y轴}@Override//绘制protected void onDraw(Canvas canvas) {    super.onDraw(canvas);    canvas.drawColor(Color.parseColor("#FFFFFFAA")); //绘制背景    drawStroke(canvas); //绘制线条,整体的一个框架    drawText(canvas); //绘制格子中间的数字变化}private void drawStroke(Canvas canvas) {    for (int i = 0; i < 5; i++) {        canvas.drawLine(startX + i * gridWidth, startY, startX + i * gridWidth, endY, strokePaint);//画横线        canvas.drawLine(startX, startY + i * gridWidth, endX, startY + i * gridWidth, strokePaint);//画竖线    }}private void drawText(Canvas canvas) { //画数字    for (int i = 0; i < 4; i++) {        for (int j = 0; j < 4; j++) {            if (arr[i][j]!=0)            canvas.drawText(arr[i][j]+"", startX +gridWidth/2+gridWidth*j, startY +gridWidth/2+gridWidth*i+textHeight/2,textPaint);        }    }}float downX,downY,moveX,moveY; //   记录手势点下/移动的坐标@Overridepublic boolean onTouchEvent(MotionEvent event) { //这里的处理不怎么好 ---> 你可能点动一下就有反应了    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            downX =event.getX();            downY =event.getY();            break;        case MotionEvent.ACTION_MOVE:            moveX=event.getX();            moveY =event.getY();            break;        case MotionEvent.ACTION_UP:            float v = Math.abs(downX - moveX) - Math.abs(downY - moveY); //手势判断用户向哪里移动            if(v > 0) {                if(downX > moveX) {                    left(); //左移                }else {                    right();//右移                }            }else{                if(downY > moveY) {                    up(); //向上移动                }else {                    down();//向下移动                }            }            downX=0;downY=0;moveX=0;moveY=0;            randomNumber(); //随机位置生数            break;    }    invalidate(); //重绘制    return true;}Random r = new Random();        //生成随机数的类int[] value = new int[2];HashMap hashMap = new HashMap<>();private void randomNumber() {    //随机位置生成一个2    hashMap.clear();    int count = 0;    for (int i = 0; i < 4; i++) {        for (int j = 0; j < 4; j++) {            if (0==arr[i][j]) {               value=new int[2];//一定要不同的对象,不然会有问题               value[0]=i;               value[1]=j;               hashMap.put(count,value); //记录可以随机生成的坐标点 的集合               count++;            }        }    }    if (hashMap.size() > 0) {   //随机选一个坐标点生成数        int i = r.nextInt(hashMap.size());//生成的数包头不包尾        int[] ints = hashMap.get(i);        arr[ints[0]][ints[1]]=2;  //生成一个数为2    } else {    //做了个简单的提示        //判断是不是输了 --- 可以自己做的更好点 --->可以缓存上一步数,看是否可以移动        Toast.makeText(getContext(),"你要输了哦",Toast.LENGTH_SHORT).show();    }}ArrayList myData = new ArrayList<>(); //缓存的集合Integer filed;private void down() {       //向下移动实现    //返回一个装满不是0数字的集合    for (int i = 0; i < 4; i++) {        myData.clear(); //清除以前的数据        for (int j = 0; j < 4; j++) { //遍历竖的格子里的数            if (arr[j][i]!=0) { //如果不是0,在这竖的格子里要进行一个重新赋值                myData.add(arr[j][i]);                arr[j][i]=0; //把以前记录的数给清除,然后后面 进行一个重新赋值            }        }        getFinalNumber2(myData); //对数据是否要相加要处理        setNumberDown(i, myData); //数据处理之后进行一个重新赋值    }}private void up() {     //向上移动实现    for (int i = 0; i < 4; i++) {        myData.clear();        for (int j = 0; j < 4; j++) {            if (arr[j][i]!=0) {                myData.add(arr[j][i]);                arr[j][i]=0;            }        }        getFinalNumber(myData);        setNumberUp(i, myData);    }}private void right() {  //向右滑    for (int i = 0; i < 4; i++) {        myData.clear();        for (int j = 0; j < 4; j++) {            if (arr[i][j]!=0) {                myData.add(arr[i][j]);                arr[i][j]=0;            }        }        getFinalNumber2(myData);//        setNumberRight(i, myData);    }}private void left() {  //向左滑    for (int i = 0; i < 4; i++) {        myData.clear();        for (int j = 0; j < 4; j++) {            if (arr[i][j]!=0) {                myData.add(arr[i][j]);                arr[i][j]=0;            }        }        getFinalNumber(myData);        setNumberLeft(i,myData);    }}private void setNumberDown(int i, ArrayList myData) {    // 重新赋值    int size = myData.size();    for (int j = 0; j < size; j++) {        arr[4-1-j][i] = myData.get(size-1-j);    }}private void setNumberUp(int i, ArrayList myData) {    // 重新赋值    int size = myData.size();    for (int j = 0; j < size; j++) {        arr[j][i]=myData.get(j);    }}private void setNumberRight(int i, ArrayList myData) {    int size = myData.size(); //重新赋值    for (int j = 0; j < size; j++) {        arr[i][4-j-1] = myData.get(size-j-1);    }}private void setNumberLeft(int i, ArrayList myData) {    // 重新赋值    int size = myData.size();    for (int j = 0; j < size; j++) {        arr[i][j] = myData.get(j);    }}private void getFinalNumber(ArrayList myData) {    for (int i = 0; i < myData.size() - 1; i++) {        filed = myData.get(i);        if (filed.equals(myData.get(i + 1))) {//是Integer对象不能用==相比较,当integer对象小于128可以用==号相比较,因为小于128是取常量池里的            myData.set(i, filed * 2);            myData.remove(i + 1);            getFinalNumber(myData);        }    }}private void getFinalNumber2(ArrayList myData) {    int mySize = myData.size() - 1;//求出集合的size    for (int i = mySize; i > 0; --i) {        filed = myData.get(i);        if (filed.equals(myData.get(i - 1))) {//是Integer对象不能用==相比较,当integer对象小于128可以用==号相比较,因为小于128是取常量池里的            myData.set(i - 1, filed * 2);            myData.remove(i);            getFinalNumber2(myData);            break;        }    }}

}
//这是一个自定义的View,你直接在layout文件中直接引用就可以了,也可修改这个view的代码实现自己的要求,这个只是简单实现功能

更多相关文章

  1. 【Android】问题记录
  2. Activity瓦解坠落退出效果
  3. 播放记录的SQLite数据库实现
  4. android学习 4-25使用Path 绘制几何图形
  5. Android练习之BitmapFactory.decodeFile加载SD卡文件
  6. Java - Android(安卓)自定义控件之圆形进度条
  7. Android滑动解锁控件
  8. ListView属性备忘
  9. [Android记录]Android(安卓)Studio问题记录

随机推荐

  1. [置顶] AndroidStudio快捷键
  2. android 一步一步创建jni示例
  3. Android(安卓)QQ多级列表的实现
  4. 运行Android(安卓)Studio时,APP安装失败--
  5. android 弹出带输入框的对话框
  6. Android(安卓)Crash日志抓取及保存
  7. android中log的使用
  8. Android中对于Geometry对象的字符串化
  9. Android(安卓)启动线程OOM
  10. Android(安卓)三角标签(自定义Textview控