You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Swing通过持续更新坐标实现弹幕游戏抛射物移动?

Java弹幕游戏抛射物移动实现方案

核心思路

别直接写死坐标,把每个抛射物的位置、速度、形状数据封装成独立对象,在游戏循环里持续更新位置,再根据新位置重新绘制形状——这是2D游戏里移动元素的标准做法。

步骤1:封装抛射物类

把抛射物的属性(位置、速度、形状偏移)和绘制方法打包成类,批量管理子弹会更方便:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;

public class Projectile {
    // 抛射物中心坐标
    private int x;
    private int y;
    // 移动速度(x、y方向的增量)
    private int dx;
    private int dy;
    // 形状相对于中心的偏移量(从你原来的固定坐标提取)
    private static final int[] RELATIVE_X = {0, 4, 7, 7, 2, -4, -12, -12, -7, -5};
    private static final int[] RELATIVE_Y = {-20, -14, -10, 8, 20, 20, 8, -10, -16, -20};
    private static final double INNER_SCALE = 0.8; // 内部高亮的缩放比例

    public Projectile(int startX, int startY, int speedX, int speedY) {
        this.x = startX;
        this.y = startY;
        this.dx = speedX;
        this.dy = speedY;
    }

    // 更新位置
    public void update() {
        x += dx;
        y += dy;
    }

    // 绘制抛射物
    public void draw(Graphics g) {
        // 绘制外层橙色多边形
        g.setColor(Color.ORANGE);
        Polygon outer = new Polygon();
        for (int i = 0; i < RELATIVE_X.length; i++) {
            outer.addPoint(x + RELATIVE_X[i], y + RELATIVE_Y[i]);
        }
        g.fillPolygon(outer);

        // 绘制内层青色高亮
        g.setColor(Color.CYAN);
        Polygon inner = new Polygon();
        for (int i = 0; i < RELATIVE_X.length; i++) {
            int scaledX = (int) (RELATIVE_X[i] * INNER_SCALE);
            int scaledY = (int) (RELATIVE_Y[i] * INNER_SCALE);
            inner.addPoint(x + scaledX, y + scaledY);
        }
        g.fillPolygon(inner);
    }
}

说明:RELATIVE_X/Y是从你原来的固定坐标(中心220,120)计算出的偏移量,比如原来的点220,100对应偏移0,-20,移动时只用改x/y中心值,不用重新定义所有点。

步骤2:实现游戏循环与渲染

用Swing的Timer驱动游戏循环,定时更新所有抛射物位置并重新绘制:

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class BulletHellGame extends JPanel implements ActionListener {
    private ArrayList<Projectile> projectiles = new ArrayList<>();
    private Timer gameTimer;

    public BulletHellGame() {
        // 初始化游戏循环(每16ms触发一次,约60帧)
        gameTimer = new Timer(16, this);
        gameTimer.start();

        // 添加测试抛射物,比如向下移动,速度(0,3)
        projectiles.add(new Projectile(220, 120, 0, 3));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 清屏(背景色设为黑色)
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());

        // 更新并绘制所有抛射物
        for (Projectile p : projectiles) {
            p.update();
            p.draw(g);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 触发重绘
        repaint();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Bullet Hell Game");
        frame.setSize(800, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new BulletHellGame());
        frame.setVisible(true);
    }
}

说明:

  • paintComponent是Swing的绘制入口,每次repaint()都会调用它
  • 先清屏再绘制,避免残留上一帧的图像
  • Timer的16ms间隔对应约60FPS,保证移动流畅

扩展建议

  • 添加生命周期判断:抛射物超出屏幕后从列表移除,避免内存占用
  • 用浮点数存储位置和速度,实现更平滑的移动(需把x/y改为double类型,绘制时强转int)
  • 批量生成抛射物时,直接往projectiles列表中添加新对象即可

内容的提问来源于stack exchange,提问作者shge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 08:57:47