Java实现2048小游戏(直接拿走运行)

Java实现2048小游戏(直接拿走运行)运行效果:1.项目结构2.代码BaseData接口packagecom.hsy.game;importjava.awt.*;publicinterfaceBaseData{FonttopicFont=newFont(“微软雅黑”,Font.BOLD,50);FontscoreFont=newFont(“微软雅黑”,Font.BOLD,28);FontnormalFont=newFont(“宋体”,Font.PLAI

大家好,又见面了,我是你们的朋友全栈君。

运行效果:
在这里插入图片描述
1.项目结构
在这里插入图片描述
2.代码
BaseData接口

package com.hsy.game;

import java.awt.*;

public interface BaseData { 
   
    Font topicFont = new Font("微软雅黑", Font.BOLD, 50);
    Font scoreFont = new Font("微软雅黑", Font.BOLD, 28);
    Font normalFont = new Font("宋体", Font.PLAIN, 20);
    Font font1 = new Font("宋体", Font.BOLD, 46);
    Font font2 = new Font("宋体", Font.BOLD, 40);
    Font font3 = new Font("宋体", Font.BOLD, 34);
    Font font4 = new Font("宋体", Font.BOLD, 28);
    Font font5 = new Font("宋体", Font.BOLD, 22);
    int normalFontData = 20;
    int topicFontData = 30;

    void init();
    void showView();
}

GameView类

package com.hsy.game;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class GameView implements BaseData{ 
   
    private static final int jFrameWidth = 400;
    private static final int jFrameHeight = 530;
    private static int score = 0;

    private JFrame jFrameMain;
    private JLabel jLblTitle;
    private JLabel jLblScoreName;
    private JLabel jLblScore;
    private GameBoard gameBoard;


    private JLabel jlblTip;

    public GameView() { 
   
        init();
    }

    @Override
    public void init() { 
   
        jFrameMain = new JFrame("2048小游戏");
        jFrameMain.setSize(jFrameWidth, jFrameHeight);
        jFrameMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrameMain.setLocationRelativeTo(null);
        jFrameMain.setResizable(false);
        jFrameMain.setLayout(null);

        jLblTitle = new JLabel("2048", JLabel.CENTER);
        jLblTitle.setFont(topicFont);
        jLblTitle.setForeground(Color.BLACK);
        jLblTitle.setBounds(50, 0, 150, 60);
        jFrameMain.add(jLblTitle);


        // 分数区
        jLblScoreName = new JLabel("得 分", JLabel.CENTER);
        jLblScoreName.setFont(scoreFont);
        jLblScoreName.setForeground(Color.WHITE);
        jLblScoreName.setOpaque(true);
        jLblScoreName.setBackground(Color.GRAY);
        jLblScoreName.setBounds(250, 0, 120, 30);
        jFrameMain.add(jLblScoreName);

        jLblScore = new JLabel("0", JLabel.CENTER);
        jLblScore.setFont(scoreFont);
        jLblScore.setForeground(Color.WHITE);
        jLblScore.setOpaque(true);
        jLblScore.setBackground(Color.GRAY);
        jLblScore.setBounds(250, 30, 120, 30);
        jFrameMain.add(jLblScore);

        // 说明:
        jlblTip = new JLabel("操作: ↑ ↓ ← →, 按esc键重新开始 ",
                JLabel.CENTER);
        jlblTip.setFont(normalFont);
        jlblTip.setForeground(Color.DARK_GRAY);
        jlblTip.setBounds(0, 60, 400, 40);
        jFrameMain.add(jlblTip);

        gameBoard = new GameBoard();
        gameBoard.setBounds(0, 100, 400, 400);
        gameBoard.setBackground(Color.GRAY);
        gameBoard.setFocusable(true);
        gameBoard.setLayout(new FlowLayout());
        jFrameMain.add(gameBoard);
    }

    // 游戏面板需要对键值实现侦听,
    // 这里采用内部类来继承 JPanel 类,
    // 并实现接口 KeyListener 中的 keyPressed 方法,
    // 方格是通过
    @SuppressWarnings("serial")
    class GameBoard extends JPanel implements KeyListener { 
   
        private static final int CHECK_GAP = 10;
        private static final int CHECK_ARC = 20;
        private static final int CHECK_SIZE = 86;

        private Check[][] checks = new Check[4][4];
        private boolean isAdd = true;

        public GameBoard() { 
   
            initGame();
            addKeyListener(this);
        }

        @Override
        public void keyPressed(KeyEvent e) { 
   
            switch (e.getKeyCode()) { 
   
                case KeyEvent.VK_ESCAPE:
                    initGame();
                    break;
                case KeyEvent.VK_LEFT:
                    moveLeft();
                    createCheck();
                    judgeGameOver();
                    break;
                case KeyEvent.VK_RIGHT:
                    moveRight();
                    createCheck();
                    judgeGameOver();
                    break;
                case KeyEvent.VK_UP:
                    moveUp();
                    createCheck();
                    judgeGameOver();
                    break;
                case KeyEvent.VK_DOWN:
                    moveDown();
                    createCheck();
                    judgeGameOver();
                    break;
                default:
                    break;
            }
            repaint();
        }

        private void initGame() { 
   
            score = 0;
            for (int indexRow = 0; indexRow < 4; indexRow++) { 
   
                for (int indexCol = 0; indexCol < 4; indexCol++) { 
   
                    checks[indexRow][indexCol] = new Check();
                }
            }
            // 生成两个数
            isAdd = true;
            createCheck();
            isAdd = true;
            createCheck();
        }

        private void createCheck() { 
   
            List<Check> list = getEmptyChecks();

            if (!list.isEmpty() && isAdd) { 
   
                Random random = new Random();
                int index = random.nextInt(list.size());
                Check check = list.get(index);
                // 2, 4出现概率3:1
                check.value = (random.nextInt(4) % 3 == 0) ? 2 : 4;
                isAdd = false;
            }
        }

        // 获取空白方格
        private List<Check> getEmptyChecks() { 
   
            List<Check> checkList = new ArrayList<>();
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 0; j < 4; j++) { 
   
                    if (checks[i][j].value == 0) { 
   
                        checkList.add(checks[i][j]);
                    }
                }
            }

            return checkList;
        }

        private boolean judgeGameOver() { 
   
            jLblScore.setText(score + "");

            if (!getEmptyChecks().isEmpty()) { 
   
                return false;
            }

            for (int i = 0; i < 3; i++) { 
   
                for (int j = 0; j < 3; j++) { 
   
                    //判断是否存在可合并的方格
                    if (checks[i][j].value == checks[i][j + 1].value
                            || checks[i][j].value == checks[i + 1][j].value) { 
   
                        return false;
                    }
                }
            }

            return true;
        }

        private boolean moveLeft() { 
   
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 1, index = 0; j < 4; j++) { 
   
                    if (checks[i][j].value > 0) { 
   
                        if (checks[i][j].value == checks[i][index].value) { 
   
                            score += checks[i][index++].value <<= 1;
                            checks[i][j].value = 0;
                            isAdd = true;
                        } else if (checks[i][index].value == 0) { 
   
                            checks[i][index].value = checks[i][j].value;
                            checks[i][j].value = 0;
                            isAdd = true;
                        } else if (checks[i][++index].value == 0) { 
   
                            checks[i][index].value = checks[i][j].value;
                            checks[i][j].value = 0;
                            isAdd = true;
                        }
                    }
                }
            }
            return isAdd;
        }

        private boolean moveRight() { 
   
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 2, index = 3; j >= 0; j--) { 
   
                    if (checks[i][j].value > 0) { 
   
                        if (checks[i][j].value == checks[i][index].value) { 
   
                            score += checks[i][index--].value <<= 1;
                            checks[i][j].value = 0;
                            isAdd = true;
                        } else if (checks[i][index].value == 0) { 
   
                            checks[i][index].value = checks[i][j].value;
                            checks[i][j].value = 0;
                            isAdd = true;
                        } else if (checks[i][--index].value == 0) { 
   
                            checks[i][index].value = checks[i][j].value;
                            checks[i][j].value = 0;
                            isAdd = true;
                        }
                    }
                }
            }

            return isAdd;
        }

        private boolean moveUp() { 
   
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 1, index = 0; j < 4; j++) { 
   
                    if (checks[j][i].value > 0) { 
   
                        if (checks[j][i].value == checks[index][i].value) { 
   
                            score += checks[index++][i].value <<= 1;
                            checks[j][i].value = 0;
                            isAdd = true;
                        } else if (checks[index][i].value == 0) { 
   
                            checks[index][i].value = checks[j][i].value;
                            checks[j][i].value = 0;
                            isAdd = true;
                        } else if (checks[++index][i].value == 0){ 
   
                            checks[index][i].value = checks[j][i].value;
                            checks[j][i].value = 0;
                            isAdd = true;
                        }
                    }
                }
            }

            return isAdd;
        }

        private boolean moveDown() { 
   
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 2, index = 3; j >= 0; j--) { 
   
                    if (checks[j][i].value > 0) { 
   
                        if (checks[j][i].value == checks[index][i].value) { 
   
                            score += checks[index--][i].value <<= 1;
                            checks[j][i].value = 0;
                            isAdd = true;
                        } else if (checks[index][i].value == 0) { 
   
                            checks[index][i].value = checks[j][i].value;
                            checks[j][i].value = 0;
                            isAdd = true;
                        } else if (checks[--index][i].value == 0) { 
   
                            checks[index][i].value = checks[j][i].value;
                            checks[j][i].value = 0;
                            isAdd = true;
                        }
                    }
                }
            }

            return isAdd;
        }

        @Override
        public void paint(Graphics g) { 
   
            super.paint(g);
            for (int i = 0; i < 4; i++) { 
   
                for (int j = 0; j < 4; j++) { 
   
                    drawCheck(g, i, j);
                }
            }

            // GameOver
            if (judgeGameOver()) { 
   
                g.setColor(new Color(64, 64, 64, 150));
                g.fillRect(0, 0, getWidth(), getHeight());
                g.setColor(Color.WHITE);
                g.setFont(topicFont);
                FontMetrics fms = getFontMetrics(topicFont);
                String value = "Game Over!";
                g.drawString(value,
                        (getWidth()-fms.stringWidth(value)) / 2,
                        getHeight() / 2);
            }
        }

        // 绘制方格
        // Graphics2D 类扩展了 Graphics 类,
        // 提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
        private void drawCheck(Graphics g, int i, int j) { 
   
            Graphics2D gg = (Graphics2D) g;
            gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_NORMALIZE);
            Check check = checks[i][j];
            gg.setColor(check.getBackground());
            // 绘制圆角
            // x - 要填充矩形的 x 坐标。
            // y - 要填充矩形的 y 坐标。
            // width - 要填充矩形的宽度。
            // height - 要填充矩形的高度。
            // arcwidth - 4 个角弧度的水平直径。
            // archeight - 4 个角弧度的垂直直径。
            gg.fillRoundRect(CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * j,
                    CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * i,
                    CHECK_SIZE, CHECK_SIZE, CHECK_ARC, CHECK_ARC);
            gg.setColor(check.getForeground());
            gg.setFont(check.getCheckFont());

            // 对文字的长宽高测量。
            FontMetrics fms = getFontMetrics(check.getCheckFont());
            String value = String.valueOf(check.value);
            //使用此图形上下文的当前颜色绘制由指定迭代器给定的文本。
            //getAscent()是FontMetrics中的一个方法,
            //它返回某字体的基线(baseline)到该字体中大多数字符的升部(ascender)之间的距离
            //getDescent 为降部
            gg.drawString(value,
                    CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * j +
                            (CHECK_SIZE - fms.stringWidth(value)) / 2,
                    CHECK_GAP + (CHECK_GAP + CHECK_SIZE) * i +
                            (CHECK_SIZE - fms.getAscent() - fms.getDescent()) / 2
                            + fms.getAscent());
        }

        @Override
        public void keyReleased(KeyEvent e) { 
   
        }

        @Override
        public void keyTyped(KeyEvent e) { 
   
        }

    }

    @Override
    public void showView() { 
   
        jFrameMain.setVisible(true);
    }

}

