java - 在 JFrame 中没有看到矩形 Player 类

标签 java swing

我是java新手,正在尝试创建一个基本游戏,现在正在尝试对玩家类进行编程。然而,当我运行游戏时,只出现 JFRame。这些是我的 thress 类,它们没有显示错误。

import java.awt.Color;

import javax.swing.JFrame;

public class Game extends JFrame {
    public
 final static int WIDTH = 700, HEIGHT = 450;
    public
 GamePanel panel;

    public Game() {
        setSize(WIDTH, HEIGHT);
        setTitle("Game");
        setBackground(Color.WHITE);
        setResizable(false);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
         add(panel);
    }

    public GamePanel getPanel() {
        return panel;
    }

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

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements ActionListener, KeyListener {
    public
 Game game;
    public
 Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        addKeyListener(this);
        setFocusable(true);
    }

    public
 void update() {
        player.update();
    }

    public void actionPerformed(ActionEvent e) {
        update();
        repaint();
    }

        public Player getPlayer(int playerNo) {
          return player; 
        }

    public void keyPressed(KeyEvent e) {
        player.pressed(e.getKeyCode());
    }

    public void keyReleased(KeyEvent e) {
        player.released(e.getKeyCode());
    }

    public void keyTyped(KeyEvent e) {
        ;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        player.paint(g);
    }
}

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Color;

public class Player {
    public
 static final int WIDTH = 50, HEIGHT = 50;
    public
 Game game;
    public
 int left, right;
    public
 int y;
    public
 int x, xa;

    public Player(Game game, int left, int right, int x) {
        this.game = game;
        this.x = x;
        y = game.getHeight() - 20;
        this.left = left;
        this.right = right;
        this.y = y;
        x = game.getWidth() - 36;
    }

    public void update() {
        if (x > 0 && x < game.getWidth() - WIDTH - 36)
            x += xa;
        else if (x == 0)
            x++;
        else if (x == game.getWidth() - WIDTH - 36)
            x--;
    }

    public void pressed(int keyCode) {
        if (keyCode == left)
            xa = -1;
        else if (keyCode == right)
            xa = 1;
    }

    public void released(int keyCode) {
        if (keyCode == left || keyCode == right)
            xa = 0;
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, WIDTH, HEIGHT);
    }

    public void paint(Graphics g) {
        g.fillRect(x, y, WIDTH, HEIGHT);
        g.setColor(Color.ORANGE);
    }
}

最佳答案

获取setVisible(true);并将其移至Game构造函数的最后一个。此外,您还应该确保在构建 UI 时在 EDT 上下文中工作,请参阅 Initial Threads了解更多详情

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game extends JFrame {

    public final static int WIDTH = 700, HEIGHT = 450;
    public GamePanel panel;

    public Game() {
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        setSize(WIDTH, HEIGHT);
        setVisible(true);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Game();
            }
        });
    }
}

基本上,Swing 的布局管理是惰性的,它不会尝试更新容器层次结构,直到你告诉它(revalidate)或者它被实现或调整大小,这是一件好事,因为操作可能会很昂贵。

接下来,看一下 player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);

您将播放器的位置设置为比组件 width36 像素,但是当调用此函数时,width > 将是 0

基本上,您需要在进行此类调用之前让 UI“稳定下来”。这其实并不那么容易。您可以使用 ComponentListener 并监视 componentResized 事件,但是窗口在首次初始化时可以多次调整大小,为此,您需要“等待”直到尺寸“确定”,例如......

public Game() {
    addComponentListener(new ComponentAdapter() {
        private boolean initalised = false;
        private Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                initalised = true;
                panel.init();
                timer.stop();
            }
        });

        @Override
        public void componentResized(ComponentEvent e) {
            if (!initalised) {
                timer.restart();
            }
        }
    });

然后您需要更新 GamePanel 以提供 init 方法...

public class GamePanel extends JPanel implements ActionListener, KeyListener {

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

    public void init() {
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        repaint();
    }
    //...
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (player != null) {
            player.paint(g);
        }
    }
}

您有各种各样的“神奇”数字,这些数字并不等于您实际想要做的事情,例如......

player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);

不应该是game.getWidth() - Player.WIDTH吗?

然后在播放器中...

public Player(Game game, int left, int right, int x) {
    this.game = game;
    this.x = x;
    y = game.getHeight() - 20;
    //...
    this.y = y;
    x = game.getWidth() - 36;
}

您将参数x 分配给字段x,然后在构造函数末尾更改它?另外,this.y = y 毫无意义!?

