My java(JFrame) player movement script won't work

﹥>﹥吖頭↗ 提交于 2021-02-08 09:20:27

问题


I am making a top down 2d survival game where the player must dodge projectiles from enemies in order to survive, but I've run into an issue that may, slightly influence the gameplay of my first real java project, that issue being that the player cannot move in any way shape or form and if the projectiles had of been implemented, then the player would lose immediately after spawning into this world.

here is the code:

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) {
        
    }
}

Input script:

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);
    }
}

thank you for any help provided.


回答1:


A couple of issues first of all:

  1. Dont extend JFrame unecessarily, you can create a JPanel and simply add it to the JFrame
  2. Never override paint instead use a JComponent like a JPanel and override paintComponent, not forgetting to call super.paintComponent as the first statement in the overriden method. Also never call paint or paintComponent directly instead use JComponent#repaint() Here is a good read on the above
  3. All Swing components should be created on the EDT
  4. Don't call setSize use an appropriate layout manager, and override getPreferredSize where needed to provide size hints to the layout manager, then call JFrame#pack() before setting the frame to be visible
  5. I suggest using KeyBindings as opposed to a KeyListener
  6. You cannot use a while loop on the same thread as your UI components or the UI will freeze and not update, instead use a Thread

I myself am creating my own Swing Game Library, which you might use as a reference for future endeavors or issues you might be facing, such as the addition of a game loop, separating your game objects logic from the game panel/screen, anti-aliasing etc.

Below is your code with the above suggestions implemented to help you get started, as well as some comments pointing you to what else you could add or change to make your game more re-usable as it grows:

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
        }

    }
}

To re-iterate, there are many more changes you could make (I've commented around the code to give you hints), but I did not do these for you as that would just be a spoiler! :)



来源:https://stackoverflow.com/questions/65735680/my-javajframe-player-movement-script-wont-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!