Adorid实现2048小游戏

Android实现2048游戏



1.框架

利用安卓开发2048小游戏
在这里插入图片描述

2.实现效果图

在这里插入图片描述
在这里插入图片描述

3.代码

MainActivity

public class MainActivity extends Activity {
    
    

    public static MainActivity mainActivity = null;
    private int score = 0;
    public TextView tvScore;
    public TextView tvHScore;
    public Button restartBtn ;
    int count =0 ;
    private Map<String,Integer> userinfo;
    public static MainActivity getMainActivity() {
    
    
        return mainActivity;
    }

    public MainActivity() {
    
    
        mainActivity = this;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvScore = (TextView) findViewById(R.id.tvScore);
        tvHScore = (TextView) findViewById(R.id.tvHScore);
        tvHScore.setText(getHighestSore()+"分");
        count = userinfo.get("nowcount");

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    
    
        // Inflate the menu; this adds items to the action bar if it is present.

        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    
    
        switch (item.getItemId()){
    
    
            case R.id.action_back:
                finish();
                break;
            case R.id.action_myrecord:
                startActivity(new Intent(MainActivity.this,Game_Record.class));
                break;
            default:
                break;
        }
        return true;
    }

    public void clearScore(){
    
    
        RefreshHightScore();
        score = 0;
        showScore();
    }

    public void showScore(){
    
    
        tvScore.setText(score+" 分");
        tvHScore.setText(getHighestSore() + "分");
    }

    public void addScore(int s){
    
    
        score+=s;
        showScore();
    }

    public int getHighestSore(){
    
    
        int Mnum=0;
        //获取记录的最高分
        userinfo = SPSave.getUserInfo(MainActivity.this);
        if(userinfo.get("HightestScore")!=null){
    
    
         Mnum   = userinfo.get("HightestScore");
        }
        return Mnum;
    }
    public void RefreshHightScore(){
    
    
        int Max = getHighestSore();
        if(score>Max){
    
    
            Max = score;
        }
        SPSave.savedUserInfo(MainActivity.this,score,Max,count);//更新最高分
    }
   public int getScore(){
    
    
        return score;
   }
}

GameView

public class GameView extends GridLayout {
    
     // 2048游戏主类 让这个类绑定xml

    private Card[][] cardsMap = new Card[4][4]; // 用一个二维数组来记录下方阵
    private List<Point> emptyPoints = new ArrayList<Point>(); // 把所有的位置(空点的位置)全放在一个数组里面,方便随机地去取

    // 为了能让这个GameView从xml文件中能够访问到,要添加构造方法(能传入相关属性的构造方法),为了保险起见,最好把它的三个构造方法都添加上
    public GameView(Context context, AttributeSet attrs, int defStyle) {
    
     // 构造函数
        super(context, attrs, defStyle);
        initGameView(); // 初始化
    }

    public GameView(Context context) {
    
     // 构造函数
        super(context);
        initGameView();
    }