现在,我们来谈谈 setSize(WIDTH, HEIGHT); 是一个多么糟糕的主意,它关系到为什么你的播放器没有出现在你想要的位置......

窗口有装饰,因此您的可视区域将始终小于实际窗口尺寸,更糟糕的是,装饰的尺寸是可变的。相反,您应该使用 JFrame#pack 将窗口打包在其内容周围,并让内容提供有关它想要的大小的提示。

看看How can I set in the midst?了解更多详情。

您应该使用pack...而不是设置框架的大小

public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }

并允许 GamePanel 决定它想要多大......

public static class GamePanel extends JPanel implements ActionListener, KeyListener {

    public final static int WIDTH = 700, HEIGHT = 450;

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(WIDTH, HEIGHT);
    }

这也意味着您不应将 Game 传递给您的对象,而应该将 GamePanel 传递给它们并使用其尺寸,例如...

public static class Player {
    //...
    public Player(GamePanel game, int left, int right, int x) {
        this.game = game;
        this.left = left;
        this.right = right;
        this.x = x;
        y = game.getHeight() - HEIGHT;
    }

您也不应该使用 KeyListener 而应该使用 Key Bindings API相反,这将解决与焦点相关的问题并使配置击键变得更容易

基本上,您缺少对 Swing 框架如何工作的一些核心理解,这会导致无穷无尽的问题,在深入研究像游戏这样复杂的内容之前,我会花时间了解更多有关该框架一般如何工作的信息发展

可运行示例...

现在,因为我基本上已经修改了你的代码以使其正常工作......

Happy Player

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Game();
            }
        });
    }

    public static class GamePanel extends JPanel implements ActionListener, KeyListener {

        public final static int WIDTH = 700, HEIGHT = 450;

        public Game game;
        public Player player;

        public GamePanel(Game game) {
            setBackground(Color.GREEN);
            this.game = game;
            addKeyListener(this);
            setFocusable(true);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(WIDTH, HEIGHT);
        }

        public void init() {
            System.out.println("!!");
            player = new Player(this, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, getWidth() - 50);
            repaint();
        }

        public void update() {
            player.update();
        }

        public void actionPerformed(ActionEvent e) {
            update();
            repaint();
        }

        public Player getPlayer(int playerNo) {
            return player;
        }

        public void keyPressed(KeyEvent e) {
            player.pressed(e.getKeyCode());
        }

        public void keyReleased(KeyEvent e) {
            player.released(e.getKeyCode());
        }

        public void keyTyped(KeyEvent e) {
            ;
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (player != null) {
                player.paint(g);
            }
        }
    }

    public static class Player {

        public static final int WIDTH = 50, HEIGHT = 50;
        public GamePanel game;
        public int left, right;
        public int y;
        public int x, xa;

        public Player(GamePanel game, int left, int right, int x) {
            this.game = game;
            this.left = left;
            this.right = right;
            this.x = x;
            y = game.getHeight() - HEIGHT;
        }

        public void update() {
            if (x > 0 && x < game.getWidth() - WIDTH - 36) {
                x += xa;
            } else if (x == 0) {
                x++;
            } else if (x == game.getWidth() - WIDTH - 36) {
                x--;
            }
        }

        public void pressed(int keyCode) {
            if (keyCode == left) {
                xa = -1;
            } else if (keyCode == right) {
                xa = 1;
            }
        }

        public void released(int keyCode) {
            if (keyCode == left || keyCode == right) {
                xa = 0;
            }
        }

        public Rectangle getBounds() {
            return new Rectangle(x, y, WIDTH, HEIGHT);
        }

        public void paint(Graphics g) {
            System.out.println(x + "x" + y);
            g.fillRect(x, y, WIDTH, HEIGHT);
            g.setColor(Color.ORANGE);
        }
    }
}

关于java - 在 JFrame 中没有看到矩形 Player 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36191150/

相关文章:

java - 为什么我的简单计时器应用程序每次暂停时都会变得更快?

java - JPMS ServiceLoader 对我不起作用

java - 对 ArrayList 类型的对象实例进行选择排序会产生奇怪的结果

java - 如何实现一个鼠标监听器,返回鼠标在 JTable 中指向的字符?

java - 在Java/Swing中,ButtonModel的isRollover()和isArmed()方法有什么区别?

java - NetBeans IDE 中的组合框不会填充从 MySQL 中提取的年份

java - 将 Java 对象传递到 Retrofit 中未正确处理

Java从堆中取消分配一个对象

java - setVgap(0)、setHgap(0) 在网格布局中不起作用?

Java:完全禁用任何 Swing 不需要的蜂鸣声的方法?