我的java(JFrame)播放器移动脚本赢得';行不通

我的java(JFrame)播放器移动脚本赢得';行不通,java,swing,jframe,keylistener,Java,Swing,Jframe,Keylistener,我正在制作一个自上而下的2d生存游戏,玩家必须躲避敌人的炮弹才能生存,但我遇到了一个问题,可能会稍微影响我第一个真正java项目的游戏性,这个问题是玩家不能以任何形式移动,如果炮弹已经实现,那么玩家在产卵到这个世界后会立即失败 代码如下: package maximiza; import java.awt.*; import java.awt.event.KeyEvent; import javax.swing.*; public class Game extends JFrame {

我正在制作一个自上而下的2d生存游戏,玩家必须躲避敌人的炮弹才能生存,但我遇到了一个问题,可能会稍微影响我第一个真正java项目的游戏性,这个问题是玩家不能以任何形式移动,如果炮弹已经实现,那么玩家在产卵到这个世界后会立即失败

代码如下:

package maximiza;

import java.awt.*;
import java.awt.event.KeyEvent;

import javax.swing.*;

public class Game extends JFrame {

    private static final long serialVersionUID = 1L;

    public int xPosition = 240;
    public int yPosition = 240;
    public int speed = 10;
    
    public int playerSize = 20;
    
    public Game()
    {
        setTitle("Maximiza");
        setSize(500, 500);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    
    public void paint(Graphics g)
    {
        g.setColor(Color.yellow);
        g.fillRect(xPosition, yPosition, playerSize, playerSize);
    }
    
    public void init()
    {
        addKeyListener(new Input(this));
    }
    
    public static void main(String [] args)
    {
        boolean living = true;
        Game g = new Game();
        g.init();
        while(living)
        {
            g.paint(null);
        }
    }

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
    
        if(key == KeyEvent.VK_UP) {
            yPosition += speed;
        } else if(key == KeyEvent.VK_DOWN) {
            yPosition -= speed;
        }
    }
    
    public void keyReleased(KeyEvent e) {
        
    }
}
输入脚本:

package maximiza;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class Input extends KeyAdapter {
    
    Game game;
    
    public Input(Game game) {
        this.game = game;
    }
    
    public void keyPressed(KeyEvent e) {
        game.keyPressed(e);
    }
    
    public void keyReleased(KeyEvent e) {
        game.keyReleased(e);
    }
}

感谢您提供的帮助。

首先有几个问题:

  • 不要不必要地扩展
    JFrame
    ,您可以创建一个
    JPanel
    ,只需将其添加到
    JFrame
  • 永远不要重写
    paint
    ,而是像
    JPanel
    一样使用
    JComponent
    并重写
    paintComponent
    ,不要忘记调用
    super.paintComponent
    作为重写方法中的第一条语句。另外,切勿直接调用
    paint
    paintComponent
    ,而应使用
    JComponent#repaint()
    阅读上述内容
  • 所有Swing组件都应在上创建
  • 不要调用
    setSize
    使用适当的布局管理器,在需要向布局管理器提供尺寸提示的地方覆盖
    getPreferredSize
    ,然后在将框架设置为可见之前调用
    JFrame#pack()
  • 我建议使用而不是
    KeyListener
  • 不能在与UI组件相同的线程上使用while循环,否则UI将冻结而不更新,而是使用
  • 我自己正在创建我自己的,您可以将其作为未来努力或可能面临的问题的参考,例如添加游戏循环、将游戏对象逻辑与游戏面板/屏幕分离、消除锯齿等

    下面是您的代码,其中包含上述建议以帮助您入门,以及一些注释,指出您还可以添加或更改哪些内容,以使您的游戏在发展过程中更具可重用性:

    要重新迭代,您可以进行更多的更改(我已经对代码进行了注释,以提供提示),但我没有为您执行这些操作,因为这只会是一个扰流器!)

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyEvent;
    import javax.swing.*;
    
    public class Game {
    
        private GamePanel gamePanel;
    
        public Game() {
            createAndShowUI();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(Game::new);
        }
    
        private void createAndShowUI() {
            JFrame frame = new JFrame("Maximiza");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            gamePanel = new GamePanel();
    
            gamePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP pressed");
            gamePanel.getActionMap().put("UP pressed", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    gamePanel.moveUp(); // this would be something like gameObject.moveDown()
                }
            });
            gamePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN pressed");
            gamePanel.getActionMap().put("DOWN pressed", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    gamePanel.moveDown(); // this would be something like gameObject.moveDown()
                }
            });
    
            frame.add(gamePanel);
            frame.pack();
            frame.setVisible(true);
    
            // a more approrpiate game loop can be used as we only need to call repaint 60 times per second not more or less.
            // fixed step: https://stackoverflow.com/questions/13739693/java-swing-based-game-framework-any-advice/13740162#13740162
            // variable step: https://github.com/davidkroukamp/SwingGameLibrary/blob/main/src/za/co/swinggamelibrary/GameLoop.java
            Thread gameLoop = new Thread(() -> {
                boolean living = true;
                while (living) {
                    gamePanel.repaint();
    
                    // lets sleep a bit not to eat up processor time unnecessarily needs a better implementation of a game loop but thread sleep will do okay for now
                    try {
                        Thread.sleep(16);
                    } catch (InterruptedException ex) {
                    }
                }
            });
            gameLoop.start();
        }
    
        public class GamePanel extends JPanel {
    
            // these properties should go into its own game object which is separated from the game panel, and can simply be added to the game panel via a list
            // and in the paintComponent method you simply iterate all the game objects and draw them
            // https://github.com/davidkroukamp/SwingGameLibrary-Samples/blob/main/sample1/src/sgltest/Player.java
            public int xPosition = 240;
            public int yPosition = 240;
            public int speed = 10;
    
            public int playerSize = 20;
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                // can make graphics look better too using some rendering hints https://github.com/davidkroukamp/SwingGameLibrary/blob/main/src/za/co/swinggamelibrary/Graphics2DHelper.java
                // should move to game object inside a render(Graphics2D g2d) method which gets called for each game object passing in the graphics parameter
                g.setColor(Color.yellow);
                g.fillRect(xPosition, yPosition, playerSize, playerSize);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(500, 500);
            }
    
            // these methods would go into the game object class too under a single move methid which checks booleans on whether to move up or down or whatever
            public void moveUp() {
                yPosition -= speed; // this could probably just set a boolean which your game object will check and update its position accordingly via a move() method thats called before gamePanel.repaint in the thread
            }
    
            public void moveDown() {
                yPosition += speed; // this could probably just set a boolean which your game object will check and update its position accordingly via a move() method thats called before gamePanel.repaint in the thread
            }
    
        }
    }