Переход от меню к реальному игровому процессу - PullRequest
0 голосов
/ 27 января 2019

Итак, я делаю клон космических захватчиков. Изначально у меня не было проблем с тем, чтобы моя игра работала с простым основным классом, который создал фрейм, создал игровой процесс и запустил поток.

Но затем я попытался реализовать меню «Пуск», и все пошло к чёрту. Меню появляется с успехом, но игровой процесс не появляется, когда я нажимаю старт.

У меня заканчиваются идеи, и я полностью ошеломлен. Я также немного новичок в SO, поэтому, если я что-то упущу, я буду признателен за любую помощь.

Вот оригинал без меню, которое работало нормально:

    public static void main(String[] args) {

    JFrame frame = new JFrame("SpaceRaiders");

    frame.setSize(600, 600);
    frame.setLocationRelativeTo(null);
    frame.setResizable(false);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Gameplay gameplay = new Gameplay();
    frame.add(gameplay);
    frame.setVisible(true);

    Thread t1 = new Thread(gameplay);
    t1.start();


}

Однако, в тот момент, когда я попытался создать меню, чтобы потом играть в игру, я столкнулся с всевозможными неприятностями. Я создал класс пользовательского интерфейса, а также класс «игры», например:

public class UI {

JFrame frame, f2;
JPanel titrePanel, startButtonPanel, loadButtonPanel, p2;
JLabel nomJeu;
JButton startButton, loadButton;
Font fontTitre, fontStart;
Gameplay gameplay;

public void createUI(ChoixJeu cj) {
    frame = new JFrame("SpaceRaiders");
    frame.setSize(600, 600);
    frame.setLocationRelativeTo(null);
    frame.setResizable(false);

    frame.setLayout(null);

    frame.getContentPane().setBackground(Color.black);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //------------------ECRAN MENU---------------------
    //Titre
    titrePanel = new JPanel();
    titrePanel.setBounds(100, 100, 400, 100);
    titrePanel.setBackground(Color.BLUE);

    Font fontTitre = new Font("Times New Roman", Font.BOLD, 50);
    Font fontStart = new Font("Times New Roman", Font.PLAIN, 20);
    nomJeu = new JLabel("SpaceRaiders");
    nomJeu.setForeground(Color.white);
    nomJeu.setFont(fontTitre);
    titrePanel.add(nomJeu);

    //Start button
    startButtonPanel = new JPanel();
    startButtonPanel.setBounds(200, 400, 200, 40);
    startButtonPanel.setBackground(Color.BLACK);

    startButton = new JButton("START");
    startButton.setBackground(Color.BLACK);
    startButton.setForeground(Color.WHITE);
    startButton.setFont(fontStart);
    startButton.setFocusPainted(false);
    startButton.addActionListener(cj);
    startButton.setActionCommand("start");
    startButtonPanel.add(startButton);

    //Load Button
    loadButtonPanel = new JPanel();
    loadButtonPanel.setBounds(200, 440, 200, 100);
    loadButtonPanel.setBackground(Color.BLACK);

    loadButton = new JButton("LOAD");
    loadButton.setBackground(Color.BLACK);
    loadButton.setForeground(Color.WHITE);
    loadButton.setFont(fontStart);
    loadButton.setFocusPainted(false);
    titrePanel.add(nomJeu);
    loadButtonPanel.add(loadButton);

    frame.add(startButtonPanel);
    frame.add(titrePanel);

    //------------------ECRAN MENU FIN---------------------   
    frame.setVisible(true);


}

И игровой класс ...

public class Jeu {

ChoixJeu cj = new ChoixJeu();
UI ui = new UI();
Ecrans e = new Ecrans(ui);
Gameplay gp;

public static void main(String[] args) {

    new Jeu();


}

public Jeu() {

    ui.createUI(cj);
    Gameplay gameplay = new Gameplay();
    this.gp = gameplay;

}

public class ChoixJeu implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent ae) {

        String yourChoice = ae.getActionCommand();

        switch (yourChoice) {
            case "start":
                e.montrerEcranJeu();
                new Thread(gp).start();
                ui.frame.add(gp);

                break;
            default:
                break;
        }

    }

}
* *} Тысяча двадцать-один

Я также пытался создать класс / метод, который скрывает панели меню

    public void montrerEcranJeu() {
    //Cache Menu
    ui.titrePanel.setVisible(false);
    ui.startButtonPanel.setVisible(false);


    //Montre Jeu
    // ui.frame.add(gameplay);
}

И на всякий случай класс Gameplay. Метод run () находится внизу

public class Gameplay extends JPanel implements KeyListener, ActionListener, Runnable {

private Ship player = new Ship(new Point(200, 555));
Timer t = new Timer(5, this);


private ArrayList<Laser> lasers = new ArrayList<Laser>();
private int laserNb;
private boolean readytofire;
private boolean shot = false;


private ArrayList<Invader> invaders = new ArrayList<Invader>();

private boolean pause;

public Gameplay() {
    super();
    t.start();
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);

