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

添加至JPanel的JComponent不显示?吸血鬼幸存者类游戏开发问题

问题与解答

问题描述

我正在开发一款类似《吸血鬼幸存者》的游戏,目前尝试让可操作角色显示在屏幕上。实现思路是:创建带图片的JPanel作为背景,再在其上添加HeroComponent和MonstersComponent(当前先处理角色部分)。设计逻辑为玩家始终处于屏幕中央,当玩家向右移动时,背景JPanel和所有怪物向相反方向移动,以此营造移动错觉。

但遇到问题:将HeroComponent添加到JPanel时角色不显示,不过直接添加到JFrame时可正常显示。相关代码如下:

GameWindow类

public class GameWindow {
    private JFrame frame;
    private Hero hero;
    private GameBackgroundPanel backgroundPanel;

    public GameWindow(JFrame frame, Hero hero) {
        this.frame = frame;
        this.hero = hero;
        backgroundPanel = new GameBackgroundPanel();
//        frame.add(backgroundPanel, BorderLayout.CENTER);

        frame.setLayout(new BorderLayout());
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setUndecorated(true);
        frame.setResizable(false);

        frame.setContentPane(backgroundPanel);
    }

    public void startWindow() {
        frame.setVisible(true);
    }
}

GameBackgroundPanel类

public class GameBackgroundPanel extends JPanel {
    public int backgroundX = 0, backgroundY = 0;
    private ImageIcon icon = new ImageIcon("src/se/liu/rodis915/mineIsAPicture/poggers.png");
    private Hero hero = new HeroA();

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
//        Graphics2D g2d = (Graphics2D)g;
        HeroToComponent heroComponent = new HeroToComponent(hero);
        setLayout(new FlowLayout());
        setOpaque(false);
        g.drawImage(icon.getImage(), backgroundX, backgroundY, getWidth(), getWidth(), null);
        add(heroComponent, BorderLayout.CENTER);
    }
}

我的疑问:

  1. 猜测问题出在JPanel的布局、代码执行顺序等方面,希望解决角色不显示的问题。
  2. 若移动JPanel的位置,内部所有组件是否会随之移动?如果可以,该如何实现?
  3. 原本想直接向JFrame添加多个组件,但发现无法添加多个,对此感到困惑。

解决方案

1. 角色不显示问题修复

你的GameBackgroundPanel存在几个核心错误:

  • 在paintComponent中添加组件、设置布局:paintComponent是组件绘制方法,会被频繁调用(窗口重绘、最小化恢复等),每次调用都创建新组件并添加,会导致组件重复创建、性能急剧下降,同时打乱布局管理器的工作逻辑。
  • 布局约束冲突:你设置了FlowLayout,却用BorderLayout.CENTER的约束添加组件,FlowLayout不识别该约束,会直接忽略,导致组件位置异常甚至不显示。
  • 初始化时机错误:组件添加和布局设置应该在面板构造方法中完成,而非绘制方法。

修改后的GameBackgroundPanel示例:

public class GameBackgroundPanel extends JPanel {
    public int backgroundX = 0, backgroundY = 0;
    private ImageIcon icon = new ImageIcon("src/se/liu/rodis915/mineIsAPicture/poggers.png");
    private Hero hero = new HeroA();

    public GameBackgroundPanel() {
        // 构造方法中完成初始化
        setLayout(new BorderLayout()); // 用BorderLayout实现角色居中
        setOpaque(false);
        HeroToComponent heroComponent = new HeroToComponent(hero);
        add(heroComponent, BorderLayout.CENTER);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 仅负责绘制背景
        g.drawImage(icon.getImage(), backgroundX, backgroundY, getWidth(), getHeight(), null);
    }
}

2. JPanel移动与内部组件同步

是的,JPanel作为容器,它的位置变化会带动内部所有子组件一起移动——因为子组件的坐标是相对于父容器左上角的相对坐标。

实现方式分两种场景:

  • 直接移动容器:调用JPanel的setLocation(x, y)方法更新坐标即可,内部组件会自动同步位置。
  • 背景滚动(游戏场景推荐):不移动容器本身,而是在paintComponent中修改背景图片的绘制坐标(即你的backgroundX/backgroundY),同时手动同步怪物组件的位置(相对于背景偏移)。这种方式性能更高,无需频繁触发容器和子组件的重排。

3. JFrame添加多个组件的方法

JFrame默认使用BorderLayout,直接调用frame.add(component)时,组件会默认放到BorderLayout.CENTER位置——而BorderLayout的每个位置(CENTER、NORTH、SOUTH、EAST、WEST)只能放置一个组件,重复添加会覆盖之前的组件。

要添加多个组件,有两种常用方式:

  • 使用中间容器:把多个组件放到一个JPanel中,再将这个JPanel添加到JFrame的布局位置。示例:
JPanel contentPanel = new JPanel();
contentPanel.setLayout(new FlowLayout()); // 根据需求选择布局
contentPanel.add(heroComponent);
contentPanel.add(monsterComponent);
frame.add(contentPanel, BorderLayout.CENTER);
  • 更换布局管理器:将JFrame的布局改为FlowLayout、GridLayout等支持多组件的布局,或使用null布局(不推荐,手动管理坐标繁琐且易出问题)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:33:31