android---2048遊戲實現

幫同窗作的遊戲,爲加快遊戲開發進度,參考了某在線學院的設計教程
這裏寫圖片描述java

根據界面,主要實現4*4的格子方塊比較麻煩,其餘的都挺簡單的.整體爲實現4*4的格子,自定義GridLayout,並在其中添加觸摸監聽事件,進行一系列的操做,從而實現遊戲的邏輯,最後再添加動畫效果便可完成.

下面是設計思路:android

一.GameView的設計

首先自定義一個類,繼承GridLayout,添加兩個構造方法
public class GameView extends GridLayout {

    //兩個必要的構造方法
    public GameView(Context context) {
        super(context);
        initView();
    }

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }
    }

接下來在initView()中實現設置GridLayout爲四列,而且添加觸摸事件監聽.(監聽方法還能夠重寫onTouchEvent(),返回值爲true便可),判斷觸摸方向,主要是經過x軸和y軸的偏移量的比較markdown

//初始化變量的方法
    public void initView(){
        //設置只有四列
        setColumnCount(4);
        //設置監聽事件
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        setX = event.getX();
                        setY = event.getY();
                        break;
                    case MotionEvent.ACTION_UP:
                        offsetX = event.getX() - setX;
                        offsetY = event.getY() - setY;
                        //判斷滑動方向
                        if (Math.abs(offsetX) >= Math.abs(offsetY)) {
                            if (offsetX > 0) {
                                swipright();
                            } else if (offsetX < 0) {
                                swipleft();
                            }
                        } else {
                            if (offsetY > 0) {
                                swipdown();
                            } else if (offsetY < 0) {
                                swipup();
                            }
                        }

                        break;
                }

                return true;
            }
        });
    }

監聽事件實現後先放在那裏,接下來把4*4的裏面每一個小格子設計成小卡片,每一個卡片就是一個TextView,卡片設計很簡單,須要什麼就添加什麼,默認數字爲0,這個時候表明是空值,也就是空卡片.框架

public class Card extends FrameLayout {

    public Card(Context context) {
        super(context);
        tvCard = new TextView(getContext());
        tvCard.setTextSize(40f);
        tvCard.setGravity(Gravity.CENTER);
        LayoutParams lp = new LayoutParams(-1,-1);
        lp.setMargins(15,15,0,0);
        addView(tvCard, lp);
    }
    //卡片上的數字
    private int num;
    private boolean is2048 = true;
    private void judgeIs2048(int num){
        if (is2048){
            if (2048==num){
                Toast.makeText(getContext(),"恭喜趙瑩達到2048",Toast.LENGTH_LONG).show();
                is2048 = false;
            }
        }
    }
    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
        if (num<=0){
            tvCard.setText("");
        }else {
        //這裏傳進去的是字符串所以須要加上空字符
            tvCard.setText(num+"");
        }
        switch (num) {
            case 0:
                tvCard.setBackgroundColor(0x33ffffff);
                break;
            case 2:
                tvCard.setBackgroundColor(0xffeee4da);
                break;
            case 4:
                tvCard.setBackgroundColor(0xffede0c8);
                break;
            case 8:
                tvCard.setBackgroundColor(0xfff2b179);
                break;
            case 16:
                tvCard.setBackgroundColor(0xfff59563);
                break;
            case 32:
                tvCard.setBackgroundColor(0xfff67c5f);
                break;
            case 64:
                tvCard.setBackgroundColor(0xfff65e3b);
                break;
            case 128:
                tvCard.setBackgroundColor(0xffedcf72);
                break;
            case 256:
                tvCard.setBackgroundColor(0xffedcc61);
                break;
            case 512:
                tvCard.setBackgroundColor(0xffedc850);
                break;
            case 1024:
                tvCard.setBackgroundColor(0xffedc53f);
                break;
            case 2048:
                tvCard.setBackgroundColor(0xffedc22e);
                break;
            default:
                tvCard.setBackgroundColor(0xff3c3a32);
                break;
        }
        judgeIs2048(num);
    }


    //判斷是否相等,用於合併
    public boolean equals(Card o) {
        return getNum()==o.getNum();
    }

    //用於顯示數字
    private TextView tvCard;

    public TextView getTvCard() {
        return tvCard;
    }
}
卡片設計就須要添加到GameView裏面,這個時候重寫onSizeChanged()函數,這個在程序打開的時候運行一次,經過他來動態設計卡片大小,而且添加卡片和開始遊戲.
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, w, oldw, oldh);
        Config.CARD_WIDTH = (Math.min(w,h)-10)/4;
        AddCard(Config.CARD_WIDTH);
        StartGame();

    }

