设计思路与技术架构
我将设计一个基于Java Swing的飞机大战游戏,实现玩家控制飞机移动、发射子弹,敌方飞机自动生成,碰撞检测以及计分系统等功能。整个游戏采用面向对象的思想设计,使用MVC架构模式:
- 模型(Model):游戏核心逻辑(飞机、子弹、碰撞等)
- 视图(View):游戏渲染与用户界面(Swing组件)
- 控制器(Controller):用户输入处理(键盘事件)
主要类设计
PlaneWarGame
- 游戏主框架GamePanel
- 游戏画布Player
- 玩家飞机类Enemy
- 敌机类Bullet
- 子弹类Explosion
- 爆炸效果类
完整代码实现
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
// 游戏主类
public class PlaneWarGame extends JFrame {
private GamePanel gamePanel;
public PlaneWarGame() {
setTitle("Java飞机大战");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
gamePanel = new GamePanel();
add(gamePanel);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(PlaneWarGame::new);
}
}
// 游戏主画板
class GamePanel extends JPanel implements KeyListener, ActionListener {
private Player player;
private List enemies;
private List playerBullets;
private List explosions;
private Timer gameTimer;
private Random random;
private int score = 0;
private boolean gameRunning = true;
private Font gameFont = new Font("Arial", Font.BOLD, 24);
public GamePanel() {
setFocusable(true);
addKeyListener(this);
setBackground(new Color(0, 0, 30));
random = new Random();
player = new Player(400, 500);
enemies = new ArrayList<>();
playerBullets = new ArrayList<>();
explosions = new ArrayList<>();
gameTimer = new Timer(16, this); // 约60FPS
gameTimer.start();
// 初始创建敌机
for (int i = 0; i < 5; i++) {
spawnEnemy();
}
}
// 生成敌机
private void spawnEnemy() {
int x = random.nextInt(getWidth() - 50);
int y = random.nextInt(300) - 400;
enemies.add(new Enemy(x, y));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// 绘制星空背景
drawStarBackground(g);
// 绘制玩家飞机
player.draw(g);
// 绘制敌机
for (Enemy enemy : enemies) {
enemy.draw(g);
}
// 绘制子弹
for (Bullet bullet : playerBullets) {
bullet.draw(g);
}
// 绘制爆炸效果
for (Explosion explosion : explosions) {
explosion.draw(g);
}
// 绘制分数和状态
drawGameInfo(g);
// 游戏结束画面
if (!gameRunning) {
drawGameOver(g);
}
}
private void drawStarBackground(Graphics g) {
g.setColor(Color.WHITE);
for (int i = 0; i < 100; i++) {
int x = random.nextInt(getWidth());
int y = random.nextInt(getHeight());
int size = random.nextInt(3) + 1;
g.fillOval(x, y, size, size);
}
}
private void drawGameInfo(Graphics g) {
g.setColor(Color.WHITE);
g.setFont(gameFont);
g.drawString("得分: " + score, 20, 30);
g.drawString("生命: " + player.getHealth(), 20, 60);
}
private void drawGameOver(Graphics g) {
g.setColor(new Color(200, 0, 0, 150));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.BOLD, 48));
String gameOverText = "游戏结束";
int textWidth = g.getFontMetrics().stringWidth(gameOverText);
g.drawString(gameOverText, getWidth()/2 - textWidth/2, getHeight()/2 - 30);
g.setFont(gameFont);
g.drawString("最终得分: " + score, getWidth()/2 - 80, getHeight()/2 + 30);
g.drawString("按R键重新开始", getWidth()/2 - 80, getHeight()/2 + 70);
}
@Override
public void actionPerformed(ActionEvent e) {
if (gameRunning) {
// 玩家移动
player.move();
// 敌机移动和生成
Iterator enemyIterator = enemies.iterator();
while (enemyIterator.hasNext()) {
Enemy enemy = enemyIterator.next();
enemy.move();
// 检查玩家碰撞
if (player.checkCollision(enemy)) {
player.hit();
explosions.add(new Explosion(enemy.getX(), enemy.getY()));
enemyIterator.remove();
spawnEnemy();
}
// 超出屏幕检测
if (enemy.getY() > getHeight()) {
enemyIterator.remove();
spawnEnemy();
}
}
// 子弹移动
Iterator bulletIterator = playerBullets.iterator();
while (bulletIterator.hasNext()) {
Bullet bullet = bulletIterator.next();
bullet.move();
// 子弹碰撞检测
enemyIterator = enemies.iterator();
boolean bulletHit = false;
while (enemyIterator.hasNext() && !bulletHit) {
Enemy enemy = enemyIterator.next();
if (bullet.checkCollision(enemy)) {
explosions.add(new Explosion(enemy.getX(), enemy.getY()));
enemyIterator.remove();
bulletHit = true;
score += 10;
spawnEnemy();
}
}
// 移除超出屏幕的子弹
if (bullet.getY() < 0 || bulletHit) {
bulletIterator.remove();
}
}
// 更新爆炸效果
Iterator explosionIterator = explosions.iterator();
while (explosionIterator.hasNext()) {
Explosion explosion = explosionIterator.next();
if (explosion.update()) {
explosionIterator.remove();
}
}
// 随机生成新敌机
if (random.nextInt(100) < 2) {
spawnEnemy();
}
// 游戏结束检查
if (player.getHealth() <= 0) {
gameRunning = false;
}
}
repaint();
}
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (gameRunning) {
switch (key) {
case KeyEvent.VK_LEFT:
player.setMoveLeft(true);
break;
case KeyEvent.VK_RIGHT:
player.setMoveRight(true);
break;
case KeyEvent.VK_UP:
player.setMoveUp(true);
break;
case KeyEvent.VK_DOWN:
player.setMoveDown(true);
break;
case KeyEvent.VK_SPACE:
player.fire(playerBullets);
break;
}
} else if (key == KeyEvent.VK_R) {
restartGame();
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
player.setMoveLeft(false);
break;
case KeyEvent.VK_RIGHT:
player.setMoveRight(false);
break;
case KeyEvent.VK_UP:
player.setMoveUp(false);
break;
case KeyEvent.VK_DOWN:
player.setMoveDown(false);
break;
}
}
private void restartGame() {
player = new Player(400, 500);
enemies.clear();
playerBullets.clear();
explosions.clear();
score = 0;
for (int i = 0; i < 5; i++) {
spawnEnemy();
}
gameRunning = true;
}
@Override
public void keyTyped(KeyEvent e) {}
}
// 玩家飞机类
class Player {
private int x, y;
private int width = 60;
private int height = 40;
private int speed = 5;
private int health = 100;
private boolean moveLeft, moveRight, moveUp, moveDown;
private long lastFireTime;
private int fireDelay = 300; // 发射间隔(ms)
private Color color = new Color(0, 200, 255);
public Player(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
// 绘制飞机主体
g.setColor(color);
// 机身
g.fillRect(x - width/2, y - height/2, width, height/3);
g.fillRect(x - width/3, y - height/2, width*2/3, height);
// 机翼
Polygon leftWing = new Polygon();
leftWing.addPoint(x - width/2, y - height/6);
leftWing.addPoint(x - width/2, y + height/6);
leftWing.addPoint(x - width/3, y);
g.fillPolygon(leftWing);
Polygon rightWing = new Polygon();
rightWing.addPoint(x + width/2, y - height/6);
rightWing.addPoint(x + width/2, y + height/6);
rightWing.addPoint(x + width/3, y);
g.fillPolygon(rightWing);
// 驾驶舱
g.setColor(Color.CYAN);
g.fillOval(x - width/8, y - height/4, width/4, width/4);
}
public void move() {
if (moveLeft) x = Math.max(x - speed, width/2);
if (moveRight) x = Math.min(x + speed, 800 - width/2);
if (moveUp) y = Math.max(y - speed, height/2);
if (moveDown) y = Math.min(y + speed, 600 - height/2);
}
public void fire(List bullets) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastFireTime > fireDelay) {
bullets.add(new Bullet(x, y - height/2, 0, -8));
lastFireTime = currentTime;
}
}
public boolean checkCollision(Enemy enemy) {
int distX = Math.abs(x - enemy.getX());
int distY = Math.abs(y - enemy.getY());
return distX < (width/2 + enemy.getWidth()/2) &&
distY < (height/2 + enemy.getHeight()/2);
}
public void hit() {
health -= 25;
}
public void setMoveLeft(boolean moveLeft) {
this.moveLeft = moveLeft;
}
public void setMoveRight(boolean moveRight) {
this.moveRight = moveRight;
}
public void setMoveUp(boolean moveUp) {
this.moveUp = moveUp;
}
public void setMoveDown(boolean moveDown) {
this.moveDown = moveDown;
}
public int getHealth() {
return health;
}
}
// 敌机类
class Enemy {
private int x, y;
private int width = 50;
private int height = 30;
private int speedY = 3;
private int speedX;
private Color color;
public Enemy(int x, int y) {
this.x = x;
this.y = y;
speedX = (new Random().nextBoolean() ? 1 : -1) * (new Random().nextInt(2) + 1);
color = new Color(255, 100 + new Random().nextInt(100), 0);
}
public void draw(Graphics g) {
g.setColor(color);
// 机身
g.fillRect(x - width/2, y - height/2, width, height/2);
// 机翼
g.fillPolygon(new int[]{x - width/2, x - width/2, x},
new int[]{y - height/3, y + height/3, y}, 3);
g.fillPolygon(new int[]{x + width/2, x + width/2, x},
new int[]{y - height/3, y + height/3, y}, 3);
// 驾驶舱
g.setColor(Color.RED);
g.fillOval(x - width/8, y - height/4, width/4, width/4);
}
public void move() {
y += speedY;
x += speedX;
// 碰到边界反弹
if (x < width/2 || x > 800 - width/2) {
speedX = -speedX;
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
// 子弹类
class Bullet {
private int x, y;
private int width = 4;
private int height = 12;
private int speedX, speedY;
private Color color = Color.YELLOW;
public Bullet(int x, int y, int speedX, int speedY) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
}
public void draw(Graphics g) {
g.setColor(color);
g.fillRect(x - width/2, y, width, height);
// 添加发光效果
g.setColor(Color.WHITE);
g.fillRect(x - width/2 + 1, y + 1, width - 2, height - 2);
}
public void move() {
x += speedX;
y += speedY;
}
public boolean checkCollision(Enemy enemy) {
int distX = Math.abs(x - enemy.getX());
int distY = Math.abs(y - enemy.getY());
return distX < (width/2 + enemy.getWidth()/2) &&
distY < (height/2 + enemy.getHeight()/2);
}
public int getY() {
return y;
}
}
// 爆炸效果类
class Explosion {
private int x, y;
private int maxRadius = 40;
private int currentRadius = 5;
private int growthRate = 3;
private Color color = new Color(255, 150, 0, 200);
public Explosion(int x, int y) {
this.x = x;
this.y = y;
}
public boolean update() {
currentRadius += growthRate;
return currentRadius >= maxRadius;
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x - currentRadius, y - currentRadius,
currentRadius * 2, currentRadius * 2);
}
}
核心技术解析
1. 游戏循环与动画
使用Timer
类实现游戏主循环(约60FPS):
gameTimer = new Timer(16, this); // 约60FPS
gameTimer.start();
2. 玩家控制与移动
采用状态机模式处理玩家移动:
public void move() {
if (moveLeft) x = Math.max(x - speed, width/2);
if (moveRight) x = Math.min(x + speed, 800 - width/2);
if (moveUp) y = Math.max(y - speed, height/2);
if (moveDown) y = Math.min(y + speed, 600 - height/2);
}
3. 碰撞检测系统
使用简单的矩形碰撞检测算法:
public boolean checkCollision(Enemy enemy) {
int distX = Math.abs(x - enemy.getX());
int distY = Math.abs(y - enemy.getY());
return distX < (width/2 + enemy.getWidth()/2) &&
distY < (height/2 + enemy.getHeight()/2);
}
4. 对象池管理
使用Java集合框架高效管理游戏对象:
private List enemies = new ArrayList<>();
private List playerBullets = new ArrayList<>();
private List explosions = new ArrayList<>();
5. 粒子效果实现
爆炸效果使用逐渐放大的圆形:
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x - currentRadius, y - currentRadius,
currentRadius * 2, currentRadius * 2);
}
6. 键盘事件处理
实现KeyListener接口处理用户输入:
@Override
public void keyPressed(KeyEvent e) {
// 处理键盘按下事件
}
@Override
public void keyReleased(KeyEvent e) {
// 处理键盘释放事件
}
游戏功能说明
- 玩家控制:
- 方向键控制飞机移动
- 空格键发射子弹
- 游戏结束按R键重新开始
- 敌机系统:
- 随机生成不同飞行轨迹的敌机
- 碰到屏幕边界反弹
- 计分系统:
- 击落敌机获得10分
- 屏幕上显示当前分数和生命值
- 生命系统:
- 被敌机撞击损失25点生命值
- 生命值为0时游戏结束
- 视觉特效:
- 星空背景
- 子弹发光效果
- 圆形爆炸动画
性能优化建议
- 对象池技术:重用不再使用的对象(如子弹、爆炸效果)
- 空间分区:对游戏对象进行空间划分,优化碰撞检测
- 双缓冲技术:减少画面闪烁(Swing默认已实现)
- 碰撞优化:使用距离平方代替开方运算
- 多线程:可将游戏逻辑与渲染分开至不同线程
扩展方向
- 添加多种武器系统和道具
- 实现关卡系统和BOSS战
- 添加音效和背景音乐
- 实现高分榜存储功能
- 添加敌人弹幕系统
- 实现3D渲染效果
这个飞机大战游戏展示了Java在2D游戏开发中的强大能力,代码设计遵循了面向对象原则,并包含了实用的游戏开发技术。玩家可以通过这个项目学习游戏循环、事件处理、碰撞检测等核心游戏开发概念。
致每个在宿舍挑灯夜战的你:
当简历石沉大海,当笔试频频受挫,请记住—— 大厂要的不是完美的毕业生,而是能解决问题的战士
今晚你刷的每一道场景题,都在增加未来工卡上的含金量 此刻的行动,将决定你站在西二旗还是城中村
【0秒行动点→ si我发送“666”,拿下你的Offer通行证】
(前50名可获我1v1专属答疑,职业规划一次)
编辑
编辑
编辑
编辑