Java: проблемы с KeyListener в игре Space Invaders

Я пытаюсь реализовать KeyListener в игре Space Invaders на Java, чтобы переместить корабль (сейчас это просто красный прямоугольник).

Я думаю, что это хорошо реализовано, но я не могу заставить его работать.

Вот корабельный:

import java.awt.Color;  
import java.awt.Graphics;  

public class Nave{

int x, y;
int AnchoNave = 40, AltoNave = 40;  // WIDTH_SHIP and HIGH_SHIP
Finestra f;                         // WINDOW
int velocidad = 4, v = 0;           // VELOCITY
Joc j;

Nave(Finestra f, int x, int y){
    this.f = f;
    this.x = x;
    this.y = y;
}

void pintaNave(Graphics g){

    g.setColor(Color.RED);
    g.drawRect(x, y, AnchoNave, AltoNave);
    g.setColor(Color.RED);
    g.fillRect(x, y, AnchoNave, AltoNave);

}

void movimiento(){  // this is not in the loop now.

    x+=velocidad;
    if (x>f.AMPLE-AnchoNave-10){
        x=0;
    }  

}  

}

Вот окно:

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import javax.swing.JFrame;

public class Finestra extends JFrame implements ActionListener,  KeyListener{

Image im;
Graphics g;
int AMPLE=600,ALT=500;     // WIDTH and HIGH
Joc j;

Nave nave;                 // Nave = SHIP
int velocidad = 10;        // VELOCITY

public static void main(String[] args) {
    new Finestra();        // Finestra = WINDOW
}

Finestra(){

    super("-+- Space Invaders -+-");
    setVisible(true);
    setSize(AMPLE,ALT);
    im=this.createImage(AMPLE, ALT);
    g=im.getGraphics();
    j=new Joc(this);
    j.playing();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setResizable(false);

    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
}

public void update(Graphics g) {
    paint(g);
}

public void paint(Graphics g) { 
    g.drawImage(im, 0,0, null); 
}


@Override
public void actionPerformed(ActionEvent e) {
    j.nave.x =j.nave.x + j.nave.v;
    repaint();  
}  

@Override
public void keyPressed(KeyEvent e) {
    int tecla = e.getKeyCode();
    if (tecla == KeyEvent.VK_RIGHT)
        j.nave.v = +10;
    if (tecla == KeyEvent.VK_LEFT)
        j.nave.v = -10;
    }

@Override
public void keyReleased(KeyEvent e) {
    j.nave.v = 0;
}

@Override
public void keyTyped(KeyEvent e) {}

}

И, наконец, это класс, содержащий цикл игры:

import java.awt.Color;
import java.awt.Graphics;

public class Joc{


Finestra f;                 // WINDOW
Enemigos c1[];              // ENEMIES
Nave nave;                  // SHIP

Joc(Finestra f){            // JOC = GAME
    this.f=f;
}
void playing() {
    initicalitzaJoc();
    do {
        moviments();           // MOVEMENTS
        detectaColisions();    // COLLISION DETECTION
        pintarPantalla(f.g);   // PAINT SCREEN
        f.repaint();

        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }           
    }while(true);
}

private void detectaColisions() { 
} 

private void moviments() {  
    for(int i=0;i<c1.length;i++)
        c1[i].movimiento(); 
}

private void initicalitzaJoc() {        

    c1 = new Enemigos[15];                 // ENEMIES

    for (int i=0; i<5; i++)
        c1[i] = new Enemigos(f, 100+i*80, 100, 5);
    for (int i=5; i<10; i++)
        c1[i] = new Enemigos(f, 100+(i-5)*80, 150, 5);
    for (int i=10; i<15; i++)
        c1[i] = new Enemigos(f, 100+(i-10)*80, 200, 5);

    // Nave del jugador:                    // PLAYER'S SHIP
    nave = new Nave(f,300-40/2, 500-40-5);

}

void pintarPantalla(Graphics g) {   

    g.setColor(Color.WHITE);
    g.fillRect(0, 0, 600,500);

    for (int i=0; i<5; i++)         
        c1[i].pinta(g,1);;
    for (int i=5; i<10; i++)
        c1[i].pinta(g,3);
    for (int i=10; i<15; i++)
        c1[i].pinta(g,6);       

    nave.pintaNave(g);

}

}

Не знаю, где могла быть ошибка, может, в цикле ... не знаю.

Вопрос в том, как я могу исправить это, чтобы можно было перемещать корабль с помощью клавиатуры? Space Invaders - это домашнее задание, я обязан использовать KeyListener ... Как мне заставить его работать?


person Manuel Gijón    schedule 16.02.2016    source источник
comment
Это не исправить, это не работает.   -  person Manuel Gijón    schedule 16.02.2016
comment
Это не исправить, это не работает. Да, да, я имел в виду хороший, исправляя правки, которые я предложил. Еще пара советов: 1) Чтобы быстрее получить помощь, опубликуйте минимальный воспроизводимый пример или Краткий, автономный, правильный пример. 2) Совет: добавьте @trashgod (или кого бы то ни было, @ важно), чтобы уведомить человека о новом комментарии. (Я сомневаюсь, что они заметили правку, в которой вы должны использовать KeyListener для домашнего задания.)   -  person Andrew Thompson    schedule 17.02.2016


Ответы (2)


Я нашел ответ.

Проблема заключалась в том, что класс «Finestra» извлекал функцию «воспроизведение» (так что цикл запускался) перед чтением клавиш.

Достаточно погони за порядком:

Finestra(){

    super("-+- Space Invaders -+-");
    setVisible(true);
    setSize(AMPLE,ALT);
    im=this.createImage(AMPLE, ALT);
    g=im.getGraphics();
    j=new Joc(this);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setResizable(false);

    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
    System.out.println("hola");
    j.playing();  // enter the loop after reading the keys.
}
person Manuel Gijón    schedule 17.02.2016
comment
Я нашел ответ. Рад, что вы разобрались. :) Приятно решить эту проблему самостоятельно и сообщить об исправлении. - person Andrew Thompson; 17.02.2016

Взглянув на обработчик ключевого события:

@Override
public void keyPressed(KeyEvent e) {
  int tecla = e.getKeyCode();
  if (tecla == KeyEvent.VK_RIGHT)
    j.nave.v = +10;
  if (tecla == KeyEvent.VK_LEFT)
    j.nave.v = -10;
}

Он изменяет переменную под названием «v» на вашем корабле (нефе).

Затем ваш метод movimiento (предположительно "перемещение") на вашем корабле использует другую переменную velocidad. Он полностью игнорирует v!

Удалите переменную v и просто используйте velocidad.

Кроме того, вы всегда вызываете movimiento только на своих вражеских кораблях, а не на корабле вашего игрока! Естественно, он никогда не двигается.

person NickJ    schedule 16.02.2016
comment
Спасибо, но это не объясняет, почему я использовал новую переменную v для управления новым движением (на самом деле, movimiento отсутствует в методе movimients, который находится в цикле). - person Manuel Gijón; 16.02.2016