Colin Jang
Colin Jang

Reputation: 5

keyListener with Swing and game level system with Swing/keyListener and Thread

I am a novice coder, have a tiny bit of experience with C++ about 10 years ago and now learning java (it's been about 4-5 months). I have a little collaborative project going, and I've got some things to figure out.

Here's the code:

import java.awt.event.*;
import java.awt.*;

import javax.swing.JFrame;

import java.util.Scanner;
import java.util.Random;

public class Game extends JFrame {


    GamePanel panel;
    int[][] grid;
    int size;

    //...and some other variables

    public Game(String title) {

        super(title);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        panel = new GamePanel(grid,size);
        this.add(panel);

        Button button = new Button("WHAT");
        button.setBounds(-100, -100, 70, 70);
        this.add(button);
        button.addKeyListener(new KeyHandler());

    }

    class KeyHandler extends KeyAdapter {

        public void keyPressed(KeyEvent e) {

            int keycode = e.getKeyCode();

            switch(keycode) {

                //arrow keys input and stuff

            }

            if(checkForWin())  //checkForWin() returns a boolean value for win/loss
                //won the game, thus end the thread here

            if(checkForLoss()) // similar stuff as checkForLoss()
                //lost the game, thus end the thread here

            //...update the panel
            panel.repaint();

        }

    }

    public static void main(String [] args) {

        Game me = new Game("GAME");

        me.setVisible(true);

    }

}

So that's pretty much how the whole game thing looks like.

And I have questions:

  1. I am using a button and put it at a negative position to make it invisible and using it as a mean of KeyListener. Is there any other way to add a key listener? ex) to the panel or something?

  2. I want to change it so that each "level" is a thread and make it like

    public static void main(String [] args) {
    
        int level = 1;
    
        do {
    
            GameThread gt = new GameThread("Game");
    
            // run() will have the game constructor inside
    
            gt.setLevel(level);
            gt.start();
            gt.join();       //wait until the game "level" is finished
    
            if(won)
                level++;
    
            if(lost)
                level = 1;
    
        } while(!checkIfDonePlaying())
    
    }
    

Somewhat like this. I'm having trouble making the thread continue to run until the game level is actually finished. How do I do that?

  1. I want to add a JLabel to show the score on the frame. But when I do that, the score doesn't update when I repaint() it. How do I do that?

Thanks in advance!

Upvotes: 0

Views: 133

Answers (2)

TNT
TNT

Reputation: 2920

A few things:

  1. Yes, there is a way to add a KeyListener to the panel, and that's by using key bindings. For example:

    javax.swing.InputMap im = panel.getInputMap(panel.WHEN_IN_FOCUSED_WINDOW);
    javax.swing.ActionMap am = panel.getActionMap();
    
    im.put(javax.swing.KeyStroke.getKeyStroke("pressed UP"), "up");
    am.put("up", new javax.swing.AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ev) {
            // handle up arrow key action here
        }
    });
    
  2. Swing is an event-driven environment, so do-while loops should not be used. Instead, use a Swing timer that periodically checks if your level has been completed.

  3. Since you're not doing any custom painting on your JLabel, you shouldn't be using repaint. Instead, use its setText method.

Upvotes: 1

jaronoff97
jaronoff97

Reputation: 451

Here's a solution for your first issue:

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

Then you should just be able to do the usual key listener methods. Be sure to implement KeyListener! Solutions for your other issues on their way. (Actually take @TNT 's suggestion and use keybindings, I'm more comfortable with listeners but for games I usually use lwjgl or slick2d)

2.

I feel that running your programs levels may be a bit inefficient (that may just be me) I would suggest having one thread in a run method and have the following:

Public void reset(int level)
 {
   //reset all variables based on local variable level...

}

Call it like this:

Reset(++currentLevel)); //use ++ before currentLevel so it adds to it and then resets

And you could easily use switch cases to do some special stuff if you want

Switch(level){
case 1: //...
}

And so forth. (I'm typing on mobile sorry for weird caps)

Upvotes: 0

Related Questions