目录

  • 一、实现效果
  • 二、实现代码
  • 三、重难点讲解
    • 3.1 数字移动问题
    • 3.2 绘图问题---抗锯齿

一、实现效果

二、实现代码

Check表示格子,GameView实现游戏视图界面及功能,是核心。

Check.java

import java.awt.Color;
import java.awt.Font;// 方格类
public class Check {public int value;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);public Check() {value = 0; //value为方格中数字}//字体颜色public Color getForeground() {switch (value) {case 0:return new Color(0xcdc1b4);//0的颜色与背景色一致,相当于没有数字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 font1;}if (value < 100) {return font2;}if (value < 1000) {return font3;}if (value < 10000) {return font4;}return font5;}}

GameView.java

import java.awt.*;
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{private static final int jframeWidth = 405;//窗口宽高private static final int jframeHeight = 530;private static int score = 0;Font topicFont = new Font("微软雅黑", Font.BOLD, 50);//主题字体Font scoreFont = new Font("微软雅黑", Font.BOLD, 28);//得分字体Font explainFont = new Font("宋体", Font.PLAIN,20);//提示字体private JFrame jframeMain;private JLabel jlblTitle;private JLabel jlblScoreName;private JLabel jlblScore;private JLabel jlblTip;private GameBoard gameBoard;public GameView() {init();}public void init() {//1、创建窗口jframeMain = new JFrame("2048小游戏");jframeMain.setSize(jframeWidth, jframeHeight);jframeMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jframeMain.setLocationRelativeTo(null);//窗口显示位置居中jframeMain.setResizable(false);jframeMain.setLayout(null);//设置绝对布局,以便后面可以用setBounds设置位置jlblTitle = new JLabel("2048", JLabel.CENTER);jlblTitle.setFont(topicFont);jlblTitle.setForeground(Color.BLACK);jlblTitle.setBounds(50, 0, 150, 60);jframeMain.add(jlblTitle);//2、框架窗口搭建好,则需向里面开始添加内容//设置字体及其颜色、位置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);//3、得分区(得分名+分数)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);//4、提示说明区jlblTip = new JLabel("操作: ↑ ↓ ← →, 按esc键重新开始  ",JLabel.CENTER);jlblTip.setFont(explainFont);jlblTip.setForeground(Color.DARK_GRAY);jlblTip.setBounds(0, 60, 400, 40);jframeMain.add(jlblTip);//5、主游戏面板区gameBoard = new GameBoard();gameBoard.setBounds(0, 100, 400, 400);gameBoard.setBackground(Color.GRAY);gameBoard.setFocusable(true);//焦点即当前正在操作的组件,也就是移动的数字gameBoard.setLayout(new FlowLayout());jframeMain.add(gameBoard);}// 游戏面板class GameBoard extends JPanel implements KeyListener {private static final int CHECK_GAP = 10;//方格之间的间隙private static final int CHECK_SIZE = 85;//方格大小private static final int CHECK_ARC = 20;//方格弧度private Check[][] checks = new Check[4][4];private boolean isadd = true;public GameBoard() {initGame();addKeyListener(this);}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();}@Overridepublic void keyPressed(KeyEvent e) {switch (e.getKeyCode()) {case KeyEvent.VK_ESCAPE:initGame();//重新开始游戏(初始化游戏)break;case KeyEvent.VK_LEFT:moveLeft();createCheck();//调用一次方法创建一个方格数字judgeGameOver();//创建后判断是否GameOver,若所有格子均满即跳出GameOverbreak;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();//刷新,会自动调用paint()方法,重新绘制移动后的图}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:1int randomValue = random.nextInt(4);check.value = ( randomValue % 3 == 0 || randomValue % 3 == 1) ? 2 : 4;//只有[0,4)中的2才能生成4isadd = 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;}//是否全部格子占满,全部占满则GameOverprivate 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 void moveLeft() {//找到一个非空格子后checks[i][j].value > 0,可分为三种情况处理for (int i = 0; i < 4; i++) {for (int j = 1, index = 0; j < 4; j++) {if (checks[i][j].value > 0) {//第一种情况:checks[i][j](非第1列)与checks[i][index]的数相等,则合并乘以2,且得分增加if (checks[i][j].value == checks[i][index].value) {score += checks[i][index].value *= 2;checks[i][j].value = 0;isadd = true;} else if (checks[i][index].value == 0) {//第二种:若checks[i][index]为空格子,checks[i][j]就直接移到最左边checks[i][index]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]不为空格子,并且数字也不相等,若其旁边为空格子,则移到其旁边checks[i][index].value = checks[i][j].value;checks[i][j].value = 0;isadd = true;}}}}}private void 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 *= 2;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;}}}}}private void 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 *= 2;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;}}}}}private void 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 *= 2;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;}}}}}@Overridepublic 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);}}// GameOverif (judgeGameOver()) {g.setColor(new Color(64, 64, 64, 100));//RGBA最后一个A可以视为透明度g.fillRect(0, 0, getWidth(), getHeight());//填充矩形(游戏面板),将暗黑色填充上去g.setColor(Color.WHITE);g.setFont(topicFont);FontMetrics fms = getFontMetrics(topicFont);//FontMetrics字体测量,该类是Paint的内部类,通过getFontMetrics()方法可获取字体相关属性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());// 绘制圆角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中的一个方法,//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());//让数字居中显示}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}}public void showView() {jframeMain.setVisible(true);}}

Main.java

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

三、重难点讲解

3.1 数字移动问题

数字移动是一难点,分三种情况,以moveLeft()为例
(1)按左键,若最左边是相同的,则合并


(2)若左边是空格,则直接移动到最左即可

(3)若最左边不为空格,且不相等,则看它右边是否是空格,是则移动到其旁边

3.2 绘图问题—抗锯齿

java提供的Graphics 2D,它是Graphics 子类

Graphics2D gg = (Graphics2D) g;
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);

上面这两个语句实现的功能是消除文字锯齿,字体更清晰顺滑,可以看下图没有setRenderingHint和有setRenderingHint的区别

java实现2048小游戏(详细注解)相关推荐