Check类

package com.hsy.game;

import java.awt.Color;
import java.awt.Font;


public class Check { 
   
    public int value;

    public Check() { 
   
        clear();
    }

    public void clear() { 
   
        value = 0;
    }

    public Color getForeground() { 
   
        switch (value) { 
   
            case 0:
                return new Color(0xcdc1b4);
            case 2:
            case 4:
                return Color.BLACK;
            default:
                return Color.WHITE;
        }
    }

    public Color getBackground() { 
   
        switch (value) { 
   
            case 0:
                return new Color(0xcdc1b4);
            case 2:
                return new Color(0xeee4da);
            case 4:
                return new Color(0xede0c8);
            case 8:
                return new Color(0xf2b179);
            case 16:
                return new Color(0xf59563);
            case 32:
                return new Color(0xf67c5f);
            case 64:
                return new Color(0xf65e3b);
            case 128:
                return new Color(0xedcf72);
            case 256:
                return new Color(0xedcc61);
            case 512:
                return new Color(0xedc850);
            case 1024:
                return new Color(0xedc53f);
            case 2048:
                return new Color(0xedc22e);
            case 4096:
                return new Color(0x65da92);
            case 8192:
                return new Color(0x5abc65);
            case 16384:
                return new Color(0x248c51);
            default:
                return new Color(0x248c51);
        }
    }

