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

网友投稿 264 2023-01-28

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

运行效果:

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.setLocationhttp://RelativeTo(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();

gahttp://meBoard.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 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;

}

}

// 获取空XqWYmwNrdp白方格

private List getEmptyChecks() {

List 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][iXqWYmwNrdp].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即可

总结

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:快递查询的免费api(在线查询快递)
下一篇:Java编写超时工具类实例讲解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~