Android(安卓)小游戏2048 代码简单实现
16lz
2021-01-26
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的代码实现自己的要求,这个只是简单实现功能
更多相关文章
- 【Android】问题记录
- Activity瓦解坠落退出效果
- 播放记录的SQLite数据库实现
- android学习 4-25使用Path 绘制几何图形
- Android练习之BitmapFactory.decodeFile加载SD卡文件
- Java - Android(安卓)自定义控件之圆形进度条
- Android滑动解锁控件
- ListView属性备忘
- [Android记录]Android(安卓)Studio问题记录