    public Font getCheckFont() { 
   
        if (value < 10) { 
   
            return BaseData.font1;
        }
        if (value < 100) { 
   
            return BaseData.font2;
        }
        if (value < 1000) { 
   
            return BaseData.font3;
        }
        if (value < 10000) { 
   
            return BaseData.font4;
        }

        return BaseData.font5;
    }

}

Test类

package com.hsy.game;

public class Test { 
   
    public static void main(String[] args) { 
   
        new GameView().showView();
    }
}

运行Test即可

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159839.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • win7 boot设置_重装系统boot missing

    win7 boot设置_重装系统boot missing转自 http://blog.wsdd.org/安装linux,vista/win7双系统后,怎么引导是个问题理论上,可以从windows的bootloader引导linux,也可以linux的grub引导windows但windows更霸道,经常霸占MBR,所以最好是linux不放MBR,然后从windows的bootloader引导linux把linux装在自己的分区,不要

    2022年10月12日
    0
  • foc无刷电机位置控制(直流无刷电机接线图解)

    序:矢量控制的核心思想是为了简化无刷电机的控制模型,将一个需要换相的无刷电机通过各种算法变换,抽象为一个直流电机的控制模型,只需要控制简单的两个直流分量来控制无刷电机,其中Vq抽象为直流电机的两端电压,Vd可调节电机力矩,但这个模型需要一个实时的电机轴角度θ参与计算。为了实现这个直流电机的控制模型,需要用到两个数学变换,即clarke变换和park变换。需要用到最原始的PID控制器等内容。…

    2022年4月11日
    383
  • java毕业设计_校园二手交易平台

    java毕业设计_校园二手交易平台校园二手交易平台mysql数据库创建语句校园二手交易平台oracle数据库创建语句校园二手交易平台sqlserver数据库创建语句校园二手交易平台spring+springMVC+hibernate框架对象(javaBean,pojo)设计校园二手交易平台spring+springMVC+mybatis框架对象(javaBean,pojo)设计校园二手交易平台登录注册界面校园二手交易平…

    2022年6月16日
    18
  • Django(50)drf异常模块源码分析

    Django(50)drf异常模块源码分析异常模块源码入口APIView类中dispatch方法中的:response=self.handle_exception(exc)源码分析我们点击handle_exception跳转,查看该

    2022年7月30日
    6
  • 理解ABA问题_什么叫ABA

    理解ABA问题_什么叫ABA理解ABA问题1ABA问题的产生2原子引用AtomicReference3带时间戳的原子引用AtomicStampedReference解决ABA问题1ABA问题的产生所谓ABA问题,就是比较并交换的循环,存在一个时间差,而这个时间差可能带来意想不到的问题。比如线程1和线程2同时也从内存取出A,线程T1将值从A改为B,然后又从B改为A。线程T2看到的最终值还是A,经过与预估值的比较,二者相等,可以更新,此时尽管线程T2的CAS操作成功,但不代表就没有问题。有的需求,比如CAS,只注重头

    2025年6月8日
    0
  • Maven cmd 打包命令

    Maven cmd 打包命令转载:https://blog.csdn.net/qq_34927809/article/details/80108376cd到需要打包项目的pom.xml文件下:输入mvncleaninstall-Dmaven.test.skip=true-Dmaven.javadoc.skip=true打包到本地项目的target下面…

    2022年6月5日
    67

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号