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
前期调查
网页版2048:https://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.登陆界面目前只是空壳,因为数据库这一块实在没弄懂......