【问题标题】:Updating variables with an EventListener使用 EventListener 更新变量
【发布时间】:2017-02-04 03:50:29
【问题描述】:

我已经开始了自学java游戏设计的过程,我遇到了我的第一个障碍:我有一个KeyListener对象,当用户点击左右键时,它会被立即调用。当它被调用时,我让控制台打印“这有效”,并且我将 vel 更新为 1 或 -1。但是,在控制台打印时,vel 不会更新。这是为什么呢?

public class Paddle{

private int width = 100;
private int height = 15;
private int winWidth;
private int posX;
private int posY;
int vel = 0;
Game game;

public Paddle(){

}
public Paddle(int winWidth, int winHeight, Game game){
    posX = winWidth / 2;
    posY = winHeight - 70;
    this.winWidth = winWidth;
    this.game = game;
}
**public void move(){
    if((posX + vel < winWidth) && (posX + vel > 0)){
        posX += vel;
    }
}**
public void paint(Graphics2D g){
    g.setColor(Color.BLACK);
    g.fillRect(posX, posY, width, height);
}
**public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
        System.out.println("This works");
        this.vel = 1;
    }
    if(e.getKeyCode() == KeyEvent.VK_LEFT){
        vel = -1;
    }
}
public void keyReleased(KeyEvent e) {
    vel = 0;
}**
}

.

public class Keyboard implements KeyListener{

Paddle paddle = new Paddle();

@Override
public void keyPressed(KeyEvent e) {
    paddle.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {       
    paddle.keyReleased(e);
}
@Override
public void keyTyped(KeyEvent e) {
    //Not using it
}
}

.

public class Game extends JPanel{

public int width = 900;
public int height = width / 16 * 9;
private static boolean running = true;

Ball ball = new Ball(width, height, this);
Paddle paddle = new Paddle(width, height, this);
Keyboard keyboard = new Keyboard();

public Game(){
    JFrame frame = new JFrame("Mini Tennis");

    this.addKeyListener(keyboard);
    this.setFocusable(true);

    frame.add(this);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(width, height);;
    frame.setLocationRelativeTo(null);
    System.out.println(frame.getHeight());
}
public void move(){
    ball.move();
    paddle.move();
}
public void paint(Graphics g){
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;
    ball.paint(g2d);
    paddle.paint(g2d);
}
public void gameOver(){
    running = false;
    System.out.println("Game Over");
}
public static void main(String[] args) throws InterruptedException{
    Game game = new Game();

    while(running){
        game.move();
        game.repaint();

        Thread.sleep(10);
    }
}
}

【问题讨论】:

  • 当我们处于学习模式时,让我们看看一些直接的问题/改进。作为一般建议,您应该覆盖paintComponent 而不是paint,这可能不会对您产生巨大的影响,但以后可能会在您的脸上炸毁。在您更好地了解自己在做什么之前,我会避免使用线程(或您的 while 循环)作为更新机制,Swing 不是线程安全的,相反,请考虑使用 Swing 计时器。您应该避免使用 KeyListener 而更喜欢 Key Bindings API,它修复了与焦点相关的问题并提供了更可重用的结构
  • 您遇到的问题是 KeyListener 正在更改的 Paddle 实例与您正在绘制的实例不同。作为一个想法,您的 KeyListener 应该设置某种状态变量,然后在更新循环运行时将其传递给游戏元素,这将输入机制与游戏元素分开,从而更容易更改
  • @MadProgrammer 非常感谢您的反馈!我一定会考虑所有这些建议。然而,我确实有两个非常愚蠢的问题。当您说游戏元素时,您指的是什么,您能否给我一个 KeyListener 传递状态变量的示例。很抱歉我在 Java 基础知识方面工作了一段时间,但我刚刚转向游戏开发。

标签: java swing keylistener keyevent updating


【解决方案1】:

您在键盘类中声明了以下内容,

Paddle paddle = new Paddle();

这意味着您要递增的 v 与 Game.java 类中的 v 不同

您应该将 paddle 对象传递给 Keyboard 类。

你的 Paddle 类应该是这样的,

public class Keyboard implements KeyListener {

Paddle paddle;

public Keyboard(Paddle paddel) {
    this.paddle = paddel;
}

@Override
public void keyPressed(KeyEvent e) {
    paddle.keyPressed(e);
}

@Override
public void keyReleased(KeyEvent e) {
    paddle.keyReleased(e);
}

@Override
public void keyTyped(KeyEvent e) {
    // Not using it
}
}

并且在 Game 类中而不是

Keyboard keyboard = new Keyboard();

这个应该加上,

Keyboard keyboard = new Keyboard(paddle);

如果您有任何疑问,请告诉我。

【讨论】:

  • 更好的解决方案是将输入与更新周期解耦,而不是将球拍传递给KeyListener,KeyListener 应该改变游戏模型的状态,球拍从中更新自
  • @MadProgrammer 从设计的角度来看,您是对的。谢谢。
【解决方案2】:

当一个键被使用时,它被按下然后释放。然后,您的 vel 变量在按键事件期间更改为 1 或 -1,然后在释放时重置为 0。

【讨论】:

  • 这不会对显示的桨的当前状态产生太大影响
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 2020-03-21
相关资源
最近更新 更多