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即可

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 软件测试工程师自我介绍_软件测试工程师简历自我评价

    软件测试工程师自我介绍_软件测试工程师简历自我评价目录:导读一、前言:浅谈面试二、软件测试工程师:简历模板三、软件测试工程师:简历包装1.基本信息:2.教育背景:3.专业技能4.工作经历5.项目经验6.自我评价四、软件测试工程师:简历总结一、前言:浅谈面试面试是我们进入一个公司的门槛,通过了面试才能进入公司,你的面试结果和你的薪资是息息相关的。那如何才能顺利的通过面试,得到公司的认可呢?面试软件…

    2022年10月21日
  • Github搭建个人博客(2019最新版,亲测)

    Github搭建个人博客(2019最新版,亲测)版权声明:本文为徐代龙原创文章,未经徐代龙允许不得转载。https://blog.csdn.net/xudailong_blog/article/details/78762262(一)前言:建议:慢慢看,也就这一篇用心了点写说来话长,一把辛酸泪,可算是弄好了。1起因:在很早很早,大一的时候,估计快记不得日子了,那时候来到PC吧创业团队,一个大一级的学长通过…

  • LINUX下 Udev详解[通俗易懂]

    如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策略。在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev目录下。后来,采用了devfs,一个基于内核的动态设备文件系统,他首次出现在2.3.46内核中。Mandrake,Gentoo等Linux分发版本采用了这种方式。devfs创建的设备文件是动态的。但

  • for遍历list Python_不属于python循环语句的是

    for遍历list Python_不属于python循环语句的是for循环是最常用的循环语句,在各种高级编程语言中都会被频繁使用,在python中也不例外,除了常规的for循环或者嵌套的for循环语法以外,python还有一种精巧的list内的for循环语句的语法,如果能熟练掌握这种语法对提高编程的效率有很大的帮助,今天我给大家我给大家分享一些我收集的关于list内使用for循环的小技巧,希望对大家有所帮助:1.简单替换for循环它的主要语法结构如下:my_list=[表达式for循环项in循环体(if条件)]这里表达式可以为循环项,

  • jdk的动态代理机制_jdk动态代理

    jdk的动态代理机制_jdk动态代理摘要:    代理模式为其他对象提供了一种代理以控制对这个对象的访问,具体实现包括两大类:静态代理和动态代理。Java动态代理机制的出现使得Java开发人员只需要简单地指定一组接口及委托类对象便能动态地获得代理类,并且其所生成的代理类在将所有的方法调用分派到委托对象上反射执行的同时,还可以对方法进行增强,这也正是SpringAOP的实现基础。通过阅读本文,读者将会对代理模式和Java动态…

    2022年10月16日
  • 小程序直播开发文档_小程序直播平台

    小程序直播开发文档_小程序直播平台参考文档:https://www.cnblogs.com/pass245939319/p/9001137.html今天研究了新东西小程序的直播开发这个东西我研究了整整一下午快给我整哭了我的demo地址:https://github.com/AloneYan/WeChat-live.git下面进入正题首先你必须搞一个小程序公众平台的账号注册一个自己的小程序获得自己的…

发表回复

您的电子邮箱地址不会被公开。

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