1. 游戏概述

本游戏是一个基于 Java 的二维游戏,玩家控制一条鱼在海洋环境中生存,通过吃掉敌方小鱼来获得分数并提升等级。游戏包含了多个关卡和敌人类型,具有简单的碰撞检测和游戏状态管理。

(因为手头上找不到合适的游戏素材,所以都是拿现有的东西拼凑的,内容可替换)

  1. 开发环境

  • 开发工具:Vscode
  • 编程语言:Java
  • 主要库
    • javax.swing:用于创建图形用户界面
    • java.awt:用于绘图和图形处理
    • java.util:用于数据结构和集合
  1. 类基本功能实现

游戏窗口

  • GameWin.java
  • 作用:设置游戏窗口的大小、标题、背景颜色,并初始化游戏状态。
  • 关键方法
    • launch():设置窗口属性,添加鼠标和键盘事件监听器,并启动游戏循环。
    • paint(Graphics g):使用双缓冲技术绘制游戏内容,包括背景、玩家和敌人。
    • logic():处理游戏逻辑,包括敌人的生成、移动和碰撞检测。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class GameWin extends JFrame {

//0未开始 1游戏中 2游戏失败 3游戏成功 4游戏暂停

//游戏默认状态
static int State = 0;

Image offScreenImage;
//游戏窗口的宽度和高度
int width = 1920;
int height = 1080;

//其他成员变量...

public void launch(){
this.setVisible(true);
this.setSize(width, height);
this.setLocationRelativeTo(null); // Center the window
this.setTitle("大鱼吃小鱼");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

//添加鼠标和键盘事件监听器
//...

//启动游戏循环
new Thread(() -> {
while (true) {
repaint();
time++;
try {
Thread.sleep(40); // 控制刷新频率
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}

public void paint(Graphics g) {
//双缓冲绘制
offScreenImage = createImage(width, height);
Graphics gImage = offScreenImage.getGraphics();
bg.paintSelf(gImage, myFish.level);
//绘制游戏内容...
g.drawImage(offScreenImage, 0, 0, null);
}

void logic() {
//处理游戏逻辑...
}

public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}

工具类

  • GameUtils.java
  • 作用:提供游戏中的全局变量和工具方法,如方向控制、分数计算和关卡管理。
  • 关键方法
    • drawWord(Graphics g, String str, Color color, int size, int x, int y):在屏幕上绘制文字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class GameUtils {

//方向
static boolean LEFT = false; //向左
static boolean RIGHT = false; //向右
static boolean UP = false; //向上
static boolean DOWN = false; //向下

//分数
static int count = 0;

//关卡等级
static int level = 0;

//敌方鱼类集合
public static List<Enemy> EnemyList = new ArrayList<>();

//背景和鱼的图片
public static Image bgimg = Toolkit.getDefaultToolkit().createImage("images/sea.jpg");
public static Image MyFishimg_L = Toolkit.getDefaultToolkit().createImage("images/myFish/myfish.png");
public static Image MyFishimg_R = Toolkit.getDefaultToolkit().createImage("images/myFish/myfish.png");
//其他图片...

public static void drawWord(Graphics g, String str, Color color, int size, int x, int y) {
g.setColor(color);
g.setFont(new Font("仿宋", Font.BOLD, size));
g.drawString(str, x, y);
}
}

我方鱼

  • MyFish.java
  • 作用:定义玩家鱼的属性和行为。
  • 关键方法
    • logic():根据方向键输入更新鱼的位置。
    • paintSelf(Graphics g):绘制鱼的图像。
    • getRec():返回鱼的矩形区域用于碰撞检测。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MyFish {
Image img = GameUtils.MyFishimg_L; // 我方鱼的图片
int x = 700, y = 500; // 我方鱼的位置
int width = 50, height = 50; // 我方鱼的宽度和高度
int speed = 20; // 我方鱼的移动速度
int level = 1; // 我方鱼的等级

void logic() {
if (GameUtils.UP) {
y -= speed; // 向上移动
}
if (GameUtils.DOWN) {
y += speed; // 向下移动
}
if (GameUtils.LEFT) {
x -= speed; // 向左移动
}
if (GameUtils.RIGHT) {
x += speed; // 向右移动
}
}

public void paintSelf(Graphics g) {
logic();
g.drawImage(img, x, y, width + GameUtils.count, height + GameUtils.count, null);
}

public Rectangle getRec() {
return new Rectangle(x, y, width + GameUtils.count, height + GameUtils.count);
}
}

敌人鱼

  • Enemy.java
  • 作用:定义敌人鱼的属性和行为,包括多个子类以实现不同类型和方向的敌人鱼。
  • 关键方法
    • paintSelf(Graphics g):绘制敌人鱼的图像。
    • getRec():返回敌人鱼的矩形区域用于碰撞检测。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Enemy {
int x, y; //敌人的位置
int width, height; //敌人的宽度和高度
Image img; //敌人的图片
int speed = 5; //敌人的移动速度
int dir = 1; //敌人的移动方向,1表示向右,-1表示向左
int type; //敌人的类型
int count; //计数器,计算分值

public void paintSelf(Graphics g) {
g.drawImage(img, x, y, width, height, null);
}

public Rectangle getRec() {
return new Rectangle(x, y, width, height);
}
}

class Enemy_1_L extends Enemy {
Enemy_1_L() {
this.x = -45;
this.y = (int) (Math.random() * 700 + 100); // 随机生成y坐标
this.width = 50;
this.height = 50;
this.speed = 10; // 设置速度
this.count = 1;
this.type = 1;
this.img = GameUtils.enemyl_img; // 假设GameUtils中有敌人图片
}
}
//其他敌人子类...

背景

  • Bg.java
  • 作用:绘制游戏背景,并根据游戏状态显示不同的文字信息。
  • 关键方法
    • paintSelf(Graphics g, int fishLevel):绘制背景和状态信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Bg {
void paintSelf(Graphics g, int fishLevel) {
g.drawImage(GameUtils.bgimg, 0, 0, null);
switch (GameWin.State) {
case 0:
GameUtils.drawWord(g, "点击鼠标开始游戏", Color.red, 50, 800, 500);
break;
case 1:
GameUtils.drawWord(g, "积分" + GameUtils.count, Color.orange, 50, 200, 120);
GameUtils.drawWord(g, "难度" + GameUtils.level, Color.orange, 50, 600, 120);
GameUtils.drawWord(g, "等级" + fishLevel, Color.orange, 50, 1000, 120);
break;
case 2:
GameUtils.drawWord(g, "积分" + GameUtils.count, Color.orange, 50, 200, 120);
GameUtils.drawWord(g, "难度" + GameUtils.level, Color.orange, 50, 600, 120);
GameUtils.drawWord(g, "等级" + fishLevel, Color.orange, 50, 1000, 120);
GameUtils.drawWord(g, "游戏失败", Color.red, 80, 700, 500);
break;
case 3:
GameUtils.drawWord(g, "积分" + GameUtils.count, Color.orange, 50, 200, 120);
GameUtils.drawWord(g, "难度" + GameUtils.level, Color.orange, 50, 600, 120);
GameUtils.drawWord(g, "等级" + fishLevel, Color.orange, 50, 1000, 120);
GameUtils.drawWord(g, "胜利", Color.red, 80, 700, 500);
break;
case 4:
break;
default:
break;
}
}
}
  1. 详细功能实现

键盘控制移动

  • 功能描述:玩家可以通过键盘的W、A、S、D键控制鱼的上下左右移动。
  • 关键代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
GameUtils.UP = true; // 向上
}
if (e.getKeyCode() == KeyEvent.VK_S) {
GameUtils.DOWN = true; // 向下
}
if (e.getKeyCode() == KeyEvent.VK_A) {
GameUtils.LEFT = true; // 向左
}
if (e.getKeyCode() == KeyEvent.VK_D) {
GameUtils.RIGHT = true; // 向右
}
}

@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
GameUtils.UP = false; // 停止向上
}
if (e.getKeyCode() == KeyEvent.VK_S) {
GameUtils.DOWN = false; // 停止向下
}
if (e.getKeyCode() == KeyEvent.VK_A) {
GameUtils.LEFT = false; // 停止向左
}
if (e.getKeyCode() == KeyEvent.VK_D) {
GameUtils.RIGHT = false; // 停止向右
}
}
});
  • 实现细节
    • 使用KeyListener监听键盘事件。
    • 按下W、A、S、D键时,分别将GameUtils中的方向标志设置为true
    • 松开按键时,将对应的方向标志设置为false
    • MyFish类的logic()方法中,根据方向标志更新鱼的位置。

