我的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);
}
}
感谢您提供的任何帮助.
首先有几个问题:
- 不要不必要地扩展
JFrame
,您可以创建JPanel
并将其简单地添加到JFrame
- 切勿覆盖
paint
,而应使用JComponent
之类的JComponent
并覆盖paintComponent
,不要忘记将super.paintComponent
用作覆盖方法中的第一条语句.也不要直接调用paint
或paintComponent
,而要使用JComponent#repaint()
这里是上面的好读物 - 所有Swing组件都应在 EDT 上创建
- 不要使用适当的布局管理器调用
setSize
,并在需要的地方覆盖getPreferredSize
以向布局管理器提供尺寸提示,然后调用将框架设置为可见 - 我建议使用 KeyBindings ,而不要使用
KeyListener
- 您不能在与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 } } }
再次重申,您可以进行更多更改(我已在代码中注释了提示),但是我没有为您做这些,因为那只会破坏您的生命! :)
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.
解决方案A couple of issues first of all:
- Dont extend
JFrame
unecessarily, you can create aJPanel
and simply add it to theJFrame
- Never override
paint
instead use aJComponent
like aJPanel
and overridepaintComponent
, not forgetting to callsuper.paintComponent
as the first statement in the overriden method. Also never callpaint
orpaintComponent
directly instead useJComponent#repaint()
Here is a good read on the above - All Swing components should be created on the EDT
- Don't call
setSize
use an appropriate layout manager, and overridegetPreferredSize
where needed to provide size hints to the layout manager, then callJFrame#pack()
before setting the frame to be visible - I suggest using KeyBindings as opposed to a
KeyListener
- 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! :)
这篇关于我的Java(JFrame)播放器移动脚本无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- Dont extend