前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【java】百行代码 实现2048小游戏

【java】百行代码 实现2048小游戏

作者头像
韩旭051
发布2020-06-23 11:13:14
2K0
发布2020-06-23 11:13:14
举报
文章被收录于专栏:刷题笔记

2048的代码不是我写的,是从牛客网的项目平台找到的项目

项目代码链接(代码放在了文章最后)

https://git.nowcoder.com/11000160/2048-java/blob/master/Game2048.java

录制的效果图:

游戏逻辑分析

2048大家都玩过,我就不介绍了,没玩过了可以去玩儿一下,直接说游戏的逻辑

1.通过上、下、左、右移动,使相邻的相同元素进行合并,进而数字相加得到 2048的结果的游戏。

2.每次生成得到数字块是 2或4 ,生成的位置是在空白位置随机出现。

3.游戏最开始随机出现两个数字块

4.每次传入一个移动方向(上下左右),所有数字块都向该方向移动直到边界,相同两个数字块会合并成两数之和变成一个数字块。

5.若移动后没有一个数字块发生位移则移动无效,不会产生新数字块。

6.当场景没有空位且无法移动则游戏失败。

7.游戏分数为场景内最大的数字,当数字为2048时游戏结束。

代码的分析

感觉代码已经很简洁了 200来行就能写出这个游戏。

简易的思维导图

文字版

Game2048

main主方法

SwingUtilities.invokeLater(() -> {

JFrame f = new JFrame();

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE可以关闭窗口);

f.setTitle("2048");设置窗口标题

f.setResizable(true);面板可以调节

f.add(new Game2048(), BorderLayout.CENTER);把游戏放入面板

f.pack();

f.setLocationRelativeTo(null);

f.setVisible(true);可见

});

class Tile数字块类

数字块类

private boolean merged;是否合并

private int value;值

