I’m making Space Invaders, and the game is running with a while-loop.
When the game is not in a loop it respons to key presses, but when i have started the loop it don’t respond. It’s the same object that implements the keylistener and the loop method, so is it possible that they can’t do both at the same time? Will i have to create another object just for keylistening so i can type in loop?
I’m not entirely sure, but I think your problem is caused by not using
try{Thread.sleep(sleepTime);}catch(InterruptedException e){}
at the end of each cycle, which means the CPU is choked by the loop and doesn’t have time to process KeyEvents . I believe I’ve had the same thing happen when omitting that part of game loops.
hm i already have
try { Thread.sleep(20); } catch (Exception e) {}
now I have tried to make a keylistener both as a separate class and as a inner class, and it’s the same problem. Before the while loop starts it respons, but after it doens’t.
I have been looking at this tutorial:
http://www.cokeandcode.com/info/showsrc/showsrc.php?src=../spaceinvaders/org/newdawn/spaceinvaders/Game.java
and he did it with a private class, and I’m quite sure i did it like he did, so now I’m pretty lost ???
What Thread is your game loop running in? main, EDT, a thread you have constructed, or something else?
Post your code.
In short, this is what happens when i run the game:
The main method creates a game object --> the game waits for a “any key press” (that thing works) --> the game starts–>it initializes the player object, and starts the loop.
all the comments are danish, but i believe i made all the varibles english
Wall of code
package Main;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Game extends JPanel {
//Variabler
//True hvis spillet kører
Boolean looping = true;
//Array med spilleren og alle fjende objekterne
ArrayList<Object> spaceships = new ArrayList<Object>();
//spillets vindue
JFrame frame;
//Spillets panel som der tegnes i
JPanel panel;
//Grafikken der bruges til at tegne med
Graphics g;
//spiller objektet
Player player;
//Spillerens score
int score;
//hvor lang tid spilleren har spillet
int time;
//1/50 del af et sekund, bruges til at tælle tiden
int split_sec;
//True hvis spillet venter på at man skal gå igang
boolean press_any_key = true;
//Objektet der skal holde styr på tastetryk
KeyboardListener listener;
public Game() {
//Opret vinduet
frame = new JFrame("Space Invaders");
frame.setLocation(200,200);
panel = (JPanel)frame.getContentPane();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(650,510));
panel.setBackground(Color.black);
setBounds(0,0,650,510);
panel.add(this);
setIgnoreRepaint(true);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
requestFocus();
//Lav en KeyListener
listener = new KeyboardListener();
listener.game_link = this;
//Sæt spillet til at lytte efter tastetryk med en indre klasse
addKeyListener(listener);
//Sætter grafikken
g = panel.getGraphics();
try { Thread.sleep(1000); } catch (Exception e) {}
//Venter på spillerens start
waiting();
}
public static void main(String[] args) {
Game game = new Game();
}
public void loop(){
while (looping == true){
//Tegn baggrund
g.setColor(Color.black);
g.fillRect(0, 0, 650, 510);
//Fjendens opdatering
//Spillerens opdatering
player.step();
player.draw(g);
//Interface opdatering
interface_update();
draw_interface();
//vent 1/50 del af et sekund før løkken gentages
try { Thread.sleep(25); } catch (InterruptedException e) {}
}
}
public void init(){
//Sætter så spillet kan kører i ring
looping = true;
//Lav spilleren
player = new Player();
//Gør så spiller objektet kan refererer til dette objekt
player.game = this;
//Læg spilleren i arrayen med alle rumskib-objekterne
spaceships.add(player);
listener.player_link = player;
}
public void remove_enemy(Enemy e){
spaceships.remove(e);
}
public void add_enemy(Enemy e){
spaceships.add(e);
}
public void start_game(){
//Start et nyt spil
init();
loop();
}
public void reset(){
//Fjerner alle nuværende objekter
spaceships.clear();
//Stopper spillet
looping = false;
//Sætter så spillet venter på at man skal starte forfra
waiting();
}
public void waiting(){
//Venter på på at spilleren skal starte
press_any_key = true;
g.setColor(Color.black);
g.fillRect(0, 0, 650, 510);
g.setColor(Color.red);
g.drawString("PRESS ANY KEY", 270, 450);
}
public void draw_interface(){
//Tegn tiden
g.drawString("Time: "+time, 50, 50);
}
public void interface_update(){
split_sec++;
if (split_sec == 40) {
split_sec = 0;
time++;
}
}
}
and the KeyListener object
package Main;
import java.awt.event.*;
public class KeyboardListener implements KeyListener{
public Game game_link;
public Player player_link;
public KeyboardListener(){
}
public void keyTyped(KeyEvent e) {
if (game_link.press_any_key == true){
game_link.start_game();
game_link.press_any_key = false;
return;
}
}
public void keyPressed(KeyEvent e) {
System.out.println("Keypress test");
//Hvis piletasterne er trykket ned skal den sætte spillerens fart
if (e.getKeyCode() == KeyEvent.VK_LEFT) {player_link.set_x_speed(-3);}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {player_link.set_x_speed(3);}
if (e.getKeyCode() == KeyEvent.VK_UP) {player_link.set_y_speed(-3);}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {player_link.set_y_speed(3);}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {player_link.set_x_speed(0);}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {player_link.set_x_speed(0);}
if (e.getKeyCode() == KeyEvent.VK_UP) {player_link.set_y_speed(0);}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {player_link.set_y_speed(0);}
}
}
Your game loop is executing on the EDT (Event Dispatch Thread); hence once started you will no-longer be able to receive events.
Your code seems rather confused & is consequently far more complicated than it needs to be.
I suggest you find an example of a simple game loop demonstrating the fundamentals.
You need to separate your drawing code from your game code. Your loop needs to go in a Thread other than the EDT, and it can’t include any of the drawing methods.
Also, the “Graphics g” variable shouldn’t be an instance variable of the class. Instead, the parameter used by paintComponent should be used. Since you’re ignoring repaint, you will have to call paint yourself, and paint will call paintComponent. You should look up BufferStrategy in the Java API and the Java Tutorial to see how you’re supposed to use this.
I tried to fix up your code, but it got to be too much. It would be easier to just give you code than to try writing it all over again.
You should buy either Developing Games in Java or Killer Game Programming in Java (preferably both) from Amazon.com. After reading those two books, you’ll probably have an idea of what to do. These will explain active rendering, which it seems like you think you’re doing but you’re not.
Reading a book about threads (e.g. Java Concurrency in Practice) would probably be helpful too, but it might be overkill.
why do you have the keyboard reading in another class. there is an AWT library for it, and lwjgl and slick can do it, other probably can as well. you can just implement keyboardListener and then jsut make a method for keypress keyrelease and keyTyped I think. or jsut have it check the keys every loop if you use LWJGL or Slick.
but then again the coke and code tut did a lot of the stuff it didnt need ot do.
if there is a reason for making a class to read the keys please inform me.