    for (int j = 0; j < 80; j += 20) {
        for (int i = 0; i < 20; i++) {
            invaders.add(new Invader(5 + i * 30, j));
        }
    }
}

public boolean addLaser(Laser a) {
    lasers.add(a);
    return true;
}

public boolean addPlayer(Ship p) {

    this.player = p;

    return true;
}


@Override
public void keyTyped(KeyEvent ke) {

}

public void keyPressed(KeyEvent e) {
    if (KeyEvent.VK_RIGHT == e.getKeyCode()) {
        moveRight();
    }
    if (KeyEvent.VK_LEFT == e.getKeyCode()) {
        moveLeft();
    }
    if (KeyEvent.VK_SPACE == e.getKeyCode()) {
        shoot();
        System.out.println("Space Action from Gameplay is working");
    }
}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void actionPerformed(ActionEvent ae) {
    repaint();
}


public void moveRight() {
    if (player.getCentre().getX() >= 580) {
        player.setX(580);
    } else {
        double movement = player.getCentre().getX();
        movement += 10;
        player.setX(movement);
    }
    this.repaint();
}

public void moveLeft() {
    if (player.getCentre().getX() <= 20) {
        player.setX(20);
    } else {
        double movement = player.getCentre().getX();
        movement -= 10;
        player.setX(movement);
    }
    this.repaint();
}


public void shoot() {

    shot = true;
    if (readytofire) {
        Point top = new Point(player.getTopX(), player.getTopY());
        Laser laser = new Laser(top);
        addLaser(laser);

    }
}


public void moveShot() {
    if (shot) {
        for (Laser l : lasers) {
            l.setY(l.getTopLeft().getY() - 1);
        }
    }
}


@Override
public void paint(Graphics g) {
    setBackground(Color.black);
    super.paint(g);
    player.draw(g);
    for (Laser l : lasers) {
        l.draw(g);
    }
    for (Invader i : invaders) {
        i.draw(g);
    }

}

// public void paintComponent (Graphics g){
// Controle Thread
public void run() {

    while (true) {
        moveShot();

        for (Invader i : invaders) {
            i.moveAndUpdate();

        }
        //  for (Invader i : invaders) {
        //         if (){
        //            System.out.println("YOU ARE DEAD!");
        //        } 

        //  }
        try {
            Thread.sleep(10);
            readytofire = true;

        } catch (InterruptedException ex) {
            Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

}

1 Ответ

0 голосов
/ 27 января 2019

Итак, использование null макетов - это начало ваших проблем. Я мог бы рекомендовать использовать CardLayout, который разработан, чтобы помочь вам динамически переключаться между представлениями. См. Как использовать CardLayout для получения более подробной информации. Я бы также предложил потратить время на чтение Компоновки компонентов внутри контейнера и найти один или несколько подходящих макетов для поддержки вашего меню.

Вы также делаете много фундаментальных ошибок. Swing не является потокобезопасным, поэтому вам следует избегать обновления пользовательского интерфейса (или чего-то, от чего зависит пользовательский интерфейс) вне контекста EDT - см. Параллельность в Swing для получения дополнительной информации и Как использовать Swing Таймеры для возможного решения.

В качестве общей рекомендации вам следует избегать переопределения paint и, в случае классов, которые расширяются от JComponent, вместо этого предпочитать paintComponent. Вам также следует избегать вызова методов, которые могут изменить состояние компонента во время цикла рисования, это может увеличить количество запросов на перекрашивание и снизить производительность вашей программы (т. Е. Не вызывать setBackground внутри рисования).

Посмотрите Выполнение пользовательской рисования и Рисование в AWT и Swing для получения более подробной информации о том, как работает система рисования и как с ней лучше работать.

Вам также следует избегать KeyListener, это может вызвать проблемы, когда вы добавляете в изображение другие, фокусируемые компоненты. Вместо этого вам следует отдать предпочтение API связывания клавиш вместо

Я прочитал [вставить ссылку или учебник], но это все равно не помогает ...

И простите меня, если это не происходит постоянно.

Смысл предоставления вам обучающих ссылок состоит в том, чтобы побудить вас чему-то научиться;

  • Узнайте, где найти ответы на ваши вопросы
  • Узнайте, как работают API
  • Расширьте свои знания и понимание того, как работают API

Сказав это, они не всегда "очевидны" в отношении решения. Когда я нахожусь в такой ситуации, я начинаю с одного или нескольких новых проектов, посвященных просто работе над тем аспектом API, который я пытаюсь понять. Ибо здесь я могу исследовать концепции изолированно, и когда я «думаю», я понимаю их, попробуйте внедрить их в проект, над которым я работаю. Это может занять несколько итераций, но как только он заработает, я получу гораздо более глубокое понимание и оценку API, чем получу от простого решения «копировать и вставить»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...