个人任务实现:
序号 | 完成功能与任务 | 描述 |
1 | 实现了球的随机生成 | 使用多个方法将属性可能出现的种类都随机,并随机组合在一起增大球的随机性 |
2 | 对球是否出边界的处理和球的补充 | 判断其他球中是否有球出了游戏边界后再利用newball的方法补充球以保证游戏界面中球的数量 |
3 | 实现玩家球控制移动方向 | 使用了DAO模式。用接口枚举方向并将键盘内容结合改变球运动的方向 |
项目功能架构图:
1. 实现其他球随机生成大小的动态范围(未完成)
想实现该部分主要目的能够防止玩家球在吞噬一定的球后就能够吞噬其他所有球,变成无敌的状态,而导致游戏难度的降低,但是一直改不出来,改完范围就会报错,无法找到生成范围
2. 其他球的运动,对球是否出边界的处理和球的补充
OtherBall 类管理球的集合,处理它们的运动、交互以及检查它们是否出界。它还具有在给定 Graphics 对象上绘制所有球的方法。并将它们添加到列表中。isAlive 方法检查球是否出界,并在需要时创建一个新球。move 方法随机移动所有球,isEat 方法检查是否有任何球可以吃掉另一个球。
关键代码:
public void isAlive() {
// 遍历所有的球,如果球出界,则删除这个球,并创建一个新的球()
for (int i = 0; i < balls.size(); i++) {
Ball ball = balls.get(i);
if (ball.getX() < -200 || ball.getX() > 1000 || ball.getY() < -200 || ball.getY() > 1000) {
ball = null;
}
}
int count2 = (int) (Math.random() * 100 + 1);
//判断是否需要创建球
if (count2 > 90) {
newBall();
}
}
//球的随机移动
public void move(int m) {
for (Ball ball : balls) {
ball.move(m);
}
}
/**
* 判断球是否被吃
*/
public void isEat(MyBall mb, int i) {
for (int j = 0; j < balls.size() - 1; j++) {
Ball ball = balls.get(j);
mb.eat(ball, i);
ball.eat(balls.get(j + 1), i);
}
}
3. 玩家球的运动和是否出界
Ball类利用move 方法将球沿控制方向移动。利用DAO接口传入changeDir方法改变方向,eat 方法根据一个球的直径和位置处理一个球吃掉另一个球的逻辑。draw 方法用于在屏幕上呈现球。
关键代码:
public void draw(Graphics g) {
if (image != null) {
// 创建一个圆形的剪辑区域
Graphics2D g2d = (Graphics2D) g.create();
g2d.setClip(new Ellipse2D.Float(this.x, this.y, this.diameter, this.diameter));
// 在剪辑区域内绘制图片
g2d.drawImage(image, this.x, this.y, this.diameter, this.diameter, null);
g2d.dispose(); // 释放由 create() 方法创建的 Graphics 对象的资源
} else {
// 如果没有图片,就绘制一个彩色的圆形
g.setColor(color);
g.fillOval(this.x, this.y, this.diameter, this.diameter);
g.setColor(Color.orange);
g.drawOval(this.x, this.y, this.diameter, this.diameter);
}
}
/**
* changeDir方法,用于改变球的移动方向
*/
public void changeDir(Direction dir) {
this.direction = dir;
}
/**
* move方法,用于根据当前的移动方向移动球
*/
public void move(int m) {
if (this.direction != null) {
switch (direction) {
case UP:
y -= m;
break;
case DOWN:
y += m;
break;
case LEFT:
x -= m;
break;
case RIGHT:
x += m;
break;
default:
break;
}
}
}
/**
* eat方法,用于处理球吃掉其他球的逻辑
*/
public void eat(Ball ball, int i) {
int x1 = ball.getX();
//获取小球的 x 坐标
int y1 = ball.getY();
// 获取小球的 y 坐标
int d1 = ball.getD();
// 获取小球的直径
if (this.diameter < 600) {
// 如果大球的直径小于600
if (d1 < this.diameter) {
// 如果小球的直径小于大球的直径
// 小球被吃掉
// 计算小球和大球之间的距离
int d = (int) Math.sqrt((x1 + d1 / 2 - this.getX() - this.getDiameter() / 2) * (x1 + d1 / 2 - this.getX() - this.getDiameter() / 2) + (y1 + d1 / 2 - this.getY() - this.getDiameter() / 2) * (y1 + d1 / 2 - this.getY() - this.getDiameter() / 2));
if (d < (d1 + this.getDiameter()) / 2) {
// 如果小球在大球的半径范围内 该小球应该被吃掉
this.setDiameter(this.diameter + d1 / i);
// 大球直径+=小球的直径除以i的值
ball.setX(-100);
//小球 x 坐标设置为 -100,使其移出屏幕或不再可见
ball.setY(-100);
// 小球 y 坐标设置为 -100,使其移出屏幕或不再可见
ball.setD(0);
// 小球直径设置为0,使其不再可见或无效
ball = null;
// 将小球对象设置为null,释放内存
}
} else if (d1 > this.getDiameter()) {
// 如果小球的直径大于大球的直径
// 计算小球和大球之间的距离
int d = (int) Math.sqrt((x1 + d1 / 2 - this.getX() - this.getDiameter() / 2) * (x1 + d1 / 2 - this.getX() - this.getDiameter() / 2) + (y1 + d1 / 2 - this.getY() - this.getDiameter() / 2) * (y1 + d1 / 2 - this.getY() - this.getDiameter() / 2));
if (d < (d1 + this.getDiameter()) / 2) {
// 如果小球在大球的半径范围内
// 小球应该被吃掉
this.setX(-100);
// 大球 x 坐标设置为 -100,使其移出屏幕或不再可见
this.setY(-100);
// 大球 y 坐标设置为 -100,使其移出屏幕或不再可见
this.setDiameter(0);
// 大球直径设置为0,使其不再可见或无效
}
}
} else {
// 如果大球的直径大于或等于600
JOptionPane.showMessageDialog(new Frame2(), "恭喜您,球球够大了", "提示", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
4. 实现了球的随机生成
newBall 方法生成具有随机大小、位置、颜色和图像路径的新球,chooseColor 方法将数字映射到颜色。
关键代码:
//生成随机颜色
public Color chooseColor(int num) {
Color color = switch (num) {
case 0 -> Color.BLACK;
case 1 -> Color.BLUE;
case 2 -> Color.RED;
case 3 -> Color.GREEN;
case 4 -> Color.YELLOW;
case 5 -> Color.ORANGE;
case 6 -> Color.GRAY;
case 7 -> Color.PINK;
case 8 -> Color.CYAN;
case 9 -> Color.DARK_GRAY;
case 10 -> Color.MAGENTA;
case 11 -> Color.WHITE;
case 12 -> Color.LIGHT_GRAY;
default -> throw new IllegalStateException("Unexpected value: " + num);
};
return color;
}
public void newBall() {
Random rand = new Random();
// 生成新球的直径
int size = rand.nextInt(70) + 15;
// 生成新球的位置
int x3 = rand.nextInt(1001);
int y3 = rand.nextInt(1001);
// 选择颜色
int num = rand.nextInt(13);
int num1 = rand.nextInt(6);
Color color = chooseColor(num);
String[] imagePaths =
{
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111192818.jpg",
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111215933.jpg",
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111215941.jpg",
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111215946.jpg",
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111215951.jpg",
"E:\\ideal\\BallGamebjl\\src\\BalleatBall\\微信图片_20240111215959.jpg",
};
String imagePath = imagePaths[num1];
// 创建球并添加到列表
Ball ball = new Ball(x3, y3, size, color, imagePath);
balls.add(ball);
}
1. 出边界问题:在Ball类中,可以通过检查球的位置来判断是否出界,然后采取相应的处理措施,比如将球移出界面或者重新生成一个新的球。
2.吃球问题:在Ball类中,通过eat方法实现了大球吃小球的逻辑。根据两球的直径和位置关系,判断是否可以吃掉对方球,并进行相应的处理,如增加当前球的直径并移出被吃球。
感悟:通过实现这些功能,可以感受到游戏开发中的物体交互逻辑。处理边界和碰撞问题是游戏开发中常见的挑战,而这些功能的实现可以为游戏的可玩性和趣味性增添很多元素展望:
1. 增加多样性:可以为不同大小的球设置不同速度、吃球效果和连续加速等属性,以增加游戏的多样性和挑战性。
2. 特殊能力:为大球和小球添加特殊能力,比如大球可以暂时变得更快或者更慢,小球可以暂时变得透明或者无法被吃掉等,以增加游戏的策略性和趣味性。
3. 游戏规则:设计更丰富的游戏规则,比如限定时间内吃掉尽量多的小球,或者在特定条件下触发特殊事件等,以增加游戏的可玩性和挑战性。
4. 视觉效果:优化绘制效果,添加动画效果和粒子特效,提升游戏的视觉体验。