添加卡片,一開始全設置爲0,也就是所有添加空卡片dom

//添加卡片
    private void AddCard(int CARD_WIDTH){
        Card c;
        for (int x = 0;x<4;x++){
            for (int y = 0;y<4;y++){
               c = new Card(getContext());
                c.setNum(0);
                addView(c, CARD_WIDTH, CARD_WIDTH);
                cardMap[y][x] = c;
            }
        }
    }

遊戲開始須要隨機添加兩張卡片,數值2或者4,出現比率9:1ide

//開始遊戲
    public void StartGame(){

        for (int y = 0;y<4;y++){
            for (int x = 0;x<4;x++){
                cardMap[y][x].setNum(0);
            }
        }
        AddRandomCard();
        AddRandomCard();
    }

隨機添加卡片設計函數

//添加隨機卡片
    private void AddRandomCard(){
        CardPoint.clear();
        for (int y = 0;y<4;y++){
            for (int x = 0;x<4;x++){
                if (cardMap[x][y].getNum()<=0){
                    CardPoint.add(new Point(x,y));
                }
            }
        }
        //把一張空卡片換成帶數字的
        Point p = CardPoint.remove((int)(Math.random()*CardPoint.size()));
        cardMap[p.x][p.y].setNum(Math.random()>0.1?2:4);
        MainActivity.getMainActivity().getAnimLayer().createScaleTo1(cardMap[p.x][p.y]);

    }

這樣大致框架就設計好了
接下來是滑動事件,這裏只舉例左滑佈局

private void swipleft(){
        boolean status = false;
        for (int y = 0; y < 4; y++) {
            for (int x = 0; x < 4; x++) {

                for (int x1 = x+1; x1 < 4; x1++) {
                    if (cardMap[x1][y].getNum()>0) {

                        if (cardMap[x][y].getNum()<=0) {

                            MainActivity.getMainActivity().getAnimLayer().createMoveAnim(cardMap[x1][y],cardMap[x][y], x1, x, y, y);
                            cardMap[x][y].setNum(cardMap[x1][y].getNum());
                            cardMap[x1][y].setNum(0);
                            x--;
                            status = true;
                        }else if (cardMap[x][y].equals(cardMap[x1][y])) {
                            MainActivity.getMainActivity().getAnimLayer().createMoveAnim(cardMap[x1][y], cardMap[x][y],x1, x, y, y);
                            cardMap[x][y].setNum(cardMap[x][y].getNum() * 2);
                            cardMap[x1][y].setNum(0);
                            MainActivity.getMainActivity().addScore(cardMap[x][y].getNum());
                            status = true;
                        }
                        break;
                    }
                }
            }
        }
        if (status){
            AddRandomCard();
            checkGame();
        }
    }

每次添加卡片還須要判斷是否結束遊戲動畫

//結束遊戲
    private void checkGame(){
        boolean complete = true;

        ALL:
        for (int y = 0; y < 4; y++) {
            for (int x = 0; x < 4; x++) {
                if (cardMap[x][y].getNum()==0||
                        (x>0&&cardMap[x][y].equals(cardMap[x-1][y]))||
                        (x<3&&cardMap[x][y].equals(cardMap[x+1][y]))||
                        (y>0&&cardMap[x][y].equals(cardMap[x][y-1]))||
                        (y<3&&cardMap[x][y].equals(cardMap[x][y+1]))) {

                    complete = false;
                    break ALL;
                }
            }
        }

        if (complete) {
            Toast.makeText(getContext(), "遊戲結束" + MainActivity.getMainActivity().getScore(), Toast.LENGTH_LONG).show();
        }
    }