    public GameView(Context context, AttributeSet attrs) {
    
     // 构造函数
        super(context, attrs);
        initGameView();
    }
    public void addReButton(){
    
    
        Button re = new Button(getContext());
        re.setWidth(GetCardWidth());
        re.setHeight(20);
        re.setText("Restart!");
        re.setBackgroundColor(Color.parseColor("#A3D6CC"));
        re.setOnClickListener(new OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                startGame();
            }
        });
        addView(re);
    }
    private void initGameView() {
    
     // 初始化

        setColumnCount(4); // 指明GridLayout布局是4列的
        setRowCount(5);
        setBackgroundColor(Color.parseColor("#A3D6CC")); // 配置GameView的背景或颜色

        addCards(GetCardWidth(),GetCardWidth());
        addReButton();
        setOnTouchListener(new View.OnTouchListener() {
    
     // 设置交互方式
            // 监听上下左右滑动的这几个动作,再由这几个动作去执行特定的代码,去实现游戏的逻辑

            private float startX, startY, offsetX, offsetY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
    
    

                switch (event.getAction()) {
    
    
                    case MotionEvent.ACTION_DOWN:
                        startX = event.getX();
                        startY = event.getY();
                        break;
                    case MotionEvent.ACTION_UP:
                        offsetX = event.getX() - startX;
                        offsetY = event.getY() - startY;

                        if (Math.abs(offsetX) > Math.abs(offsetY)) {
    
     // 加此判断是为了解决当用户向斜方向滑动时程序应如何判断的问题

                            if (offsetX < -5) {
    
    
                                swipeLeft();
                                // System.out.println("left");
                            } else if (offsetX > 5) {
    
    
                                swipeRight();
                                // System.out.println("right");
                            }

                        } else {
    
     // 判断向上向下

                            if (offsetY < -5) {
    
    
                                swipeUp();
                                // System.out.println("up");
                            } else if (offsetY > 5) {
    
    
                                swipeDown();
                                // System.out.println("down");
                            }

                        }
                        break;
                }

                return true; // 此处必须返回true,如返回false,则只会监听到MotionEvent.ACTION_DOWN这个事件,返回此事件没有成功,所以后面的事件也不会发生
            }
        });
    }
    private int GetCardWidth()
    {
    
    

        //屏幕信息的对象
        DisplayMetrics displayMetrics;
        displayMetrics = getResources().getDisplayMetrics();

        //获取屏幕信息
        int cardWidth;
        cardWidth = displayMetrics.widthPixels;

        //一行有四个卡片,每个卡片占屏幕的四分之一
        return ( cardWidth - 10 ) / 4;

    }
    // 只有第一次创建的时候才会执行一次 只可能会执行一次
    // 手机横放的时候不会执行,因为布局宽高不会发生改变,在AndroidManifest文件中配置了横放手机布局不变的参数
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    
     // 动态计算卡片宽高
        super.onSizeChanged(w, h, oldw, oldh);

        int cardWidth = (Math.min(w, h) - 10) / 4;
        int cardHeight = cardWidth;
        startGame();
//        addCards(cardWidth, cardHeight);

        // 因为第一次创建游戏时,onSizeChanged()会被调用,且仅被调用一次,所以在这里开启游戏很合适

    }

    private void addCards(int cardWidth, int cardHeight) {
    
    

        Card card;

        for (int y = 0; y < 4; y++) {
    
    
            for (int x = 0; x < 4; x++) {
    
    
                card = new Card(getContext());
                card.setNum(0); // 刚开始全部添加0 此时并不会显示数字

                addView(card, cardWidth, cardHeight); // card是一个继承自FrameLayout的View
                // 在initGameView()中指明这个GridLayout是四列的方阵
                cardsMap[x][y] = card;
            }
        }
    }

    private void startGame() {
    
     // 开启游戏 若重新开始游戏的话就要先清理,清理完成后添加随机数

        MainActivity.getMainActivity().clearScore(); // 刚开始分数清零

        for (int y = 0; y < 4; y++) {
    
     // 对所有值进行清理
            for (int x = 0; x < 4; x++) {
    
    
                cardsMap[x][y].setNum(0);
            }
        }
        addRandomNum(); // 需要添加两次 两个随机数
        addRandomNum();
    }

    private void addRandomNum() {
    
     // 添加随机数 首先需要遍历所有卡片

        emptyPoints.clear(); // 添加随机数之前先清空emptyPoints,然后把每一个空点都添加进来

        for (int y = 0; y < 4; y++) {
    
    
            for (int x = 0; x < 4; x++) {
    
    

                if (cardsMap[x][y].getNum() <= 0) {
    
    
                    emptyPoints.add(new Point(x, y)); // 把空点的位置添加进去
                    // 因为只有空点才能够去添加数字
                    // 已经有数字的话肯定不会去添加了
                }

            }
        }

        Point p = emptyPoints
                .remove((int) (Math.random() * emptyPoints.size())); // 随机地移除一个点
        // 注意这里仅仅是移除emptyPoints中记录的点了,并没有移除card
        cardsMap[p.x][p.y].setNum(Math.random() > 0.1 ? 2 : 4); // 给这个空点添加一个数,2或4,概率为9:1

    }

    // 实现游戏逻辑 只要有位置的改变就添加新的 最重要的部分:游戏逻辑
    private void swipeLeft() {
    
    

        boolean merge = false; // 判断是否有合并,如果有的话就进行一些处理

        for (int y = 0; y < 4; y++) {
    
    
            for (int x = 0; x < 4; x++) {
    
    
                for (int x1 = x + 1; x1 < 4; x1++) {
    
     // 从当前的位置往右边去遍历

                    if (cardsMap[x1][y].getNum() > 0) {
    
     // 如果往右去遍历得到的card的值(获取到的值)不是空的,则做如下逻辑判断

                        if (cardsMap[x][y].getNum() <= 0) {
    
     // 如果当前位置上的值是空的,则将获取到的值移动到当前位置上
                            cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
                            cardsMap[x1][y].setNum(0);

                            x--; // 这里非常重要!!!! 可以测试理解
                            merge = true;
                        } else if (cardsMap[x][y].equals(cardsMap[x1][y])) {
    
     // 如果当前位置上的值不是空的,而且获取到的值与当前位置上的值相等,则做相加处理,并将结果放在当前位置上
                            cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
                            cardsMap[x1][y].setNum(0);

                            // 合并时加分 有合并就有添加(分数)
                            MainActivity.getMainActivity().addScore(
                                    cardsMap[x][y].getNum());
                            merge = true;
                        }
                        break; // 这个break的位置非常重要!!!!! 只能写在这里!! eg:方格最下面一行是2 32
                        // 64 2,然后往左滑动的情况!
                    }
                }
            }
        }

        if (merge) {
    
     // 在添加数字时判断游戏是否结束
            addRandomNum();
            checkComplete(); // 添加新项后都要检查游戏是否结束:没空位置,而且已经不能再合并
        }
    }

    private void swipeRight() {
    
    

        boolean merge = false;

        for (int y = 0; y < 4; y++) {
    
    
            for (int x = 3; x >= 0; x--) {
    
    
                for (int x1 = x - 1; x1 >= 0; x1--) {
    
    
                    if (cardsMap[x1][y].getNum() > 0) {
    
     // 不是空的

                        if (cardsMap[x][y].getNum() <= 0) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
                            cardsMap[x1][y].setNum(0);

                            x++;

                            merge = true;

                        } else if (cardsMap[x][y].equals(cardsMap[x1][y])) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
                            cardsMap[x1][y].setNum(0);

                            // 合并时加分
                            MainActivity.getMainActivity().addScore(
                                    cardsMap[x][y].getNum());

                            merge = true;
                        }

                        break;

                    }
                }
            }
        }

        if (merge) {
    
    
            addRandomNum();
            checkComplete();
        }

    }

    private void swipeUp() {
    
    

        boolean merge = false;

        for (int x = 0; x < 4; x++) {
    
    
            for (int y = 0; y < 4; y++) {
    
    
                for (int y1 = y + 1; y1 < 4; y1++) {
    
    

                    if (cardsMap[x][y1].getNum() > 0) {
    
     // 不是空的

                        if (cardsMap[x][y].getNum() <= 0) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
                            cardsMap[x][y1].setNum(0);

                            y--;

                            merge = true;

                        } else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
                            cardsMap[x][y1].setNum(0);

                            // 合并时加分
                            MainActivity.getMainActivity().addScore(
                                    cardsMap[x][y].getNum());

                            merge = true;

                        }

                        break;

                    }
                }
            }
        }

        if (merge) {
    
    
            addRandomNum();
            checkComplete();
        }

    }

    private void swipeDown() {
    
    

        boolean merge = false;

        for (int x = 0; x < 4; x++) {
    
    
            for (int y = 3; y >= 0; y--) {
    
    
                for (int y1 = y - 1; y1 >= 0; y1--) {
    
    
                    if (cardsMap[x][y1].getNum() > 0) {
    
     // 不是空的

                        if (cardsMap[x][y].getNum() <= 0) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
                            cardsMap[x][y1].setNum(0);

                            y++;

                            merge = true;

                        } else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
    
    
                            cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
                            cardsMap[x][y1].setNum(0);

                            // 合并时加分
                            MainActivity.getMainActivity().addScore(
                                    cardsMap[x][y].getNum());

                            merge = true;

                        }

                        break;

                    }
                }
            }
        }

        if (merge) {
    
    
            addRandomNum();
            checkComplete();
        }

    }

    // 判断游戏是否结束的逻辑
    private void checkComplete() {
    
    

        boolean complete = true;

        All: for (int y = 0; y < 4; y++) {
    
    
            for (int x = 0; x < 4; x++) {
    
    

                // 游戏没有结束的判定情况 5种情况
//                if (cardsMap[x][y].getNum() == 0
//                        || (x > 0 && cardsMap[x][y].equals(cardsMap[x - 1][y]))
//                        || (x < 3 && cardsMap[x][y].equals(cardsMap[x + 1][y]))
//                        || (y > 0 && cardsMap[x][y].equals(cardsMap[x][y - 1]))
//                        || (y < 3 && cardsMap[x][y].equals(cardsMap[x][y + 1]))) {
    
    
//
//                    complete = false;
//                    break All; // 写一个标签,跳出所有循环
//                }
                if(cardsMap[x][y].getNum()==0){
    
    
                    complete = false;
                    break All;
                }
            }
        }

        if (complete) {
    
    
            AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
            dialog.setTitle("你好")
                    .setMessage("游戏结束")
                    .setPositiveButton("重来",
                            new DialogInterface.OnClickListener() {
    
    

                                @Override
                                public void onClick(DialogInterface dialog,
                                                    int which) {
    
    
                                    startGame();
                                }
                            });
//
//            dialog.setNegativeButton("退出游戏", new DialogInterface.OnClickListener() {
    
    
//
//                @Override
//                public void onClick(DialogInterface dialog, int which) {
    
    
//                    MainActivity.getMainActivity().RefreshHightScore();
//                    MainActivity.getMainActivity().finish();
//                }
//            });
            dialog.show();
        }

    }

}

