2048游戏

来源:互联网 发布:sql log shipping 编辑:程序博客网 时间:2024/06/07 19:42
    //条目布局  就是里面的控件
package com.example.liuan.ceshi;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Style;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * 2048的每个Item *  * @author zhy *  */public class Game2048Item extends View{/** * 该View上的数字 */private int mNumber;private String mNumberVal;private Paint mPaint;/** * 绘制文字的区域 */private Rect mBound;public Game2048Item(Context context, AttributeSet attrs, int defStyle){super(context, attrs, defStyle);mPaint = new Paint();}public Game2048Item(Context context){this(context, null);}public Game2048Item(Context context, AttributeSet attrs){this(context, attrs, 0);}public void setNumber(int number){mNumber = number;mNumberVal = mNumber + "";mPaint.setTextSize(30.0f);mBound = new Rect();mPaint.getTextBounds(mNumberVal, 0, mNumberVal.length(), mBound);invalidate();}public int getNumber(){return mNumber;}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);String mBgColor = "";switch (mNumber){case 0:mBgColor = "#CCC0B3";break;case 2:mBgColor = "#EEE4DA";break;case 4:mBgColor = "#EDE0C8";break;case 8:mBgColor = "#F2B179";// #F2B179break;case 16:mBgColor = "#F49563";break;case 32:mBgColor = "#F5794D";break;case 64:mBgColor = "#F55D37";break;case 128:mBgColor = "#EEE863";break;case 256:mBgColor = "#EDB04D";break;case 512:mBgColor = "#ECB04D";break;case 1024:mBgColor = "#EB9437";break;case 2048:mBgColor = "#EA7821";break;default:mBgColor = "#EA7821";break;}mPaint.setColor(Color.parseColor(mBgColor));mPaint.setStyle(Style.FILL);canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);if (mNumber != 0)drawText(canvas);}/** * 绘制文字 *  * @param canvas */private void drawText(Canvas canvas){mPaint.setColor(Color.BLACK);float x = (getWidth() - mBound.width()) / 2;float y = getHeight() / 2 + mBound.height() / 2;canvas.drawText(mNumberVal, x, y, mPaint);}}

//大布局 就是外面的控件

package com.example.liuan.ceshi;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.view.GestureDetector;import android.view.MotionEvent;import android.widget.RelativeLayout;import java.util.ArrayList;import java.util.List;import java.util.Random;/** * 2048的游戏面板,加入布局文件即可开始游戏 *  * @author zhy *  */public class Game2048Layout extends RelativeLayout{/** * 设置Item的数量n*n;默认为4 */private int mColumn = 4;/** * 存放所有的Item */private Game2048Item[] mGame2048Items;/** * Item横向与纵向的边距 */private int mMargin = 10;/** * 面板的padding */private int mPadding;/** * 检测用户滑动的手势 */private GestureDetector mGestureDetector;// 用于确认是否需要生成一个新的值private boolean isMergeHappen = true;private boolean isMoveHappen = true;/** * 记录分数 */private int mScore;public interface OnGame2048Listener{void onScoreChange(int score);void onGameOver();}private OnGame2048Listener mGame2048Listener;public void setOnGame2048Listener(OnGame2048Listener mGame2048Listener){this.mGame2048Listener = mGame2048Listener;}/** * 运动方向的枚举 *  * @author zhy *  */private enum ACTION{LEFT, RIGHT, UP, DOWM}public Game2048Layout(Context context, AttributeSet attrs, int defStyle){super(context, attrs, defStyle);mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,mMargin, getResources().getDisplayMetrics());// 设置Layout的内边距,四边一致,设置为四内边距中的最小值mPadding = min(getPaddingLeft(), getPaddingTop(), getPaddingRight(),getPaddingBottom());mGestureDetector = new GestureDetector(context , new MyGestureDetector());}/** * 根据用户运动,整体进行移动合并值等 */private void action(ACTION action){// 行|列for (int i = 0; i < mColumn; i++){List<Game2048Item> row = new ArrayList<Game2048Item>();// 行|列//记录不为0的数字for (int j = 0; j < mColumn; j++){// 得到下标int index = getIndexByAction(action, i, j);Game2048Item item = mGame2048Items[index];// 记录不为0的数字if (item.getNumber() != 0){row.add(item);}}//判断是否发生移动for (int j = 0; j < mColumn && j < row.size(); j++){int index = getIndexByAction(action, i, j);Game2048Item item = mGame2048Items[index];if (item.getNumber() != row.get(j).getNumber()){isMoveHappen = true;}}// 合并相同的mergeItem(row);// 设置合并后的值for (int j = 0; j < mColumn; j++){int index = getIndexByAction(action, i, j);if (row.size() > j){mGame2048Items[index].setNumber(row.get(j).getNumber());} else{mGame2048Items[index].setNumber(0);}}}//生成数字generateNum();}/** * 根据Action和i,j得到下标 *  * @param action * @param i * @param j * @return */private int getIndexByAction(ACTION action, int i, int j){int index = -1;switch (action){case LEFT:index = i * mColumn + j;break;case RIGHT:index = i * mColumn + mColumn - j - 1;break;case UP:index = i + j * mColumn;break;case DOWM:index = i + (mColumn - 1 - j) * mColumn;break;}return index;}/** * 合并相同的Item *  * @param row */private void mergeItem(List<Game2048Item> row){if (row.size() < 2)return;for (int j = 0; j < row.size() - 1; j++){Game2048Item item1 = row.get(j);Game2048Item item2 = row.get(j + 1);if (item1.getNumber() == item2.getNumber()){isMergeHappen = true;int val = item1.getNumber() + item2.getNumber();item1.setNumber(val);// 加分mScore += val;if (mGame2048Listener != null){mGame2048Listener.onScoreChange(mScore);}// 向前移动for (int k = j + 1; k < row.size() - 1; k++){row.get(k).setNumber(row.get(k + 1).getNumber());}row.get(row.size() - 1).setNumber(0);return;}}}/** * 得到多值中的最小值 *  * @param params * @return */private int min(int... params){int min = params[0];for (int param : params){if (min > param){min = param;}}return min;}@Overridepublic boolean onTouchEvent(MotionEvent event){mGestureDetector.onTouchEvent(event);return true;}public Game2048Layout(Context context){this(context, null);}public Game2048Layout(Context context, AttributeSet attrs){this(context, attrs, 0);}private boolean once;/** * 测量Layout的宽和高,以及设置Item的宽和高,这里忽略wrap_content 以宽、高之中的最小值绘制正方形 */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 获得正方形的边长int length = Math.min(getMeasuredHeight(), getMeasuredWidth());// 获得Item的宽度int childWidth = (length - mPadding * 2 - mMargin * (mColumn - 1))/ mColumn;if (!once){if (mGame2048Items == null){mGame2048Items = new Game2048Item[mColumn * mColumn];}// 放置Itemfor (int i = 0; i < mGame2048Items.length; i++){Game2048Item item = new Game2048Item(getContext());mGame2048Items[i] = item;item.setId(i + 1);LayoutParams lp = new LayoutParams(childWidth,childWidth);// 设置横向边距,不是最后一列if ((i + 1) % mColumn != 0){lp.rightMargin = mMargin;}// 如果不是第一列if (i % mColumn != 0){lp.addRule(RelativeLayout.RIGHT_OF,//mGame2048Items[i - 1].getId());}// 如果不是第一行,//设置纵向边距,非最后一行if ((i + 1) > mColumn){lp.topMargin = mMargin;lp.addRule(RelativeLayout.BELOW,//mGame2048Items[i - mColumn].getId());}addView(item, lp);}generateNum();}once = true;setMeasuredDimension(length, length);}/** * 是否填满数字 *  * @return */private boolean isFull(){// 检测是否所有位置都有数字for (int i = 0; i < mGame2048Items.length; i++){if (mGame2048Items[i].getNumber() == 0){return false;}}return true;}/** * 检测当前所有的位置都有数字,且相邻的没有相同的数字 *  * @return */private boolean checkOver(){// 检测是否所有位置都有数字if (!isFull()){return false;}for (int i = 0; i < mColumn; i++){for (int j = 0; j < mColumn; j++){int index = i * mColumn + j;// 当前的ItemGame2048Item item = mGame2048Items[index];// 右边if ((index + 1) % mColumn != 0){Log.e("TAG", "RIGHT");// 右边的ItemGame2048Item itemRight = mGame2048Items[index + 1];if (item.getNumber() == itemRight.getNumber())return false;}// 下边if ((index + mColumn) < mColumn * mColumn){Log.e("TAG", "DOWN");Game2048Item itemBottom = mGame2048Items[index + mColumn];if (item.getNumber() == itemBottom.getNumber())return false;}// 左边if (index % mColumn != 0){Log.e("TAG", "LEFT");Game2048Item itemLeft = mGame2048Items[index - 1];if (itemLeft.getNumber() == item.getNumber())return false;}// 上边if (index + 1 > mColumn){Log.e("TAG", "UP");Game2048Item itemTop = mGame2048Items[index - mColumn];if (item.getNumber() == itemTop.getNumber())return false;}}}return true;}/** * 产生一个数字 */public void generateNum(){if (checkOver()){Log.e("TAG", "GAME OVER");if (mGame2048Listener != null){mGame2048Listener.onGameOver();}return;}if (!isFull()){if (isMoveHappen || isMergeHappen){Random random = new Random();int next = random.nextInt(16);Game2048Item item = mGame2048Items[next];while (item.getNumber() != 0){next = random.nextInt(16);item = mGame2048Items[next];}item.setNumber(Math.random() > 0.75 ? 4 : 2);isMergeHappen = isMoveHappen = false;}}}/** * 重新开始游戏 */public void restart(){for (Game2048Item item : mGame2048Items){item.setNumber(0);}mScore = 0;if (mGame2048Listener != null){mGame2048Listener.onScoreChange(mScore);}isMoveHappen = isMergeHappen = true;generateNum();}class MyGestureDetector extends GestureDetector.SimpleOnGestureListener{final int FLING_MIN_DISTANCE = 50;@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY){float x = e2.getX() - e1.getX();float y = e2.getY() - e1.getY();if (x > FLING_MIN_DISTANCE&& Math.abs(velocityX) > Math.abs(velocityY)){action(ACTION.RIGHT);// Toast.makeText(getContext(), "toRight",// Toast.LENGTH_SHORT).show();} else if (x < -FLING_MIN_DISTANCE&& Math.abs(velocityX) > Math.abs(velocityY)){action(ACTION.LEFT);// Toast.makeText(getContext(), "toLeft",// Toast.LENGTH_SHORT).show();} else if (y > FLING_MIN_DISTANCE&& Math.abs(velocityX) < Math.abs(velocityY)){action(ACTION.DOWM);// Toast.makeText(getContext(), "toDown",// Toast.LENGTH_SHORT).show();} else if (y < -FLING_MIN_DISTANCE&& Math.abs(velocityX) < Math.abs(velocityY)){action(ACTION.UP);// Toast.makeText(getContext(), "toUp",// Toast.LENGTH_SHORT).show();}return true;}}}
//布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"  >    <com.example.liuan.ceshi.Game2048Layout        android:id="@+id/id_game2048"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_centerInParent="true"        android:background="#ffffff"        android:padding="10dp"></com.example.liuan.ceshi.Game2048Layout>    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_above="@id/id_game2048"        android:layout_centerHorizontal="true"        android:layout_marginBottom="20dp"        android:background="#EEE4DA"        android:orientation="horizontal">        <TextView            android:id="@+id/id_score"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:padding="4dp"            android:text="Score: 0"            android:textColor="#EA7821"            android:textSize="30sp"            android:textStyle="bold" />    </LinearLayout></RelativeLayout>

//主要逻辑

package com.example.liuan.ceshi;import android.content.DialogInterface;import android.os.Bundle;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.widget.TextView;public class MainActivity extends AppCompatActivity implements Game2048Layout.OnGame2048Listener  {    private TextView mScore;    private Game2048Layout mGame2048Layout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mScore = (TextView) findViewById(R.id.id_score);        mGame2048Layout = (Game2048Layout) findViewById(R.id.id_game2048);        mGame2048Layout.setOnGame2048Listener(this);    }    @Override    public void onScoreChange(int score)    {        mScore.setText("分数: " + score);    }    @Override    public void onGameOver()    {        new AlertDialog.Builder(this).setTitle("游戏结束")                .setMessage("你的最后得分是: " + mScore.getText())                .setPositiveButton("重新开始", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        mGame2048Layout.restart();                    }                }).setNegativeButton("退出游戏", new DialogInterface.OnClickListener()        {            @Override            public void onClick(DialogInterface dialog, int which)            {                finish();            }        }).show();    }}



1 0
原创粉丝点击