等级与难度的计算

  • 功能描述:根据玩家的分数动态调整游戏的等级和难度,分数越高,敌人鱼的速度和出现频率越高。
  • 关键代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (GameUtils.count < 5) {
GameUtils.level = 0;
myFish.level = 1; // 初始等级
} else if (GameUtils.count <= 15) {
GameUtils.level = 1;
} else if (GameUtils.count <= 50) {
GameUtils.level = 2;
myFish.level = 2; // 升级到等级2
} else if (GameUtils.count <= 150) {
GameUtils.level = 3;
myFish.level = 3; // 升级到等级3
} else if (GameUtils.count <= 300) {
GameUtils.level = 4;
myFish.level = 4; // 升级到等级4
} else {
State = 3; // 游戏成功
}
  • 实现细节
    • 根据玩家的分数GameUtils.count来判断当前的关卡等级。
    • 不同的关卡等级对应不同的敌人生成逻辑和移动速度。
    • 玩家的鱼也会随着关卡的提升而升级,等级越高,鱼的体积越大。

Boss功能

  • 功能描述:在特定条件下生成Boss鱼,玩家需要避开Boss并击败它以获得更高的分数。
  • 关键代码
1
2
3
4
5
6
7
8
9
10
11
12
if (GameUtils.count >= 150 && !isBoss) {
boss = new Enemy_Boss();
isBoss = true; // Boss生成后设置为true
}
if (isBoss) {
boss.x = boss.x + boss.dir * boss.speed; // 移动Boss
boss.paintSelf(gImage);
if (boss.x < 0) {
gImage.setColor(Color.red);
gImage.fillRect(boss.x, boss.y, 2400, boss.height / 30); // Boss移出屏幕后填充红色区域
}
}
  • 实现细节
    • 当玩家分数达到一定值时,生成Boss鱼。
    • Boss鱼具有更高的速度和体积,玩家需要小心躲避。
    • 如果玩家成功击败Boss,将获得大量分数并提升关卡。