  1. JAVA实现2048小游戏

    2048小游戏也算是一款好玩的益智休闲小游戏,下面本博主用 java 语言将该游戏复现,感兴趣的小伙伴点击 关注 哦! 同时博主还用 python 语言复现了该游戏,可点击以下链接浏览博主的另一篇文章 ...

  2. java编写2048小游戏

    java版2048小游戏 java编写2048小游戏 java编写2048小游戏 // An highlighted block /*** */ package games;/*** @author ...

  3. java编辑2048小游戏_Java 制作命令行版 2048小游戏

    Java 命令行版 2048小游戏(2020年8月14日) 制作背景 大二即将开学,从头开始学习了一个多月的java,对二维数组的操作稍微熟悉了一些.于是想做一个简单的2048来试一试. 众所周知,2 ...

  4. 【Java】 Java 实现 2048 小游戏

    闲暇之余再次做了一次2048.之前通过C语言完成过"2048游戏",因此java版采用了原C语言版的基本思路,学习认识了一些关于 Graphics 类和 Graphics2D 的一 ...

  5. java实现2048小游戏(源码+注释)

    实现文件 APP.java import javax.swing.*;public class APP {public static void main(String[] args) {new MyF ...

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

    运行效果: 1.项目结构 2.代码 BaseData接口 package com.hsy.game;import java.awt.*;public interface BaseData {Font ...

  7. Java实现2048小游戏,我竟然一盘都没赢,你们说我到底行不行?

    引言: 前几天偶尔看到了这个数字游戏,感觉还蛮有意思,就玩了一下,竟然赢不了,怎么玩都是输,真是邪门了,这不作为程序员员,我玩不赢我就自己写一个,行不行?我自己写的,我想赢就赢,条件我自己设定,就是玩 ...

  8. java2048小游戏源码及解析_200行java代码实现2048小游戏

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 效果图: 游戏介绍: 1.2048是一款益智类小游戏,刚开始随机出现两个数字,可以上下左右控制数字的移动. 2.当选 ...

  9. Python实现2048小游戏

    2048小游戏也算是一款好玩的益智休闲小游戏,下面本博主用 python 语言将该游戏复现,感兴趣的小伙伴点击 关注 哦! 同时博主还用 java 语言复现了该游戏,可点击以下链接浏览博主的另一篇文章 ...

最新文章

  1. pandas使用query函数基于dataframe字符串数据列中字符串的长度筛选dataframe的数据行(specific column string length)
  2. python 高阶函数
  3. LinkedHashMap和HashMap的比较使用 详解
  4. Linux命令整理 - 文件搜索【4】
  5. stm32L0工程建立(HAL+IAR,无cubemx)
  6. python颜色形状识别_Python自定义颜色形状Fi
  7. 3485. 最大异或和
  8. icmp报文格式_TCP/IP(二):IP报文格式详解
  9. vue是否可以做行车轨迹_在vue中高德地图引入和轨迹的绘制的实现
  10. 突发!百度张亚勤退休
  11. js高级技巧之函数节流
  12. mysql中类型转换
  13. 使用原理视角看 Git
  14. php中的冒泡排序和选择排序d
  15. div+css需要注意的问题
  16. java工控_用java做工控的大神进
  17. UE5 WebUI 5.0.1插件下载
  18. Excel 导入Access 不能找到表达式中引用的字段的解决方案
  19. MAC OS ssh key永久保存
  20. 微交易平台搭建开发-盘内实时K线对接

热门文章

  1. wx和sf是什么意思_网络上SF是啥意思?
  2. ASP - 三种常用分页
  3. 人与计算机猜数游戏,猜数字(古老的的密码破译类益智类小游戏)_百度百科...
  4. GPS载频信号简述(L1、L2、L3、L5)
  5. 滴滴代驾司机勇救人质 绍兴公安倡建纺城滴滴红袖章队伍
  6. 构造函数的概念及其如何使用
  7. 已知长方体相邻三个面的面积,求长方形的周长(数学公式)
  8. 输入法的重大突破:最易学又最快的顺手输入法问世了
  9. 《当幸福来敲门》经典台词
  10. 17、Health Check 健康检查