java课程设计-赛博朋克2048小游戏

Cyberpunk2048

团队情况

成员 任务分配 -
刘炜 代码整合,框架整理,游戏玩法登陆系统等关键代码编写,项目打包 组长
林毅 背景音乐背景图片插入,基础和主界面GUI 组员
童浚 tile类编写,方格类绘制,计时器代码 组员

参考项目

https://www.cnblogs.com/my-program-life/p/10987657.html Java 实现2048游戏之详细教程
https://blog.csdn.net/hunt_er/article/details/84320980?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control java程序添加背景音乐

gitee地址

https://gitee.com/mikehro/cyberpunk2048

前期调查

网页版2048https://www.2048.org/

(利用方向键控制方格移动方向,相同数字合并)

功能框架图

面向对象设计

包-类图

UML

项目运行截图

1.开始界面

新加入了背景图片

2.登陆界面

3.开始游戏

4.游戏中

5.游戏失败

项目关键代码

1.游戏窗口(GUI)和游戏开始界面绘制

  public void paintComponent(Graphics gg) {//绘制方格初始化(优先级高)
    super.paintComponent(gg);
    Graphics2D g = (Graphics2D) gg;
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,//设置绘制参数,消除文字锯齿,消除画图锯齿
        RenderingHints.VALUE_ANTIALIAS_ON);
    drawGrid(g);//画出方格
  }
  void drawGrid(Graphics2D g) {//绘制方格所在区域
    g.setColor(gridColor);//提取颜色
    g.fillRoundRect(200, 100, 499, 499, 15, 15);//填充背景,即绘制圆角矩形块
    if (gamestate == State.running) {//如果游戏状态运行中,即“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);
      g.setFont(new Font("SansSerif", Font.BOLD, 128));//设置字体
      g.drawString("2048", 310, 270);//游戏标题
      g.setFont(new Font("SansSerif", Font.BOLD, 20));
      g.drawString("赛博朋克    ", 330, 170);
      g.drawString("网络1914 刘炜 林毅 童浚   ", 330, 300);
      g.setFont(new Font("SansSerif", Font.BOLD, 50));
      if (gamestate == State.won) {//如果游戏状态为“won”
        g.drawString("你成功了!", 390, 350);
      } else if (gamestate == State.over)//如果游戏状态为“Over”
        g.drawString("Game Over", 300, 350);
      g.setColor(gridColor);
      g.setFont(new Font("SansSerif", Font.BOLD, 20));
      g.drawString("       点击开始新游戏", 330, 470);
      g.drawString("(使用方向键来移动全部方块)", 310, 530);
      if (gamestate == State.change) {
    	  g.setColor(startColor);
          g.fillRoundRect(215, 115, 469, 469, 7, 7);
    	  g.setColor(gridColor);
          g.setFont(new Font("SansSerif", Font.BOLD, 50));//设置字体
          
          g.drawString("1->简单难度", 310, 300);
          g.drawString("2->普通难度", 310, 350);
          g.drawString("3->困难难度", 310, 400);
          g.drawString("4->赛博难度", 310, 450);
          
          addKeyListener(new KeyAdapter() {//监听键盘
      	      
      	      public void keyPressed(KeyEvent e) {//若键盘点击......
      	        switch (e.getKeyCode()) {//数字键选择
      	          case KeyEvent.VK_1:
      	            target=256;
      	            break;
      	          case KeyEvent.VK_2:
      	        	target=512;
      	            break;
      	          case KeyEvent.VK_3:
      	        	target=1024;
      	            break;
      	          case KeyEvent.VK_4:
        	        	target=2048;
        	            break;
      	        }
      	       
      	        repaint();
      	      }
      	    });
      }
     
    }
  }

  public static void main(String[] args) {//Main方法
	  
    SwingUtilities.invokeLater(() -> {//设置GUI
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//可关闭窗口
      f.setTitle("赛博朋克2048");//窗口标题
      f.setResizable(true);//面板可调节
      f.add(new Game2048(), BorderLayout.CENTER);//游戏置入窗口
      new Play0("Highway Superstar - Easy Ride.mp3").start();//播放背景音乐
      f.pack();
      f.setLocationRelativeTo(null);
      f.setVisible(true);//可见
    });
  }
}            

2.方块移动,合并

 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;//原方块置0
          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;//游戏状态变为“Over”
        }
      } else if (highest == target)//最高分与目标分相同
        gamestate = State.won;//游戏状态变为“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)//foreach循环遍历所有方格获取坐标
      for (Tile tile : row)//根据坐标遍历所有方格
        if (tile != null)//若方块为空
          tile.setMerged(false);//设置false
  }
  boolean movesAvailable() {//方格移动状态
    checkingAvailableMoves = true;//可移动
    boolean hasMoves = moveUp() || moveDown() || moveLeft() || moveRight();
    checkingAvailableMoves = false;//不可移动
    return hasMoves;
  }

3.方块类

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;

public 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;
  }
}

代码静态扫描

项目总结(不足与展望)

1.由于疫情在家和个人能力问题,整个项目最终的完成度并不高,附件功能如难度选择,用户登陆,分数排名都没实装。
2.UI界面不过完善也不够美观,GUI相关功能还需要学习和完善。
3.背景音乐仅仅只是插入,没有提供静音等修改选项。
4.受限于2048游戏框架,玩法单一枯燥。希望之后能够有时间改进和增添关卡。
5.登陆界面目前只是空壳,因为数据库这一块实在没弄懂......

原文地址:https://www.cnblogs.com/MIKEHRO/p/14336294.html