暂停和重新开始功能

  • 功能描述:玩家可以随时暂停游戏,并在游戏结束或失败后重新开始游戏。
  • 关键代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 暂停功能
if (e.getKeyCode() == 32) { // 空格键
switch (State) {
case 1:
State = 4; // 暂停游戏
GameUtils.drawWord(getGraphics(), "游戏暂停", Color.red, 50, 600, 400);
break;
case 4:
State = 1; // 恢复游戏
break;
}
}

// 重新开始功能
if (e.getButton() == 1 && (State == 2 || State == 3)) {
reGame();
State = 1; // 回到初始状态
}

void reGame() {
GameUtils.EnemyList.clear(); // 清空敌人列表
time = 0; // 重置计时器
GameUtils.count = 0; // 重置分数
myFish.level = 1; // 重置等级
myFish = new MyFish(); // 重置我方鱼
boss = null; // 重置Boss
isBoss = false; // 重置Boss状态
}
  • 实现细节
    • 使用空格键切换游戏的暂停和继续状态。
    • 在游戏结束或失败时,点击鼠标可以重新开始游戏。
    • 重新开始游戏时,重置所有游戏参数,包括分数、等级、敌人列表等。
  1. 最终效果

  • 开始页面

image-20250620202556424

  • 游戏内容

image-20250620202703632

  • 游戏失败

image-20250620202745728

  • 游戏暂停

image-20250620224539888

  • 游戏胜利

数值拉太高自己打不过了 暂时先空着orz

  1. 扩展建议(可能会改进的部分)

  • 增加音效:为游戏添加背景音乐和音效,提升游戏体验。
  • 添加更多敌人类型:扩展敌人鱼的种类和行为,增加游戏的挑战性。
  • 优化碰撞检测:使用更高效的数据结构来处理大量敌人和复杂场景。