(更新)女友是第一生產力之Android實現“2048”遊戲

起因是這樣的,今早安卓開發課佈置了寫2048小遊戲的實驗,並且給了源代碼,我照着源代碼一頓猛敲,做出了個老師要的版本。
想到女朋友也挺喜歡玩2048的,就想得瑟一下,發了個apk過去。
沒想到遭到一陣嫌棄,“你這數字都是黑色好模糊啊我都看不清”,“我都快到2048了走錯一步,哎呀你這個怎麼都不能回退一步的”
emmmmmm好吧,誰叫咱想裝逼呢,那麼就針對甲方這兩個需求,開始敲代碼

繼昨日後續,甲方說“阿sir,你這個怎麼都沒有最高分的?”
對哦,身爲一個遊戲,不斷挑戰最高分,纔是它的好玩之處。着手修改

2048遊戲的實現

結果展示

1.結果1.0
在這裏插入圖片描述
2.結果2.0
在這裏插入圖片描述

思路

  1. 改顏色
    改顏色這個很容易,但是要找ARGB的顏色來改Card類中每個數字的顏色
  2. 實現回退
    這裏我用四個ArrayList分別來存放當前的位置、當前的數值、上一步的位置、上一步的數值。
    每次進行上下左右滑動的時候,就把當前的位置、當前的數值覆蓋掉上次記錄的上一步的位置、上一步的數值。然後再記錄新的當前的位置、當前的數值。
    每次回退就把上一步的位置和上一步的數值加載進這個界面。
    回退當然也要回退分數,這裏用兩個整型變量來傳遞就好了。
  3. 記錄最高分
    最簡單的我想到就是利用SharedPreferences來保存信息,這裏我覺得還需要判斷是不是第一次啓動,如果是第一次啓動那我就創建一個最高分文件來儲存,如果不是第一次啓動,那就直接從裏面拿東西。同樣,判斷第一次啓動我也用的是SharedPreferences。

源碼

  1. 首先看看我的文件樹
    在這裏插入圖片描述
  2. Card類
package com.example.minigame;

import android.content.Context;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;


public class Card extends FrameLayout {
    private TextView text;
    private int number=0;
    public int getNumber(){
        return number;
    }
    public void setNumber(int number){
        this.number=number;
        if(number<2){
            text.setText("");
        }else{
            if(number==2){
                text.setTextColor(0xFFFFFF00);
            }else if(number==4){
                text.setTextColor(0xFF00FF00);
            }
            else if(number==8){
                text.setTextColor(0xFF00FFFF);
            }
            else if(number==16){
                text.setTextColor(0xFF0000FF);
            }
            else if(number==32){
                text.setTextColor(0xFFFF00FF);
            }
            else if(number==64){
                text.setTextColor(0xFF7F007F);
            }
            else if(number==128){
                text.setTextColor(0xFFFF7F00);
            }
            else if(number==256){
                text.setTextColor(0xFF996633);
            }
            else if(number==512){
                text.setTextColor(0xFFFF0000);
            }
            else if(number==1024){
                text.setTextColor(0xFF350D04);
            }
            else if(number==2048){
                text.setTextColor(0xFFFF3800);
            }
            else{
                text.setTextColor(0xFF95090C);
            }
            text.setText(number+"");
        }
    }
    public Card(@NonNull Context context) {
        super(context);
        text=new TextView(context);
        text.setTextSize(28);
        text.setBackgroundColor(0x9966cccc);
        text.setGravity(Gravity.CENTER);
        LayoutParams params=new LayoutParams(-1,-1);
        params.setMargins(10,10,0,0);
        addView(text,params);
    }
}

  1. GameView類
package com.example.minigame;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;
import android.content.SharedPreferences;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class GameView extends GridLayout {
    //定義4*4的卡片佈局
    private Card cards[][]=new Card[4][4];
    //記錄空卡片
    private List<Point> emptyCards=new ArrayList<Point>();
    //隨機數
    Random rd=new Random();
    //分數
    int score=0;
    int oldscore=0;
    int currentscore=0;
    int bscore;

    public int getBscore() {
        return bscore;
    }

    public void setBscore(int bscore) {
        this.bscore = bscore;
    }

    //記錄所有卡片位置及當前分數
    private List<Point> backCards=new ArrayList<Point>();
    private List<Point> oldbackCards=new ArrayList<Point>();
    private List<Integer> backCardsnums=new ArrayList<Integer>();
    private List<Integer> oldbackCardsnums=new ArrayList<Integer>();


    public GameView(Context context) {
        super(context);
        initGame();
    }

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

    public GameView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initGame();
    }
    //遊戲初始界面
    private void initGame() {
        setColumnCount(4);  //設置列的數量
        setBackgroundColor(0xffffcccc); //設置背景顏色
        setOnTouchListener(new OnTouchListener() {  //觸摸監聽
            private float startX,startY;
            private float offsetX,offsetY;
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:   //手勢事件開啓
                        startX=event.getX();    //獲取當前x座標
                        startY=event.getY();    //獲取當前y座標
                        break;
                    case MotionEvent.ACTION_UP:     //手勢事件結束
                        Gameover();
                        offsetX=event.getX()-startX;    //獲取當前x座標跟移動前座標的x差值
                        offsetY=event.getY()-startY;    //獲取當前y座標跟移動前座標的y差值
                        if(Math.abs(offsetX)>Math.abs(offsetY)){    //x差值大於y差值,說明是左右移動
                            if(offsetX<-3){ //左移
                                moveLeft();
                                System.out.println("----左");
                            }else if(offsetX>3){    //右移
                                moveRight();
                                System.out.println("----右");
                            }
                        }
                        else{
                            if(offsetY<-3){
                                moveUp();
                                System.out.println("----上");
                            }else if(offsetY>3){
                                moveDown();
                                System.out.println("----下");
                            }
                        }
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }
    private void moveRight(){
        boolean flage=false;//移動是否有效
        for(int y=0;y<4;y++){
            for(int x=3;x>=0;x--){
                for(int x1=x-1;x1>=0;x1--){
                    if(cards[x1][y].getNumber()>0){//準備往右的這張卡片,需要判斷是否有數值
                        if(cards[x][y].getNumber()<2){//在右邊的這張卡片,如果沒數值,就用準備往右的這張卡片的數值替代它
                            cards[x][y].setNumber(cards[x1][y].getNumber());
                            cards[x1][y].setNumber(0);
                            x++;
                            flage=true;
                            score+=2;
                        }else if(cards[x][y].getNumber()==cards[x1][y].getNumber()){//在右邊的這張卡片,如果數值與準備往右的這張卡片的數值相同,就合併數值
                            cards[x][y].setNumber(cards[x][y].getNumber()*2);
                            score+=cards[x][y].getNumber();
                            cards[x1][y].setNumber(0);
                            flage=true;
                        }
                        break;
                    }
                }
            }
        }
        oldremeberCard();
        if(flage){//移動有效就創建新卡片
            creatRandomCard();
            remeberCard();
        }
    }
    private void moveLeft(){
        boolean flage=false;
        for(int y=0;y<4;y++){
            for(int x=0;x<4;x++){
                for(int x1=x+1;x1<4;x1++){
                    if(cards[x1][y].getNumber()>0){
                        if(cards[x][y].getNumber()<2){
                            cards[x][y].setNumber(cards[x1][y].getNumber());
                            cards[x1][y].setNumber(0);
                            x--;
                            flage=true;
                            score+=2;
                        }else if(cards[x][y].getNumber()==cards[x1][y].getNumber()){
                            cards[x][y].setNumber(cards[x][y].getNumber()*2);
                            score+=cards[x][y].getNumber();
                            cards[x1][y].setNumber(0);
                            flage=true;
                        }
                        break;
                    }
                }
            }
        }
        oldremeberCard();
        if(flage){
            creatRandomCard();
            remeberCard();
        }
    }
    private void moveDown(){
        boolean flage=false;
        for(int x=0;x<4;x++){
            for(int y=3;y>=0;y--){
                for(int y1=y-1;y1>=0;y1--){
                    if(cards[x][y1].getNumber()>0){
                        if(cards[x][y].getNumber()<2){
                            cards[x][y].setNumber(cards[x][y1].getNumber());
                            cards[x][y1].setNumber(0);
                            y++;
                            flage=true;
                            score+=2;
                        }else if(cards[x][y].getNumber()==cards[x][y1].getNumber()){
                            cards[x][y].setNumber(cards[x][y].getNumber()*2);
                            score+=cards[x][y].getNumber();
                            cards[x][y1].setNumber(0);
                            flage=true;
                        }
                        break;
                    }
                }
            }
        }
        oldremeberCard();
        if(flage){
            creatRandomCard();
            remeberCard();
        }
    }
    private void moveUp(){
        boolean flage=false;
        for(int x=0;x<4;x++){
            for(int y=0;y<4;y++){
                for(int y1=y+1;y1<4;y1++){
                    if(cards[x][y1].getNumber()>0){
                        if(cards[x][y].getNumber()<2){
                            cards[x][y].setNumber(cards[x][y1].getNumber());
                            cards[x][y1].setNumber(0);
                            y--;
                            flage=true;
                            score+=2;
                        }else if(cards[x][y].getNumber()==cards[x][y1].getNumber()){
                            cards[x][y].setNumber(cards[x][y].getNumber()*2);
                            score+=cards[x][y].getNumber();
                            cards[x][y1].setNumber(0);
                            flage=true;
                        }
                        break;
                    }
                }
            }
        }
        oldremeberCard();
        if(flage){
            creatRandomCard();
            remeberCard();
        }
    }
    private void Gameover(){//判斷遊戲是否結束
        boolean OverGame=true;
        for(int y=0;y<4;y++){
            for(int x=0;x<4;x++){
                if(cards[x][y].getNumber()<=0 ||    //有一個卡片數值爲0說明有空位
                        (x>0&&cards[x][y].getNumber()==cards[x-1][y].getNumber())|| //有相同卡片說明可以合併,下同
                        (x<3&&cards[x][y].getNumber()==cards[x+1][y].getNumber())||
                        (y>0&&cards[x][y].getNumber()==cards[x][y-1].getNumber())||
                        (y<3&&cards[x][y].getNumber()==cards[x][y+1].getNumber())){
                    OverGame=false;
                }
            }
        }
        if(OverGame){   //提示遊戲結束
            //遊戲結束時判斷最高分
            if(score>bscore){
                bscore=score;
            }
            new AlertDialog.Builder(getContext()).setTitle("遊戲結束").setMessage("請選擇是否繼續挑戰")
                    .setPositiveButton("好呀好呀",new AlertDialog.OnClickListener(){ //選擇是的話就繼續開啓新遊戲
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            GameStart();
                            score=0;
                        }
                    }).setNegativeButton("不啦不啦",null).show();
        }
    }
    private void Addard(int width,int height){
        Card c;
        for(int y=0;y<4;y++){
            for(int x=0;x<4;x++){
                c=new Card(getContext());
                cards[x][y]=c;
                c.setNumber(0);
                addView(c,width,height);
            }
        }
    }
    @Override
    protected void onSizeChanged(int w,int h,int oldw,int oldh){    //界面尺寸變化適應函數
        super.onSizeChanged(w,h,oldw,oldh);
        int width=(w-10)/4;
        Addard(width,width);
        GameStart();
    }
    private void oldremeberCard(){
        oldbackCards.clear();
        oldbackCardsnums.clear();
        oldbackCards.addAll(backCards);
        oldbackCardsnums.addAll(backCardsnums);
        oldscore=currentscore;
    }
    private void remeberCard(){    //記錄當前操作
        backCards.clear();
        backCardsnums.clear();
        for(int y=0;y<4;y++){   //重新記錄卡片位置
            for(int x=0;x<4;x++){
                Point point=new Point(x,y);
                backCards.add(point);
                backCardsnums.add(cards[x][y].getNumber());
            }
        }
        currentscore=score; //記錄當前分數
    }
    private void creatRandomCard(){
        emptyCards.clear(); //卡片位置爲空的數組清空
        for(int y=0;y<4;y++){   //重新記錄卡片位置爲空的數組
            for(int x=0;x<4;x++){
                if(cards[x][y].getNumber()<2){
                    Point point=new Point(x,y);
                    emptyCards.add(point);
                }
            }
        }
        int selat=rd.nextInt(emptyCards.size());//寫一個隨機數
        Point p=emptyCards.get(selat);//隨機取一個空着的卡片
        emptyCards.remove(selat);//取到的卡片準備賦值,所以這個卡片不爲空了,踢出去
        int number=0;
        if(rd.nextInt(10)>4){
            number=4;
        }else{
            number=2;
        }
        cards[p.x][p.y].setNumber(number);
    }
    public void GameStart(){//全部卡片置爲0,創建兩張新卡片
        if(score>bscore){
            bscore=score;
        }
        for(int y=0;y<4;y++){
            for (int x=0;x<4;x++){
                cards[x][y].setNumber(0);
            }
        }
        oldbackCards.clear();
        oldbackCardsnums.clear();
        creatRandomCard();
        creatRandomCard();
        remeberCard();
    }
    public void Gameback(){ //返回上一步操作
        if(oldbackCardsnums.isEmpty() && oldbackCards.isEmpty()){
            System.out.println("沒有值,回退不了");
        }
        else {
            for (int y = 0; y < 4; y++) {
                for (int x = 0; x < 4; x++) {
                    Point p = oldbackCards.get(y * 4 + x);//拿出位置
                    cards[p.x][p.y].setNumber(oldbackCardsnums.get(y * 4 + x));//拿出值放在該位置上
                }
            }
            score=oldscore;
            remeberCard();
        }
    }
}

  1. MainActivity類
