簡體   English   中英

我的 java(JFrame) 播放器移動腳本無法運行

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

我正在制作一款自上而下的 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);
    }
}

感謝您提供的任何幫助。

首先有幾個問題:

  1. 不要不必要地擴展JFrame ,您可以創建一個JPanel並將其簡單地添加到JFrame
  2. 永遠不要覆蓋paint而是使用像JPanel這樣的JComponent並覆蓋paintComponent ,不要忘記調用super.paintComponent作為覆蓋方法中的第一條語句。 也不要直接調用paintpaintComponent而是使用JComponent#repaint()是對上面的一個很好的閱讀
  3. 應在EDT上創建所有 Swing 組件
  4. 不要調用setSize使用適當的布局管理器,並在需要時覆蓋getPreferredSize以向布局管理器提供大小提示,然后在將框架設置為可見之前調用JFrame#pack()
  5. 我建議使用KeyBindings而不是KeyListener
  6. 您不能在與 UI 組件相同的線程上使用while 循環,否則 UI 將凍結而不更新,而是使用線程

我自己正在創建自己的Swing 游戲庫,您可以將其用作未來努力或可能面臨的問題的參考,例如添加游戲循環,將游戲對象邏輯與游戲面板/屏幕分離,反別名等

下面是您的代碼,其中包含為幫助您入門而實施的上述建議,以及一些評論,指出您還可以添加或更改哪些內容,從而使您的游戲隨着游戲的發展更具可重用性:

在此處輸入圖像描述

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
        }

    }
}

重申一下,您可以進行更多更改(我已經對代碼進行了評論以給您提示),但我沒有為您做這些,因為那只是一個劇透::)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM