21.2048小游戏

发布时间 2023-08-25 12:21:23作者: 被占用的小海海

跟着教学视频来做,但是视频不完整的,还缺一部分,后面的是我自己独自完成的,嘿嘿嘿
这是初步的作品,也就三百多行代码

package myGame2048;

public class StartGame_2048 {
    public static void main(String[] args) {
        new GameFrame_2048();
    }
}


package myGame2048;

import javax.swing.*;

public class GameFrame_2048 extends JFrame {
    public GameFrame_2048()  {
        add(new GamePanel_2048());

        setVisible(true);
        setSize(360,500);
        setTitle("2048小游戏");
        setLocationRelativeTo(null); // 居中
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

}


package myGame2048;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

public class GamePanel_2048 extends JPanel {


    // 二维数组存储4*4的卡片,这只是创建数组,没有创建具体的对象
    Card[][] allCards=new Card[4][4];
    int score;
    boolean isFail,isWin;

    public GamePanel_2048() {  // 生成对象必定调用构造器,且只执行一次
        init();
        setFocusable(true);  // 设置聚焦
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode=e.getKeyCode();
                switch (keyCode){
                    case KeyEvent.VK_UP: moveUp();  createRN();  getScore(); break;
                    case KeyEvent.VK_DOWN: moveDown();  createRN();  getScore(); break;
                    case KeyEvent.VK_LEFT:moveLeft(); createRN();  getScore(); break;
                    case KeyEvent.VK_RIGHT:moveRight(); createRN();  getScore();  break;
                    case KeyEvent.VK_SPACE:if (isFail==true || isWin==true) init();break;
                }
                repaint();
            }
        });// 键盘监听器

        // 为什么我的按钮有问题
        JButton jButton = new JButton("重新开始游戏");
        jButton.setVisible(true);
        jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                init();
                repaint();
            }
        });
        add(jButton);

    }
    public void init(){
        isFail=isWin=false;
        score=0;
        // 创建16个具体的Card对象,以及确定坐标
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                allCards[i][j]=new Card(i,j);
                // 依次创建16个Card对象.当重置游戏的时候,这些对象都会重新变为空白,变成泉下的对象
            }
        }
        createRN();
    }

    // 画笔
    @Override
    public void paint(Graphics g) {
        // 画出上面的界面
        g.setColor(Color.gray);
        g.fillRect(0,0,670,110);
        g.setColor(Color.cyan);
        g.fillRect(0,110,670,1000);
        g.setColor(Color.yellow);
        g.setFont(new Font("微软雅黑",Font.BOLD,30));
        g.drawString("2048",50,50);
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,30));
        g.drawString("分数:"+score,200,50);
        g.setColor(Color.black);
        g.setFont(new Font("宋体",Font.BOLD,15));
        g.drawString("按下键盘的上下左右进行游戏",10,80);
        // 画出16张卡片
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                // 卡片的位置
                Card card=allCards[i][j];
                g.setColor(setColor(card.num));
                g.fillRect(card.x,card.y,80,80);
                // 卡片上的数字,根据数字大小决定x的偏移量offset_x
                int offset_x = 0;
                if (card.num<10) {offset_x=25;}
                if (card.num>=10 && card.num<100) {offset_x=5;}
                if (card.num>=100 && card.num<1000) {offset_x=15;}
                if (card.num>=1000 && card.num<10000) {offset_x=10;}

                g.setColor(Color.black);
                g.setFont(new Font("微软雅黑", Font.BOLD, 50));
                if (card.num>0) g.drawString(""+card.num,card.x+offset_x,card.y+60);
            }
        }
        if (isFail==true){
            g.setColor(Color.red);
            g.setFont(new Font("宋体",Font.BOLD,20));
            g.drawString("游戏失败,按下空格重新开始游戏",10,100);
        }
        if (score==8){
            isWin=true;
            g.setColor(Color.pink);
            g.setFont(new Font("宋体",Font.BOLD,20));
            g.drawString("恭喜通关!按下空格重新开始游戏!",10,100);
        }
    }//画笔

    // 在没有数字的卡片( card.num==0)中随机地选择一张卡片,生成2(3/5概率)或者4(2/5概率)两个随机数字
    public void createRN(){
        isFail();
        if (isFail==false){
            int rn=new Random().nextInt(5); // 随机数random number:0,1,2,3,4
            if(rn==3 ||rn==3){
                rn=4;
            }else{rn=2;}
            randomCard().num=rn;
        }else System.out.println("游戏失败");
    }
    // 选出空的卡片
    public Card randomCard() { // 这里应该用异常来处理,因为再也没有没有空的卡牌的时候,游戏失败.这里就陷入了死循环
            Card card = allCards[new Random().nextInt(4)][new Random().nextInt(4)];
            if (card.num == 0) {
                return card;
            } else
                return randomCard();   // 递归,选出空的卡片}
    }



    // 根据卡片上的数字来决定卡片的颜色
    public Color setColor(int num) {
        Color color = null;
        switch (num) {
            case 0:
                color = new Color(92, 151, 117);
                break;
            case 2:
                color = Color.yellow;
                break;
            case 4:
                color = Color.red;
                break;
            case 8:
                color = Color.blue;
                break;
            case 16:
                color = Color.gray;
                break;
            case 32:
                color = Color.cyan;
                break;
            case 64:
                color = Color.lightGray;
                break;
            case 128:
                color = Color.pink;
                break;
            case 256:
                color = Color.blue;
                break;
            case 512:
                color = Color.orange;
                break;
            case 1024:
                color = Color.white;
                break;
            case 2048:
                color = Color.magenta;
                break;
        }
        return color;
    }

