仿2048游戏代码

来源:互联网 发布:怎样进行淘宝网店定位 编辑:程序博客网 时间:2024/05/20 00:51


做android开发的时间也不短了,一直都对游戏开发很感兴趣,利用工作之余的时间,仿照之前非常火热的2048游戏,写了一个差不多的游戏;核心逻辑代码是自己憋着脑袋敲出来的,有些bug难免 .博客也是作为自己的学习的记录

之前看过hongyang大神的拼图游戏的教学视频,有一种茅塞顿开的感觉,不一定所有的游戏都是需要游戏引擎才能写出来,利用android官方控件或者自定义控件也是可以写出好玩的小游戏;大神的拼图游戏:http://blog.csdn.net/lmj623565791/article/details/40595385,(写博客的时候才看到hongyang大神也有关于2048博客:http://blog.csdn.net/lmj623565791/article/details/40020137),看起来比我写的清晰多了@_@.

好吧,开始铺代码了

首先我我自定义了一个类,用于存储游戏中每一个小数字方块的信息

public class NumberItem {    private int number;//显示的数字    private int color;//显示的颜色    private int level;//级别从0开始    private int index;//位置角标    private TYPE type;//类型    public TYPE getType() {        return type;    }    public void setType(TYPE type) {        this.type = type;    }    public int getLevel() {        return level;    }    public void setLevel(int level) {        this.level = level;        number = (int) Math.pow(2, level + 1);        color = getColorByLevel(level);    }    public int getIndex() {        return index;    }    public void setIndex(int index) {        this.index = index;    }    public NumberItem(int level) {        number = (int) Math.pow(2, level + 1);        color = getColorByLevel(level);        type = TYPE.EMPTY;    }    public enum TYPE {        EMPTY,//普通没有数字的状态        NOT_EMPTY//有数字的状态    }    public void tagleType() {        if (type == TYPE.EMPTY) {            type = TYPE.NOT_EMPTY;        } else if (type == TYPE.NOT_EMPTY) {            type = TYPE.EMPTY;            setLevel(0);        }    }    /**     * 返回color     *     * @param level     * @return     */    private int getColorByLevel(int level) {        int[] colors = {R.color.level_0, R.color.level_1, R.color.level_2, R.color.level_3, R.color.level_4,                R.color.level_5, R.color.level_6, R.color.level_7, R.color.level_8, R.color.level_9,                R.color.level_10, R.color.level_11, R.color.level_12, R.color.level_13};        return colors[level];    }    public int getColor() {        return color;    }    public void setColor(int color) {        this.color = color;    }    public int getNumber() {        return number;    }    public void setNumber(int number) {        this.number = number;    }    @Override    public String toString() {        return "LEVEL-->" + level + "\nTYPE-->" + type.toString() + "\n";    }}


注释写得差不多的意思,就不赘述了


然后得需要一个自定义的游戏控件,就是用来放游戏小方块的容器,代码如下:


/** * Author:李烽 * Date:2015-09-14 * FIXME * Todo 游戏的容器 */public class GameContainer extends RelativeLayout {    private int mColumn = 4;//行数(列数)    private float mItemWidth;//每一个块的高度(宽度)    private float mWidth;//整个view的高度    private ArrayList<NumberItem> mNumberItems;//    private ArrayList<ItemView> mItems;//每一个块块    //    private static final int GAME_OVER = 1;//游戏结束//    private static final int GAME_SUCCESS = 2;//游戏胜利    private int mMargin = 3;//item之间的间隔    private int mPadding = 3;//主界面的padding    private boolean once;//是否是第一次初始化的标记(防止多次初始化)    private GestureDetector mGestureDetector;//手势管理者    public GameContainer(Context context) {        this(context, null, 0);    }    public GameContainer(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public GameContainer(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        //dp转化为px        mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3,                getResources().getDisplayMetrics());        mPadding = min(getPaddingBottom(), getPaddingLeft(), getPaddingLeft(), getPaddingRight());        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {            @Override            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {                final float absX = Math.abs(velocityX);                final float absY = Math.abs(velocityY);                final float deltaX = e2.getX() - e1.getX();                final float deltaY = e2.getY() - e1.getY();                final int travelX = getWidth() / 20;                final int travelY = travelX;                if (absY < absX && deltaX < -travelX) {                    onToLeft();                    return true;                } else if (absY < absX && deltaX > travelX) {                    onToRight();                    return true;                } else if (absX < absY && deltaY > travelY) {                    onToDown();                    return true;                } else if (absX < absY && deltaY < -travelY) {                    onToUp();                    return true;                }                return false;            }        });    }    @Override    public boolean onTouchEvent(MotionEvent event) {        mGestureDetector.onTouchEvent(event);        return true;    }    /**     * 上滑     */    private void onToUp() {//        Toast.makeText(getContext(), "top", Toast.LENGTH_SHORT).show();        if (GameHelper.allInTop(mNumberItems, mColumn))            return;        for (int i = 0; i < mColumn; i++) {            NumberItem[] items = {mNumberItems.get(i), mNumberItems.get(mColumn + i),                    mNumberItems.get(2 * mColumn + i), mNumberItems.get(3 * mColumn + i)};            GameHelper.judgeRule(items);        }        GameHelper.createNesItem(mNumberItems);        refreshItems(mNumberItems);    }    /**     * 下滑     */    private void onToDown() {        if (GameHelper.allInBottom(mNumberItems, mColumn))            return;        for (int i = 0; i < mColumn; i++) {            NumberItem[] items = {mNumberItems.get(3 * mColumn + i), mNumberItems.get(2 * mColumn + i),                    mNumberItems.get(mColumn + i), mNumberItems.get(i)};            GameHelper.judgeRule(items);        }        GameHelper.createNesItem(mNumberItems);        refreshItems(mNumberItems);    }    /**     * 右滑     */    private void onToRight() {        if (GameHelper.allInRight(mNumberItems, mColumn))            return;        for (int i = 0; i < mColumn; i++) {            NumberItem[] items = {mNumberItems.get(i * mColumn + 3), mNumberItems.get(i * mColumn + 2),                    mNumberItems.get(i * mColumn + 1), mNumberItems.get(i * mColumn)};            GameHelper.judgeRule(items);        }        GameHelper.createNesItem(mNumberItems);        refreshItems(mNumberItems);    }    /**     * 左滑     */    private void onToLeft() {        if (GameHelper.allInLeft(mNumberItems, mColumn))            return;        for (int i = 0; i < mColumn; i++) {            NumberItem[] items = {mNumberItems.get(i * mColumn), mNumberItems.get(i * mColumn + 1),                    mNumberItems.get(i * mColumn + 2), mNumberItems.get(i * mColumn + 3)};            GameHelper.judgeRule(items);        }        GameHelper.createNesItem(mNumberItems);        refreshItems(mNumberItems);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mWidth = min(getMeasuredHeight(), getMeasuredWidth());//确保为正方形        if (!once) {            initItem();            once = true;        }        setMeasuredDimension((int) mWidth, (int) mWidth);    }    /**     * 初始化每一个item     */    private void initItem() {        mItemWidth = (mWidth - mPadding * 2 - mMargin * (mColumn - 1)) / mColumn;        mItems = new ArrayList<>();        mNumberItems = new ArrayList<>();        /*初始的时候有两个是初始的item*/        int num1 = (int) (Math.random() * 16);        int num2 = (int) (Math.random() * 16);        if (num1 == num2)            num2 = num1 - 2;        for (int i = 0; i < mColumn * mColumn; i++) {            NumberItem item0 = new NumberItem(0);            if (i == num1 || i == num2)                item0.setType(NumberItem.TYPE.NOT_EMPTY);            item0.setIndex(i);            mNumberItems.add(item0);        }        refreshItems(mNumberItems);        GameHelper.setGameListener(new GameHelper.GameListener() {            @Override            public void onGameWin() {                if (callBack != null)                    callBack.onGameWin();            }            @Override            public void onGameFail() {                if (callBack != null)                    callBack.onGameFail();            }            @Override            public void onGamePointer(int point) {                if (callBack != null)                    callBack.onGamePointer(point);            }        });    }    private GameCallBack callBack;    public void gameRestart() {        initItem();    }    public void setGameCallBack(GameCallBack callBack) {        this.callBack = callBack;    }    public interface GameCallBack {        void onGameWin();        void onGameFail();        void onGamePointer(int point);    }    /**     * 根据数据更新界面     *     * @param numberItems     */    public void refreshItems(ArrayList<NumberItem> numberItems) {        removeAllViews();        for (int i = 0; i < mColumn * mColumn; i++) {            ItemView itemView = new ItemView(getContext());            if (numberItems.get(i).getType() == NumberItem.TYPE.NOT_EMPTY) {                itemView.setColor(getColorById(numberItems.get(i).getColor()));                itemView.setText(numberItems.get(i).getNumber() + "");            } else if (numberItems.get(i).getType() == NumberItem.TYPE.EMPTY) {                itemView.setColor(getColorById(R.color.level_13));                itemView.setText("");            }            itemView.setId(i + 1);            mItems.add(itemView);            RelativeLayout.LayoutParams lp = new LayoutParams((int) mItemWidth, (int) mItemWidth);            //设置各个item间的margin            //不是第一列            if (i % mColumn != 0) {                lp.leftMargin = mMargin;                lp.addRule(RelativeLayout.RIGHT_OF, mItems.get(i - 1).getId());            }            //不是第一行            if ((i + 1) > mColumn) {                lp.topMargin = mMargin;                lp.addRule(RelativeLayout.BELOW, mItems.get(i - mColumn).getId());            }            addView(itemView, lp);        }    }    /**     * 获取color值     *     * @param id     * @return     */    private int getColorById(int id) {        return getContext().getResources().getColor(id);    }    /**     * 获取多个参数的最小值     *     * @param params     * @return int     */    private int min(int... params) {        int min = params[0];        for (int param : params) {            if (param < min)                min = param;        }        return min;    }}

看起来比较多,里面的initItem()方法是参考hongyang的拼图游戏中的动态的给Relativelayout添加子view;使用了
GestureDetector

捕捉手势,然后

 /**     * 根据数据更新界面     *     * @param numberItems     */    public void refreshItems(ArrayList<NumberItem> numberItems) {        removeAllViews();        for (int i = 0; i < mColumn * mColumn; i++) {            ItemView itemView = new ItemView(getContext());            if (numberItems.get(i).getType() == NumberItem.TYPE.NOT_EMPTY) {                itemView.setColor(getColorById(numberItems.get(i).getColor()));                itemView.setText(numberItems.get(i).getNumber() + "");            } else if (numberItems.get(i).getType() == NumberItem.TYPE.EMPTY) {                itemView.setColor(getColorById(R.color.level_13));                itemView.setText("");            }            itemView.setId(i + 1);            mItems.add(itemView);            RelativeLayout.LayoutParams lp = new LayoutParams((int) mItemWidth, (int) mItemWidth);            //设置各个item间的margin            //不是第一列            if (i % mColumn != 0) {                lp.leftMargin = mMargin;                lp.addRule(RelativeLayout.RIGHT_OF, mItems.get(i - 1).getId());            }            //不是第一行            if ((i + 1) > mColumn) {                lp.topMargin = mMargin;                lp.addRule(RelativeLayout.BELOW, mItems.get(i - mColumn).getId());            }            addView(itemView, lp);        }    }

这个方法就是根据自定义的NumberItem的数据集合来更新游戏视图,主要是是否为空


里面用到了ItemView这个自定义控件(其实直接用TextView也可以)


package lee.vioson.game2048.UI.views;import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;import lee.vioson.game2048.R;/** * Author:李烽 * Date:2015-09-14 * FIXME * Todo itemiew */public class ItemView extends LinearLayout {    private TextView text;    private int color;    public ItemView(Context context) {        this(context, null, 0);    }    public ItemView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ItemView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        View view = View.inflate(context, R.layout.layout_item_contain, this);        text = (TextView) view.findViewById(R.id.text);        color = getContext().getResources().getColor(R.color.level_0);        text.setBackgroundColor(color);        text.setTextColor(Color.parseColor("#FF000000"));        text.setGravity(Gravity.CENTER);        text.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20                , getResources().getDisplayMetrics()));        text.setText(2048 + "");    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        setBackgroundResource(R.drawable.bg_contain);    }    /**     * 设置颜色     *     * @param color     */    public void setColor(int color) {        this.color = color;        text.setBackgroundColor(color);    }    /**     * 设置文字     *     * @param text     */    public void setText(String text) {        this.text.setText(text);    }}

其实就是一个Linearlayout包裹这一个textview

手势也监听了,游戏视图也显示出来了,现在就是要让视图响应手势,其实也就是通过监听手势对应的改变NumberItem集合中NumberItem的属性,然后根据数据集合刷新GameContainer,方法如下

