0

I have begun the process of teaching myself java game design, and I have run into my first obstacle: I have a KeyListener object which is called right now when the user clicks the right or left keys. When it is called I am having the console print "this works", and I am updating vel to 1 or -1. However, while the console is printing vel will not update. Why is this?

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);
    }
}
}
K Newman
  • 56
  • 5
  • 2
    While we're in a learning mode, Let's look at some immediate issues/improvements. As a general recommendation, you should override paintComponent instead of paint, may not make a huge difference to you right know, but could blow up in your face later. I'd avoid using a thread (or your while loop) as an update mechanism until you have a better idea of what you're doing, Swing is not thread safe, instead, consider using a Swing Timer. You should avoid KeyListener and prefer the Key Bindings API, it fixes the focus related issues and provides for s more reusable structure – MadProgrammer Feb 04 '17 at 04:04
  • 2
    The issue you're having is the instance of Paddle that the KeyListener is changing isn't the same one you are painting. As an idea, your KeyListener should be setting some kind of state variable(s), which is then passed to the game elements when your update loop runs, this separates input mechanism from the game elements, which makes it easier to change – MadProgrammer Feb 04 '17 at 04:08
  • @MadProgrammer thank you so much for the feedback! I will definitely take all of this advice into consideration. I do have two very stupid questions however. What are you referring to when you say game elements and can you give me an example of the KeyListener passing a state variable. I am sorry for the confusion I have worked with java basics for some time, but I have just moved to game development. – K Newman Feb 04 '17 at 04:21
  • [Thats a partial example](http://stackoverflow.com/questions/22748547/java-swing-timer-only-works-once-then-keyevents-fire-in-rapid-succession-holdi/22749251#22749251) – MadProgrammer Feb 04 '17 at 04:44
  • [And another example](http://stackoverflow.com/questions/34125578/gradually-accelerate-sprite-on-key-pressed-gradually-decelerate-on-key-released/34126260#34126260) – MadProgrammer Feb 04 '17 at 04:46

2 Answers2

0

You declared following in Keyboard calss,

Paddle paddle = new Paddle();

which means the v which you are incrementing is different from the v which is there in the class Game.java

you should either pass paddle object to Keyboard calss.

Your Paddle class should be like,

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

And in Game class instead of

Keyboard keyboard = new Keyboard();

This should be added,

Keyboard keyboard = new Keyboard(paddle);

Let me know if you have any doubt.

NewToJava
  • 149
  • 2
  • 11
  • A better solution would be to decouple the input from the update cycle, instead of passing paddle to the `KeyListener`, the `KeyListener` should be changing the state of the game model, from which the paddle is updated from – MadProgrammer Feb 04 '17 at 05:42
  • @MadProgrammer you are right from the design point of view. Thanks. – NewToJava Feb 04 '17 at 08:23
0

When a key is used, it is pressed then released. Your vel variable is then changed to 1 or -1 during the key pressed event then reset to 0 when it is released.

Zelig63
  • 1,592
  • 1
  • 23
  • 40