設計整體上框架就是上面說的那些.ui

二.動畫效果

動畫效果主要是建立,移動,合併這三個效果,所以重寫個繼承FrameLayout的class,覆蓋到遊戲界面上,這樣的目的能夠經過MainActivity中實例化當前這個類,而後能夠操做其方法,而後經過滑動來設置動畫
public class AnimLayer extends FrameLayout {

    public AnimLayer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public AnimLayer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnimLayer(Context context) {
        super(context);
    }



    public void createMoveAnim(final Card from,final Card to,int fromX,int toX,int fromY,int toY){

        final Card c = getCard(from.getNum());

        LayoutParams lp = new LayoutParams(Config.CARD_WIDTH, Config.CARD_WIDTH);
        lp.leftMargin = fromX*Config.CARD_WIDTH;
        lp.topMargin = fromY*Config.CARD_WIDTH;
        c.setLayoutParams(lp);

        if (to.getNum()<=0) {
            to.getTvCard().setVisibility(View.INVISIBLE);
        }
        TranslateAnimation ta = new TranslateAnimation(0, Config.CARD_WIDTH*(toX-fromX), 0, Config.CARD_WIDTH*(toY-fromY));
        ta.setDuration(100);
        ta.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {}

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                to.getTvCard().setVisibility(View.VISIBLE);
                recycleCard(c);
            }
        });
        c.startAnimation(ta);
    }

    private Card getCard(int num){
        Card c;
        if (cards.size()>0) {
            c = cards.remove(0);
        }else{
            c = new Card(getContext());
            addView(c);
        }
        c.setVisibility(View.VISIBLE);
        c.setNum(num);
        return c;
    }
    private void recycleCard(Card c){
        c.setVisibility(View.INVISIBLE);
        c.setAnimation(null);
        cards.add(c);
    }
    private List<Card> cards = new ArrayList<Card>();

    public void createScaleTo1(Card target){
        ScaleAnimation sa = new ScaleAnimation(0.1f, 1, 0.1f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        sa.setDuration(100);
        target.setAnimation(null);
        target.getTvCard().startAnimation(sa);
    }

}

最後主佈局文件以下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fffaf8ef" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    <LinearLayout  android:layout_marginTop="15dp" android:orientation="horizontal" android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content">
        <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff776e65" android:text="@string/title" android:textSize="50sp"/>
    </LinearLayout>

    <LinearLayout  android:layout_width="match_parent" android:orientation="horizontal" android:layout_marginTop="10dp" android:layout_height="wrap_content">

        <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ff776e65" android:layout_marginLeft="30dp" android:textSize="35sp" android:text="@string/Score"/>
        <TextView  android:id="@+id/tvscore" android:layout_marginLeft="20dp" android:textSize="25sp" android:textColor="#ff776e65" android:layout_width="70dp" android:layout_height="37dp" />
        <Button  android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/startgame" android:layout_marginLeft="40dp" android:background="#ffbbada0" android:textSize="15sp" android:text="@string/start"/>

    </LinearLayout>
    <FrameLayout  android:id="@+id/gameContainer" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1">
    <develop.niuli.com.game.GameView  android:layout_marginTop="40dp" android:id="@+id/Gridlayout" android:layout_width="match_parent" android:background="#ffbbada0" android:layout_height="350dp">

    </develop.niuli.com.game.GameView>

    <develop.niuli.com.game.AnimLayer  android:id="@+id/animLayer" android:layout_width="match_parent" android:layout_height="match_parent">
    </develop.niuli.com.game.AnimLayer>

    </FrameLayout>

</LinearLayout>

備註:

相關文章
相關標籤/搜索