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

Java Swing双玩家躲猫猫游戏:GameManager适配改造求助

解决方案:重构游戏对象结构以支持双玩家

你当前的问题核心是将每个玩家作为独立JPanel加入JFrame,这种设计不符合游戏开发的常规模式:Swing布局管理器会自动调整组件位置,手动设null布局后JPanel默认尺寸为0x0,导致面板消失;且多JPanel的独立坐标体系会让碰撞检测、统一绘制变得异常复杂。

正确思路是:用单一游戏画布面板承载所有游戏对象的绘制与输入处理,玩家仅作为普通数据类存在,不再是UI组件。


1. 重构GameObject为普通类(取消JPanel继承)

去掉UI组件相关逻辑,只保留游戏对象核心属性与绘制方法:

import java.awt.Graphics;
import java.awt.Image;

abstract class GameObject {
    protected int x;
    protected int y;
    protected int width;
    protected int height;
    protected Image image;

    public GameObject(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    // 供画布调用的绘制方法
    public void draw(Graphics g) {
        if (image != null) {
            g.drawImage(image, x, y, width, height, null);
        }
    }

    // 获取碰撞矩形(用于碰撞检测)
    public java.awt.Rectangle getBounds() {
        return new java.awt.Rectangle(x, y, width, height);
    }

    // Getter/Setter
    public int getX() { return x; }
    public void setX(int x) { this.x = x; }
    public int getY() { return y; }
    public void setY(int y) { this.y = y; }
}

2. 修改Player类,适配新的GameObject

保留移动、精灵切换逻辑,去掉JPanel相关代码:

import java.awt.event.KeyEvent;

class Player extends GameObject {
    private char type;
    private int speed;
    private char directionX = 'R';
    private boolean isMoving = false;
    private String[] sprites;

    public Player(int x, int y, int width, int height, char type) {
        super(x, y, width, height);
        this.type = type;

        String spritesSurvivor[] = {"src/char1.gif", "src/char2.gif", "src/charRun1.gif", "src/charRun2.gif", "src/dead.gif"};
        String spritesHunter[] = {"src/hunter1.gif", "src/hunter2.gif", "src/hunterRun1.gif", "src/hunterRun2.gif", "src/dead.gif"};
        
        if (type == 'S') {
            sprites = spritesSurvivor;
            speed = 10;
        } else if (type == 'H') {
            sprites = spritesHunter;
            speed = 15;
        }

        changeSprite();
    }

    // 区分玩家按键:猎人用WASD,幸存者用方向键
    public void move(int keyCode) {
        isMoving = true;
        switch (keyCode) {
            // 猎人控制
            case KeyEvent.VK_W: y -= speed; break;
            case KeyEvent.VK_S: y += speed; break;
            case KeyEvent.VK_A: x -= speed; directionX = 'L'; break;
            case KeyEvent.VK_D: x += speed; directionX = 'R'; break;
            // 幸存者控制
            case KeyEvent.VK_UP: if (type == 'S') y -= speed; break;
            case KeyEvent.VK_DOWN: if (type == 'S') y += speed; break;
            case KeyEvent.VK_LEFT: if (type == 'S') { x -= speed; directionX = 'L'; } break;
            case KeyEvent.VK_RIGHT: if (type == 'S') { x += speed; directionX = 'R'; } break;
        }
        checkBounds();
        changeSprite();
    }

    public void stop(int keyCode) {
        isMoving = false;
        changeSprite();
    }

    private void changeSprite() {
        // 保留原有精灵切换逻辑,示例如下
        if (isMoving) {
            image = java.awt.Toolkit.getDefaultToolkit().getImage(sprites[directionX == 'R' ? 2 : 3]);
        } else {
            image = java.awt.Toolkit.getDefaultToolkit().getImage(sprites[directionX == 'R' ? 0 : 1]);
        }
    }

    private void checkBounds() {
        // 替换为实际画布尺寸,可通过构造函数传入GamePanel引用获取
        x = Math.max(0, Math.min(x, getWidth() - width));
        y = Math.max(0, Math.min(y, getHeight() - height));
    }
}

3. 创建GamePanel作为游戏画布

负责绘制所有玩家、处理键盘输入、检测碰撞:

import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;

class GamePanel extends JPanel implements Runnable {
    private Player hunter;
    private Player survivor;
    private Thread gameThread;
    private boolean isGameRunning = true;

    public GamePanel() {
        // 初始化双玩家初始位置
        hunter = new Player(100, 100, 50, 50, 'H');
        survivor = new Player(800, 500, 50, 50, 'S');

        // 键盘监听(需获取焦点)
        setFocusable(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                hunter.move(e.getKeyCode());
                survivor.move(e.getKeyCode());
            }

            @Override
            public void keyReleased(KeyEvent e) {
                hunter.stop(e.getKeyCode());
                survivor.stop(e.getKeyCode());
            }
        });

        // 启动游戏循环线程
        gameThread = new Thread(this);
        gameThread.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 绘制背景(可选)
        g.setColor(java.awt.Color.LIGHT_GRAY);
        g.fillRect(0, 0, getWidth(), getHeight());

        // 绘制双玩家
        hunter.draw(g);
        survivor.draw(g);
    }

    @Override
    public void run() {
        // 60FPS固定帧率游戏循环
        long lastTime = System.nanoTime();
        double nsPerTick = 1000000000.0 / 60;
        double delta = 0;

        while (isGameRunning) {
            long now = System.nanoTime();
            delta += (now - lastTime) / nsPerTick;
            lastTime = now;

            if (delta >= 1) {
                checkCollision();
                repaint();
                delta--;
            }
        }
    }

    // 碰撞检测逻辑
    private void checkCollision() {
        if (hunter.getBounds().intersects(survivor.getBounds())) {
            isGameRunning = false;
            System.out.println("游戏结束!猎人抓住了幸存者!");
            // 可添加弹窗、重置等结束逻辑
        }
    }
}

4. 修改GameManager,接入GamePanel

现在只需将画布加入JFrame即可:

import javax.swing.JFrame;

class GameManager extends JFrame {
    public GameManager() {
        setTitle("Hide and Seek");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        setResizable(true);

        add(new GamePanel());
        setVisible(true);
    }

    public static void main(String[] args) {
        new GameManager();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:45:20