 /**     * 处理滑动之后数据的变化,映射到ui上就是界面的变化     *     * @param items     */    public static void judgeRule(NumberItem[] items) {        for (int i = 0; i < items.length; i++) {            if (i < items.length - 1) {                if (isEmpty(items[i]) && isNotEmpty(items[i + 1])) {                    //本身为空,后面的一个不为空                    if (i == 0 || i == 1) {                        //第一列和第二列的时候,这时候要考虑三个子项                        if (isAllSame(items[i + 1], items[i + 2]))                            //后面两个相同且都不为空时候融合                            fixItem(items[i + 1], items[i + 2]);                    }                    exChangeItem(items[i], items[i + 1]);                } else if (isNotEmpty(items[i], items[i + 1])) {                    //本身和后面的一个都不为空时                    if (isAllSame(items[i], items[i + 1])) {                        //如果和身后的那个相同则融合                        fixItem(items[i], items[i + 1]);                    }                } else if (isEmpty(items[i], items[i + 1])) {                    //本身和后面一个都是空时候                    if (i == 0) {                        //第一列                        if (isAllSame(items[i + 2], items[i + 3])) {                            //身后第二个和第三个相同且不为空 融合,并调换至第一列                            fixItem(items[i + 2], items[i + 3]);                            exChangeItem(items[i], items[i + 2]);                        } else {                            //身后第二个和第三个不相同时                            if (isNotEmpty(items[i + 2])) {                                //第二个不是空的就将后面两个和自己加后面第一个对换                                exChangeItem(items[i], items[i + 2]);                                exChangeItem(items[i + 1], items[i + 3]);                            } else if (isEmpty(items[i + 2])) {                                //第二个是空的,交换自己和最后一个                                exChangeItem(items[i], items[i + 3]);                            }                        }                    } else if (i == 1) {                        //第二列                        if (isEmpty(items[i - 1]))                            //前面一个(也就是第一个)为空的时候,就不管最后一个是否是空,直接和自己对换                            exChangeItem(items[i - 1], items[i + 2]);                        else if (isAllSame(items[i - 1], items[i + 2]))                            //前面一个不为空,且和最后一个相同,将它们融合就好                            fixItem(items[i - 1], items[i + 2]);                        else                            //前面一个不为空,不和最后一个相同,直接将最后一个一道自身的位置(交换)                            exChangeItem(items[i], items[i + 2]);                    }                } else if (isEmpty(items[i + 1]) && isNotEmpty(items[i])) {                    //前面一个是空的,自身不是空的                    if (i == 0 || i == 1) {                        //第一列和第二列时                        if (isAllSame(items[i], items[i + 2])) {                            //如果自身和后面第二个一样就就直接将自己和第二个融合                            fixItem(items[i], items[i + 2]);                        }                    }                }            }        }    }



写的比较乱,也没有注释,因为我写这个的时候是一边调试一边添加条件,呵呵,脑子不好使,想不出有什么好办法,还好只是4X4的布局

估计里面可能还有一些没有考虑到的情况,但是应该没有影响很大的bug;主要将每一个子项和它后面的一个比较,是否是相同等级的,相同的可以相融合,不同的就不管,如果后面一个是空的就调换位置这样;

然后也没有其它什么了,源码可以下载看,有兴趣可以帮我修改修改.不会录屏,就不上图片了,下载下来运行一下就看到效果

http://download.csdn.net/detail/lifengli123/9108863



0 0
原创粉丝点击