构造方法

  • Tile(int val) {
    • value = val;

get 和set方法

  • getValue()
  • setMerged(boolean m)

canMergeWith(Tile other)判断两个块是否可合并

  • return !merged && other != null && !other.merged && value == other.getValue();
  • 值相等,另一块不是空,本次移动没有和另一块合并,都可以合并

int mergeWith(Tile other) {合并方法

  • if (canMergeWith(other)) {
    • value *= 2;合并值翻倍
    • merged = true;
    • return value;
  • return -1;

movesAvailable判断是否可以移动

clearMerged清楚面板

遍历所有格子 设置false

变量

State静态成员

  • start, won, running, over游戏状态

colorTable颜色库

  • new Color(0x701710), new Color(0xFFE4C3), new Color(0xfff4d3),
  • new Color(0xffdac3), new Color(0xe7b08e), new Color(0xe7bf8e),
  • new Color(0xffc4c3), new Color(0xE7948e), new Color(0xbe7e56),
  • new Color(0xbe5e56), new Color(0x9c3931), new Color(0x701710)};

final static int target = 2048;目标分数

static int highest;游戏高度

static int score;游戏分数

private Color gridColor = new Color(0xBBADA0);方格颜色

private Color emptyColor = new Color(0xCDC1B4);空颜色

private Color startColor = new Color(0xFFEBCD);开始颜色

private Random rand = new Random();随机数

private Tile tiles;数字块数组 存放全部数字块

private int side = 4;格子大小4*4

private State gamestate = State.start;游戏状态

private boolean checkingAvailableMoves;可否移动状态

Game2048构造方法

setPreferredSize(new Dimension(900, 700));

setBackground(new Color(0xFAF8EF));

setFont(new Font("SansSerif", Font.BOLD, 48));

setFocusable(true);

监听鼠标

监听键盘

paintComponent绘制组件

初始化画图

setRenderingHint抗锯齿

startGame开始游戏

if (gamestate != State.running) {

score = 0;

highest = 0;

gamestate = State.running;

tiles = new Tileside;

addRandomTile();

addRandomTile();

}

drawGrid绘制面板

g.setColor(gridColor);设置颜色

g.fillRoundRect(200, 100, 499, 499, 15, 15);填充背景

判断游戏状态

drawTile绘制数字块

fillRoundRect在二维面板 r行c列画value

addRandomTile随机生成数字块

随机找空位置添加 4或2

move移动数字块

根据方向进行移动

移动后序处理

  • if (moved) {
  • if (highest < target) {
  • clearMerged();
  • addRandomTile();
  • if (!movesAvailable()) {
  • gamestate = State.over;
  • }
  • } else if (highest == target)
  • gamestate = State.won;
  • }

一系列移动方法

boolean moveUp() {

  • return move(0, -1, 0);

boolean moveDown() {

  • return move(side * side - 1, 1, 0);

boolean moveLeft() {

  • return move(0, 0, -1);

boolean moveRight() {

  • return move(side * side - 1, 0, 1);

代码

代码语言:javascript
复制
package com.hanxu51.game2048;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Game2048 extends JPanel {
    enum State {
        start, won, running, over
    }
    final Color[] colorTable = {
            new Color(0x701710), new Color(0xFFE4C3), new Color(0xfff4d3),
            new Color(0xffdac3), new Color(0xe7b08e), new Color(0xe7bf8e),
            new Color(0xffc4c3), new Color(0xE7948e), new Color(0xbe7e56),
            new Color(0xbe5e56), new Color(0x9c3931), new Color(0x701710)};
    final static int target = 2048;
    static int highest;
    static int score;
    private Color gridColor = new Color(0xBBADA0);
    private Color emptyColor = new Color(0xCDC1B4);
    private Color startColor = new Color(0xFFEBCD);
    private Random rand = new Random();
    private Tile[][] tiles;
    private int side = 4;
    private State gamestate = State.start;
    private boolean checkingAvailableMoves;
    public Game2048() {
        setPreferredSize(new Dimension(900, 700));
        setBackground(new Color(0xFAF8EF));
        setFont(new Font("SansSerif", Font.BOLD, 48));
        setFocusable(true);
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startGame();
                repaint();
            }
        });
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP:
                        moveUp();
                        break;
                    case KeyEvent.VK_DOWN:
                        moveDown();
                        break;
                    case KeyEvent.VK_LEFT:
                        moveLeft();
                        break;
                    case KeyEvent.VK_RIGHT:
                        moveRight();
                        break;
                }
                repaint();
            }
        });
    }
    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        drawGrid(g);
    }
    void startGame() {
        if (gamestate != State.running) {
            score = 0;
            highest = 0;
            gamestate = State.running;
            tiles = new Tile[side][side];
            addRandomTile();
            addRandomTile();
        }
    }
    void drawGrid(Graphics2D g) {
        g.setColor(gridColor);
        g.fillRoundRect(200, 100, 499, 499, 15, 15);
        if (gamestate == State.running) {
            for (int r = 0; r < side; r++) {
                for (int c = 0; c < side; c++) {
                    if (tiles[r][c] == null) {
                        g.setColor(emptyColor);
                        g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7);
                    } else {
                        drawTile(g, r, c);
                    }
                }
            }
        } else {
            g.setColor(startColor);
            g.fillRoundRect(215, 115, 469, 469, 7, 7);
            g.setColor(gridColor.darker());
            g.setFont(new Font("SansSerif", Font.BOLD, 128));
            g.drawString("2048", 310, 270);
            g.setFont(new Font("SansSerif", Font.BOLD, 20));
            if (gamestate == State.won) {
                g.drawString("you made it!", 390, 350);
            } else if (gamestate == State.over)
                g.drawString("game over", 400, 350);
            g.setColor(gridColor);
            g.drawString("click to start a new game", 330, 470);
            g.drawString("(use arrow keys to move tiles)", 310, 530);
        }
    }
    void drawTile(Graphics2D g, int r, int c) {
        int value = tiles[r][c].getValue();
        g.setColor(colorTable[(int) (Math.log(value) / Math.log(2)) + 1]);
        g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7);
        String s = String.valueOf(value);
        g.setColor(value < 128 ? colorTable[0] : colorTable[1]);
        FontMetrics fm = g.getFontMetrics();
        int asc = fm.getAscent();
        int dec = fm.getDescent();
        int x = 215 + c * 121 + (106 - fm.stringWidth(s)) / 2;
        int y = 115 + r * 121 + (asc + (106 - (asc + dec)) / 2);
        g.drawString(s, x, y);
    }
    private void addRandomTile() {
        int pos = rand.nextInt(side * side);
        int row, col;
        do {
            pos = (pos + 1) % (side * side);
            row = pos / side;
            col = pos % side;
        } while (tiles[row][col] != null);
        int val = rand.nextInt(10) == 0 ? 4 : 2;
        tiles[row][col] = new Tile(val);
    }
    private boolean move(int countDownFrom, int yIncr, int xIncr) {
        boolean moved = false;
        for (int i = 0; i < side * side; i++) {
            int j = Math.abs(countDownFrom - i);
            int r = j / side;
            int c = j % side;
            if (tiles[r][c] == null)
                continue;
            int nextR = r + yIncr;
            int nextC = c + xIncr;
            while (nextR >= 0 && nextR < side && nextC >= 0 && nextC < side) {
                Tile next = tiles[nextR][nextC];
                Tile curr = tiles[r][c];
                if (next == null) {
                    if (checkingAvailableMoves)
                        return true;
                    tiles[nextR][nextC] = curr;
                    tiles[r][c] = null;
                    r = nextR;
                    c = nextC;
                    nextR += yIncr;
                    nextC += xIncr;
                    moved = true;
                } else if (next.canMergeWith(curr)) {
                    if (checkingAvailableMoves)
                        return true;
                    int value = next.mergeWith(curr);
                    if (value > highest)
                        highest = value;
                    score += value;
                    tiles[r][c] = null;
                    moved = true;
                    break;
                } else
                    break;
            }
        }
        if (moved) {
            if (highest < target) {
                clearMerged();
                addRandomTile();
                if (!movesAvailable()) {
                    gamestate = State.over;
                }
            } else if (highest == target)
                gamestate = State.won;
        }
        return moved;
    }
    boolean moveUp() {
        return move(0, -1, 0);
    }
    boolean moveDown() {
        return move(side * side - 1, 1, 0);
    }
    boolean moveLeft() {
        return move(0, 0, -1);
    }
    boolean moveRight() {
        return move(side * side - 1, 0, 1);
    }
    void clearMerged() {
        for (Tile[] row : tiles)
            for (Tile tile : row)
                if (tile != null)
                    tile.setMerged(false);
    }
    boolean movesAvailable() {
        checkingAvailableMoves = true;
        boolean hasMoves = moveUp() || moveDown() || moveLeft() || moveRight();
        checkingAvailableMoves = false;
        return hasMoves;
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("2048");
            f.setResizable(true);
            f.add(new Game2048(), BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}
class Tile {
    private boolean merged;
    private int value;
    Tile(int val) {
        value = val;
    }
    int getValue() {
        return value;
    }
    void setMerged(boolean m) {
        merged = m;
    }
    boolean canMergeWith(Tile other) {
        return !merged && other != null && !other.merged && value == other.getValue();
    }
    int mergeWith(Tile other) {
        if (canMergeWith(other)) {
            value *= 2;
            merged = true;
            return value;
        }
        return -1;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/02/29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2048的代码不是我写的,是从牛客网的项目平台找到的项目
  • 项目代码链接(代码放在了文章最后)
  • 录制的效果图:
  • 游戏逻辑分析
  • 代码的分析
    • 简易的思维导图
      • 文字版
      • Game2048
        • main主方法
          • SwingUtilities.invokeLater(() -> {
          • JFrame f = new JFrame();
          • f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE可以关闭窗口);
          • f.setTitle("2048");设置窗口标题
          • f.setResizable(true);面板可以调节
          • f.add(new Game2048(), BorderLayout.CENTER);把游戏放入面板
          • f.pack();
          • f.setLocationRelativeTo(null);
          • f.setVisible(true);可见
          • });
        • class Tile数字块类
          • private boolean merged;是否合并
          • private int value;值
          • 构造方法
          • get 和set方法
          • canMergeWith(Tile other)判断两个块是否可合并
          • int mergeWith(Tile other) {合并方法
        • movesAvailable判断是否可以移动
          • clearMerged清楚面板
            • 遍历所有格子 设置false
          • 变量
            • State静态成员
            • colorTable颜色库
            • final static int target = 2048;目标分数
            • static int highest;游戏高度
            • static int score;游戏分数
            • private Color gridColor = new Color(0xBBADA0);方格颜色
            • private Color emptyColor = new Color(0xCDC1B4);空颜色
            • private Color startColor = new Color(0xFFEBCD);开始颜色
            • private Random rand = new Random();随机数
            • private Tile tiles;数字块数组 存放全部数字块
            • private int side = 4;格子大小4*4
            • private State gamestate = State.start;游戏状态
            • private boolean checkingAvailableMoves;可否移动状态
          • Game2048构造方法
            • setPreferredSize(new Dimension(900, 700));
            • setBackground(new Color(0xFAF8EF));
            • setFont(new Font("SansSerif", Font.BOLD, 48));
            • setFocusable(true);
            • 监听鼠标
            • 监听键盘
          • paintComponent绘制组件
            • 初始化画图
            • setRenderingHint抗锯齿
          • startGame开始游戏
            • if (gamestate != State.running) {
            • score = 0;
            • highest = 0;
            • gamestate = State.running;
            • tiles = new Tileside;
            • addRandomTile();
            • addRandomTile();
            • }
          • drawGrid绘制面板
            • g.setColor(gridColor);设置颜色
            • g.fillRoundRect(200, 100, 499, 499, 15, 15);填充背景
            • 判断游戏状态
          • drawTile绘制数字块
            • fillRoundRect在二维面板 r行c列画value
          • addRandomTile随机生成数字块
            • 随机找空位置添加 4或2
          • move移动数字块
            • 根据方向进行移动
            • 移动后序处理
          • 一系列移动方法
            • boolean moveUp() {
            • boolean moveDown() {
            • boolean moveLeft() {
            • boolean moveRight() {
        • 代码
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档