我正在尝试用Java编写一个非常简单的平台游戏。我有部分工作与被动渲染(Timer
对象调用repaint()
和revalidate()
等。但我一直在尝试实现主动渲染。它有点工作 - 它呈现,动画有效,但它似乎阻止了关键的Listener(以前工作正常)由于某种原因,我真的不明白。
我在下面尽可能少地重新创建了这个问题。当你按一个键时,应该有终端输出,但没有。如果有人能告诉我为什么keyPressed
等方法没有解雇,那将非常感激。
修改 - 根据请求将修改后的演示代码整理为一个副本/粘贴
Edit2 - 正如Andrew Thompson所建议的那样,我删除了所有的全屏代码,并且keylistener仍无法正常工作
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
class FullScreenRenderWithListener implements KeyListener {
private JFrame frame;
private World world;
public static void main(String[] args)
{
FullScreenRenderWithListener main = new FullScreenRenderWithListener();
SwingUtilities.invokeLater(main::run);
}
private void run()
{
initWindow();
setupWorld();
frame.setIgnoreRepaint(true);
frame.pack();
frame.createBufferStrategy(2);
frame.setVisible(true);
world.startActive(frame.getBufferStrategy());
}
private void initWindow()
{
frame = new JFrame();
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
}
private void setupWorld()
{
world = new World();
frame.addKeyListener(this);
frame.add(world);
world.addKeyListener(this);
}
@Override
public void keyPressed(KeyEvent event)
{
System.out.println("Pressed");
}
@Override
public void keyReleased(KeyEvent event)
{
System.out.println("Released");
}
@Override
public void keyTyped(KeyEvent event)
{
System.out.println("Typed");
}
}
class World extends JPanel {
private static final int FRAMES_PER_SEC = 60;
private static final int MILL_IN_SEC = 1000;
private static final int TICK_LENGTH =
MILL_IN_SEC / FRAMES_PER_SEC;
private BufferStrategy strategy;
private void sleepUntilEndOfFrame()
{
try {
long used = System.currentTimeMillis() % TICK_LENGTH;
long left = TICK_LENGTH - used;
Thread.sleep(left);
} catch(InterruptedException e) {
// ... Handle this error
}
}
public void startActive(BufferStrategy strategy)
{
this.strategy = strategy;
setIgnoreRepaint(true);
while(true) {
doFrame();
}
}
private void doFrame()
{
updateGameState();
activeRenderFrame();
}
private void updateGameState()
{
// ..
}
private void activeRenderFrame()
{
Graphics2D graphicsContext = (Graphics2D)strategy
.getDrawGraphics();
paintComponent(graphicsContext);
strategy.show();
Toolkit.getDefaultToolkit().sync();
graphicsContext.dispose();
sleepUntilEndOfFrame();
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(500, 500);
}
// Have overridden this method because the class
// also implements passive rendering if active is
// not supported
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// .. drawing code
}
}
答案 0 :(得分:1)
首要问题是,当您使用KeyBinding
时,不要考虑使用KeyListener
策略而不是JPanel
。您可以通过注释无限while
循环(禁用活动渲染)来检查这一点。
当您使用KeyListener
时,不会使用有效渲染过程触发{或者至少我们可以说我们的侦听器未调用)。
使用KeyEvent
可以解决此问题。
但是当您取消注释无限keyBinding
循环时,问题会再次出现。那么什么能解决这个问题呢?用于更新框架的新while
是关键!
检查由Thread
提升的程序以及使用有效呈现策略更新框架的新KeyBinding
:
Thread
此示例仅为箭头键绑定了一些import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class FullScreenRenderWithListener implements Runnable
{
private JFrame frame;
private World world;
public static void main ( String[] args )
{
FullScreenRenderWithListener main = new FullScreenRenderWithListener ();
SwingUtilities.invokeLater ( main );
}
public void run ()
{
initWindow ();
setupWorld ();
frame.setIgnoreRepaint ( true );
frame.pack ();
frame.createBufferStrategy ( 2 );
frame.setVisible ( true );
world.startActive ( frame.getBufferStrategy () );
}
private void initWindow ()
{
frame = new JFrame ();
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setLocationByPlatform ( true );
}
private void setupWorld ()
{
world = new World ();
frame.add ( world );
frame.setFocusable ( true );
world.setFocusable ( true );
}
}
class World extends JPanel
{
private static final int FRAMES_PER_SEC = 10;
private static final int MILL_IN_SEC = 1000;
private static final int TICK_LENGTH = MILL_IN_SEC / FRAMES_PER_SEC;
private BufferStrategy strategy;
//
private static final String PRESSED = "Pressed";
private static final String RELEASED = "Released";
private Map < Direction , Boolean > directionMap = new HashMap < Direction , Boolean > ();
private void sleepUntilEndOfFrame ()
{
try
{
long used = System.currentTimeMillis () % TICK_LENGTH;
long left = TICK_LENGTH - used;
Thread.sleep ( left );
}
catch ( InterruptedException e )
{
// ... Handle this error
e.printStackTrace ();
}
}
private void setBindings() {
int context = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(context);
ActionMap actionMap = getActionMap();
for (Direction direction : Direction.values()) {
inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, false), direction.getName() + PRESSED);
inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, true), direction.getName() + RELEASED);
// set corresponding actions for the key presses and releases above
actionMap.put(direction.getName() + PRESSED, new ArrowKeyAction(true, direction));
actionMap.put(direction.getName() + RELEASED, new ArrowKeyAction(false, direction));
}
}
public void startActive ( BufferStrategy strategy )
{
for ( Direction direction : Direction.values () )
{
directionMap.put ( direction , Boolean.FALSE );
}
setBindings ();
//
this.strategy = strategy;
setIgnoreRepaint ( true );
Thread t = new Thread (){
@Override
public void run ()
{
while ( true )
{
doFrame ();
}
}
};
t.start ();
}
private void doFrame ()
{
updateGameState ();
activeRenderFrame ();
}
private void updateGameState ()
{
// ..
}
private void activeRenderFrame ()
{
Graphics2D graphicsContext = (Graphics2D) strategy.getDrawGraphics ();
paintComponent ( graphicsContext );
strategy.show ();
Toolkit.getDefaultToolkit ().sync ();
graphicsContext.dispose ();
sleepUntilEndOfFrame ();
}
@Override
public Dimension getPreferredSize ()
{
return new Dimension ( 500 , 500 );
}
// Have overridden this method because the class
// also implements passive rendering if active is
// not supported
@Override
public void paintComponent ( Graphics g )
{
super.paintComponent ( g );
// .. drawing code
}
private class ArrowKeyAction extends AbstractAction
{
private Boolean pressed;
private Direction direction;
public ArrowKeyAction ( boolean pressed , Direction direction )
{
this.pressed = Boolean.valueOf ( pressed );
this.direction = direction;
}
@Override
public void actionPerformed ( ActionEvent arg0 )
{
directionMap.put ( direction , pressed );
System.out.println ("Direction: "+ direction + ", State: " + pressed);
}
}
}
enum Direction {
UP("Up", KeyEvent.VK_UP, new Point(0, -1)),
DOWN("Down", KeyEvent.VK_DOWN, new Point(0, 1)),
LEFT("Left", KeyEvent.VK_LEFT, new Point(-1, 0)),
Right("Right", KeyEvent.VK_RIGHT, new Point(1, 0));
private String name;
private int keyCode;
private Point vector;
private Direction(String name, int keyCode, Point vector) {
this.name = name;
this.keyCode = keyCode;
this.vector = vector;
}
public String getName() {
return name;
}
public int getKeyCode() {
return keyCode;
}
public Point getVector() {
return vector;
}
@Override
public String toString() {
return name;
}
}
。您也可以通过更改KeyBinding
方法查看其他键。此外,您可能希望为其他键定义更多setBindings
s和另一个Event
。
希望这有帮助。