package com.example.minigame;

import androidx.annotation.NonNull;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends Activity {
    TextView score_show;    //分數展示
    TextView bestscore_show;    //最高分展示
    GameView gv;    //子控件佈局
    Button new_game;    //新遊戲按鈕
    Button rollback;    //反悔按鈕
    SharedPreferences.Editor editor=null;
    Handler handler=new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            int num=msg.arg1;
            score_show.setText(num+"");
        }
    };
    Handler handler1=new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            int num=msg.arg1;
            bestscore_show.setText(num+"");
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        score_show=(TextView)findViewById(R.id.tv_score_show);
        gv=(GameView)findViewById(R.id.gv_show);
        new_game=(Button) findViewById(R.id.tv_newganme);
        bestscore_show=(TextView)findViewById(R.id.tv_bestscore_show);
        //判斷是不是第一次運行
        iffirstrun();
        bestscore_show.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                editor=getSharedPreferences("mybestscore",0).edit();
                editor.putString("bestscore",Integer.toString(gv.getBscore()));
                editor.commit();
            }
        });
        new_game.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                gv.GameStart();
                gv.score=0;
            }
        });
        rollback=(Button)findViewById(R.id.tv_rockback);
        rollback.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                gv.Gameback();
                System.out.println("我反悔了");
            }
        });
        //定時器,定時刷新分數
        Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Message msg=new Message();
                msg.arg1=gv.score;
                handler.sendMessage(msg);
            }
        },80,150);
        score_show.setText(100+"");

        //定時器,定時刷新最高分數
        Timer timer1=new Timer();
        timer1.schedule(new TimerTask() {
            @Override
            public void run() {
                Message msg=new Message();
                msg.arg1=gv.bscore;
                handler1.sendMessage(msg);
            }
        },80,150);
    }

    private void iffirstrun() {
        SharedPreferences sharedPreferences = this.getSharedPreferences("share", MODE_PRIVATE);
        boolean isFirstRun = sharedPreferences.getBoolean("isFirstRun", true);
        SharedPreferences.Editor ed = sharedPreferences.edit();
        if (isFirstRun){//第一次運行就創建最高分文件
            Log.d("debug", "第一次運行");
            editor=getSharedPreferences("mybestscore",0).edit();
            editor.putString("bestscore",bestscore_show.getText().toString());
            editor.commit();
            ed.putBoolean("isFirstRun", false);
            ed.commit();
        }else{
            Log.d("debug", "不是第一次運行");
            String bestscore=getSharedPreferences("mybestscore",0).getString("bestscore","");
            bestscore_show.setText(bestscore);
            gv.setBscore(Integer.parseInt(bestscore));
        }
    }
}

  1. 佈局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="2048"
            android:textColor="#EE82EE"
            android:textSize="30dp"
            android:gravity="center_horizontal"
            android:textStyle="bold"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center_horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv_score_text"
            android:textSize="18dp"
            android:textColor="#000000"
            android:padding="8dp"
            android:text="得分:"/>

        <TextView
            android:id="@+id/tv_score_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="0"
            android:textColor="#000000"
            android:textSize="20dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18dp"
            android:textColor="#000000"
            android:layout_marginLeft="70dp"
            android:padding="8dp"
            android:text="最高分:"/>

        <TextView
            android:id="@+id/tv_bestscore_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="0"
            android:textColor="#000000"
            android:textSize="20dp" />

    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center_horizontal">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv_newganme"
            android:textSize="18dp"
            android:textColor="#000000"
            android:paddingTop="8dp"
            android:paddingLeft="20dp"
            android:text="新的一局" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18dp"
            android:textColor="#000000"
            android:paddingTop="8dp"
            android:paddingLeft="10dp"

            android:id="@+id/tv_rockback"
            android:text="我要反悔" />
    </LinearLayout>
    <com.example.minigame.GameView
        android:id="@+id/gv_show"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"/>
</LinearLayout>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章