Card

public class Card extends FrameLayout {
    
    

    public Card(Context context) {
    
    

        super(context);
        label = new TextView(getContext());
        label.setTextSize(32);
        label.setBackgroundColor(0x33ffffff);
        label.setGravity(Gravity.CENTER);
        LayoutParams lp = new LayoutParams(-1, -1);
        lp.setMargins(10, 10, 0, 0);
        addView(label, lp);
        setNum(0);

    }


    private int num = 0;
    private String[] colorlist =  {
    
    "#E6C0C0","#A4A8D4","#FFF3B8","#E5C1CD","#6C9BD2","#FAC559","#E6EB94","#A3D6CC","#ffcc33","#66ff66","#B4EEB4"};


    public int getNum() {
    
    
        return num;
    }

    public void setNum(int num) {
    
    
        this.num = num;

        if (num<=0) {
    
    
            label.setText("");
            label.setBackgroundColor(0x33ffffff);
        }else{
    
    
            label.setText(num+"");
            label.setBackgroundColor(Color.parseColor(colorlist[num%11]));
        }
    }

    public boolean equals(Card o) {
    
    
        return getNum()==o.getNum();
    }

    private TextView label;
}

GameRecord

public class Game_Record extends Activity {
    
    
    private Map<String,String> userMap = new HashMap<String,String>();
    private ListView mListView ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        userMap = SPSave.getUserRecord(getBaseContext());   //获取context??
        super.onCreate(savedInstanceState);
//        Toast.makeText(Game_Record.this, "Gamerecord", Toast.LENGTH_SHORT).show();
        setContentView(R.layout.activity_gamerecord);