//---------------------------------------------------------------------------------------------------
    // 键盘监听器,控制卡片的移动
    public void moveUp(){
        for (int i = 1; i < 4; i++) {   // 最上层不需要移动,第二行最先开始移动
            for (int j = 0; j < 4; j++) {
                Card card=allCards[i][j];  // 当前的卡片
                if (card.num!=0) {
                    card.moveUp(allCards);
                }
            }
        }
    }
    public void moveDown(){
        for (int i = 2; i >=0; i--) {  // 第三行最先开始移动
            for (int j = 0; j < 4; j++) {
                Card card=allCards[i][j];  // 当前的卡片
                if (card.num!=0) {
                    card.moveDown(allCards);
                }
            }
        }
    }
    public void moveLeft(){   // 第二列最先开始移动
        for (int i = 0; i < 4 ; i++) {
            for (int j = 1; j < 4; j++) {
                Card card=allCards[i][j];  // 当前的卡片
                if (card.num!=0) {
                    card.moveLeft(allCards);
                }
            }
        }
    }
    public void moveRight(){   // 第三列最先开始移动
        for (int i = 0; i < 4; i++) {
            for (int j = 2; j >=0; j--) {
                Card card=allCards[i][j];  // 当前的卡片
                if (card.num!=0) {
                    card.moveRight(allCards);
                }
            }
        }
    }
//---------------------------------------------------------------------------------------------------
    // 游戏失败的判定
    public void isFail(){
        isFail=true;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                Card card=allCards[i][j];
                if (card.num==0){
                    isFail=false;  // 只要有任意一个为空格子,那么游戏就没有失败
                }
            }
        }
    }
    // 确定分数,在二维数组中得到最大值
    public void getScore(){
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (allCards[i][j].num>score)
                    score=allCards[i][j].num;
            }
        }
    }
}


package myGame2048;

public class Card {
    int x,y;  // 相对于面板的坐标
    int i,j;  // 在二维数组中的下标
    int num;  // 卡片的数字

    public Card(int i, int j) {
        this.i = i;
        this.j = j;
        // 确定每张卡片的坐标
        this.x=5+80*j+5*j;
        this.y=125+80*i+5*i;   // 边距为5
    }


    // 卡片移动,实际上是数字赋值
    public void moveUp(Card[][] allCards) {
        if (this.i==0) return;  // 递归结束的判定
        Card precard=allCards[i-1][j];  // 获得上一张卡片
        if (precard.num==0){
            precard.num=this.num;    // 为什么 precard变了,而那边的allCards[i-1][j] 也跟着改变
            this.num=0;
            precard.moveUp(allCards);  // 递归
        }
        // 合并数字
        if (precard.num==this.num && this.num!=0){
            precard.num*=2;
            this.num=0;
         //不需要   precard.moveUp(allCards);  // 递归
        }
    }
    public void moveDown(Card[][] allCards) {
        if (this.i==3) return;  // 递归结束的判定
        Card nextcard=allCards[i+1][j];  // 获得下一张卡片
        if (nextcard.num==0){
            nextcard.num=this.num;    // 为什么 precard变了,而那边的allCards[i-1][j] 也跟着改变
            this.num=0;
            nextcard.moveDown(allCards);  // 递归
        }
        if (nextcard.num==this.num && this.num!=0){
            nextcard.num*=2;
            this.num=0;
        }
    }
    public void moveLeft(Card[][] allCards) {
        if (this.j==0) return;  // 递归结束的判定
        Card leftcard=allCards[i][j-1];  // 获得下一张卡片
        if (leftcard.num==0){
            leftcard.num=this.num;    // 为什么 precard变了,而那边的allCards[i-1][j] 也跟着改变
            this.num=0;
            leftcard.moveLeft(allCards);  // 递归
        }
        if (leftcard.num==this.num && this.num!=0){
            leftcard.num*=2;
            this.num=0;
        }
    }
    public void moveRight(Card[][] allCards) {
        if (this.j==3) return;  // 递归结束的判定
        Card rightcard=allCards[i][j+1];  // 获得下一张卡片
        if (rightcard.num==0){
            rightcard.num=this.num;    // 为什么 precard变了,而那边的allCards[i-1][j] 也跟着改变
            this.num=0;
            rightcard.moveRight(allCards);  // 递归
        }
        if (rightcard.num==this.num && this.num!=0){
            rightcard.num*=2;
            this.num=0;
        }
    }

}