        mListView = (ListView) findViewById(R.id.recordlist);
        //创建一个内部类实例
        MylistAdapter mAdapter = new MylistAdapter();
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
    
    
            @Override
            public void onItemClick(AdapterView<?> AdapterView, View view, int position, long id) {
    
    
                Toast.makeText(Game_Record.this, "Toast点击显示第"+position+"个item", Toast.LENGTH_SHORT).show();
            }
        });
    }


    //创建自定义适配器
    class MylistAdapter extends BaseAdapter{
    
    


        @Override
        public int getCount() {
    
    
            return userMap.size()/2;
        } //因为同时保存时间和分数,所以需要/2

        @Override
        public Object getItem(int position) {
    
    
            return position;
        }

        @Override
        public long getItemId(int position) {
    
    
           return  position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
    
            //获取view对象
            View view = View.inflate(Game_Record.this,R.layout.resordlist_item,null);
            TextView mTextView  = (TextView) view.findViewById(R.id.score_ed);
            TextView mTimeView = (TextView) view.findViewById(R.id.score_time);

            if(userMap.get("score"+position)!=null){
    
    
                mTextView.setText(userMap.get("score"+position)+"分");
                mTimeView.setText(userMap.get("time"+position));
            }
            ImageView imageView = (ImageView) view.findViewById(R.id.item_image);
//            imageView.setBackgroundResource();
            return view;
        }
    }
}

SPSave

//问题:关于记录的关键id,无法确定保存,不知道该如何确定当前应该保存的id,本实验中利用count记录,但不知道如何获取缺少的id,即用户上次退出游戏所应该保存的记录应该是第几条
//每次用户开始游戏,都将从第一条记录开始修改,直到保存到15条为止,循环更新
public class SPSave {
    
    
    public static boolean savedUserInfo(Context context, int score,int hightscore,int count){
    
    
        SharedPreferences sp = context.getSharedPreferences("scoredata",Context.MODE_PRIVATE);
        SharedPreferences.Editor edit = sp.edit();
        count=count%15;   //最多保存15条记录
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM月dd日 HH:mm:ss");// HH:mm:ss//获取当前时间
        Date date = new Date(System.currentTimeMillis());
        edit.putString("time"+count, simpleDateFormat.format(date));
        edit.putInt("HightestScore",hightscore);
        edit.putString("score"+count, String.valueOf(score));
        count++;
        edit.putInt("nowcount",count);  //注意要在存放之前就把count修改不然count永远是0

        edit.commit();
        return true;
    }
    public static Map<String,Integer> getUserInfo(Context context){
    
    
        SharedPreferences sp = context.getSharedPreferences("scoredata",Context.MODE_PRIVATE);
        int hightestScore = sp.getInt("HightestScore",0);
        int count = sp.getInt("nowcount",0);
        Map<String,Integer> userMap = new HashMap<String,Integer>();
        userMap.put("HightestScore",hightestScore);
        userMap.put("nowcount",count);
        return userMap;
    }
    public static Map<String,String> getUserRecord(Context context){
    
    
        SharedPreferences sp = context.getSharedPreferences("scoredata",Context.MODE_PRIVATE);
        //获取保存数据,遍历获取。
        Map<String,String> userMap = new HashMap<String,String>();
        for(int i=0;i<10;i++){
    
    
            String score= sp.getString("score"+i,null);
            String time = sp.getString("time"+i,null);
            if(score!=null){
    
    
                userMap.put("score"+i,score);
            }
            if(time!=null){
    
    
                userMap.put("time"+i,time);
            }
        }
        return userMap;
    }
}

4.总结

1.关于listview无法显示的问题 :定义的适配器类,加载时的getCount() 和getItem() 方法出了问题,只是快捷键实现了需要重写的方法,没有具体实现,直接return 0 了,就没有办法正常显示
2.对Map<> 数据类型 的使用不熟悉,导致花费了很多时间来做无用功
3.对于通过 SharedPreferences sp=context.getSharedPreferences(“scoredata”,Context.MODE_PRIVATE);存取数据不熟悉,事先没有对需要存取的数据进行准确的分析,也是绕了很多弯。
4.对于Gridlayout和RelativeLayout布局不熟悉

代码链接

代码链接
链接:https://pan.baidu.com/s/1F-VLfkApCxjIaSIrRh4-Vw
提取码:y8du

猜你喜欢

转载自blog.csdn.net/m0_45948011/article/details/121346027