Перекрасить не обновляет экран - PullRequest
0 голосов
/ 03 июня 2019

Я хотел бы перекрасить свой экран.На данный момент все, что он делает, это показывает первый экран с точкой, где должна быть голова.Это нормально, однако я написал в своем коде, что хочу опускать голову на 10 пикселей каждую секунду.Я печатаю, в какой точке должна находиться голова, и в командной строке она показывает, что значение y действительно увеличивается.Однако на моем экране голова не двигается.

Я пытался использовать метод revalidate, пытаясь расширить класс canvas вместо jframe, я пытался использовать другие классы только для метода paint, я пытался заменитьметод рисования с методом paintComponent.И, как вы, вероятно, можете сказать, у меня плохое понимание всего, что связано с рисованием в Java.Я пытался читать в эти суперклассы, но они слишком сложны для меня, чтобы понять.Я также пытался бежать без объявления сна.Это не имело значения.

Основной класс: этот класс содержит метод main для запуска игры со змеями.

import java.util.concurrent.TimeUnit;

public class Main{

    public static void main(String[] args) throws InterruptedException {
        Main programma = new Main();
        programma.rungame();
    }

void rungame() throws InterruptedException {
        AllGUIElements gui = new AllGUIElements();
        gui.gui();
        while (true) {
            TimeUnit.SECONDS.sleep(1);
            gui.setGameScreen();
        }
    }
}

Класс AllGUIElements: этот класс создает новый фрейм, содержащий новыйпанель.Эта панель окрашивается с помощью paintComponent.setGameScreen обновляет положение головы и, как предполагается, перерисовывает экран.

import javax.swing.*;
import java.awt.*;

public class AllGUIElements extends JPanel {

    private JFrame frame;
    private JPanel panel;

    private int screen;

    Snake hoofd = new Head(new Point(30,30),3,null);

    void gui() throws InterruptedException {

        frame = new JFrame("Snake Game");
        panel = new AllGUIElements();
        panel.setBackground(Color.GRAY);
        panel.setSize(1000,500);
        frame.setSize(1000,500);
        frame.add(panel);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

void setGameScreen() {
    repaint();
        if (hoofd.getDirection() == 1) {
            hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y-10));
        }
        if (hoofd.getDirection() == 2) {
            hoofd.setPosition(new Point(hoofd.getPosition().x+10, hoofd.getPosition().y));

        }
        if (hoofd.getDirection() == 3) {
            hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y+10));

        }
        if (hoofd.getDirection() == 4) {
            hoofd.setPosition(new Point(hoofd.getPosition().x-10, hoofd.getPosition().y));
        }
}

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
            g.setColor(Color.DARK_GRAY);
            g.fillRect(0, 0, 1000, 10);
            g.fillRect(0, 0, 10, 500);
            g.fillRect(990, 0, 10, 500);
            g.fillRect(0, 490, 1000, 10);

            g.setColor(Color.GREEN);
            g.fillRect(hoofd.getPosition().x, hoofd.getPosition().y, 10, 10);
    }

}

Класс экранобъекта: Родительский класс Snake and Food (который не опубликован, поскольку в нем нет необходимости), который возвращает положение головы, часть тела и еда.

import java.awt.*;

public class Screenobject{

    Point pos;

    Screenobject(Point pos){
        this.pos = pos;
    }

    void setPosition(Point pos){
        this.pos = pos;
    }

    Point getPosition() {
        return pos;
    }
}

Змея-класс: Дитя экрана и объект Головы и Тела.Этот класс устанавливает направление объектов.

import java.awt.*;

public class Snake extends Screenobject{

    int direction;
    //directions:
    //1 = up
    //2 = right
    //3 = down
    //4 = left

    Snake nextpart;

    Snake(Point pos, int direction, Snake nextpart){
        super(pos);
        this.direction = direction;
        this.nextpart = nextpart;
    }

    int getDirection() {
        return direction;
    }
}

Класс головы: дочерний класс змеи, и предполагается, что он является первым объектом связанного списка для змеи.

import java.awt.*;

public class Head extends Snake{
    Head(Point pos, int direction, Snake nextpart){
        super(pos, direction, nextpart);
    }
}

Класс тела: Детский класс Змеи и растет с каждой едой.

import java.awt.*;

public class Body extends Snake{
    Body(Point pos, int direction, Snake nextpart){
        super(pos, direction, nextpart);
    }

}

1 Ответ

1 голос
/ 05 июня 2019

Перво-наперво:

Я использовал метод «Разделяй и властвуй», чтобы публиковать только необходимую информацию

Да, вы опубликовали только необходимую информацию, но вы все еще используете слишком много классов для MCVE / MRE , в идеале весь ваш код мог бы поместиться в одном классе.

Мне не удалось сделать его короче, не пропустив код для его запуска.

Это идея о том, что мы просим MRE, вы должны создать совершенно новую программу, чтобы изолировать проблему, в вашем случае это: Переместите фигуру в определенном направлении и продолжайте двигаться в этом направлении.

Прямо сейчас, я вижу, что вы пытались создать его и улучшить, поэтому я опубликую пример того, что ожидается в ваших будущих вопросах, чтобы вы задавали лучшие вопросы в будущем.

Как говорится, пойдем и ответим на ваш вопрос.


Это пример с менее чем 100 строками кода (не включая комментарии), который решает следующие проблемы в вашем коде:

  1. Удаляет оператор while(true) в пользу Swing Timer, чтобы предотвратить блокировку потока обработки событий (EDT)

  2. Помещает программу в EDT, см. Пункт № 2 этого ответа

  3. Использует метод JFrame#pack() вместо ручной установки его с помощью setSize(...) для JFrame и JPanel

  4. Избавляется от "магических чисел" для указаний и использует enum для этого вопроса, и, таким образом, код более читабелен, так как мы все знаем, что TOP должен двигаться это наверх, но мы не знаем, что 1 должно переместить его наверх.

  5. Использует API Shape для рисования фигур на JPanel, как показано в этот ответ

  6. Я бы также предложил назвать ваши методы, используя camelCase, чтобы rungame() стал runGame(), так как его легче читать, то же самое для других методов. И дать им более значимые имена, такие как hoofd, я не знаю, что это такое, и если бы я прочитал его в одиночку без контекста, было бы чрезвычайно трудно сказать, что это за объект.


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class SnakeGame {
    private JFrame frame;
    private Snake snake;
    private JPanel buttonsPane;
    private JButton[] buttons; // Our array of buttons
    private Timer timer;
    private Direction currentDirection;

    // This enum will be used to determine the direction the snake will take.
    private enum Direction {
        TOP, LEFT, BOTTOM, RIGHT
    }

    public static void main(String[] args) {
        // We place our program on the EDT using Java 8 lambda expressions.
        SwingUtilities.invokeLater(() -> new SnakeGame().createAndShowGUI());
    }

    private void createAndShowGUI() {
        frame = new JFrame(getClass().getSimpleName());
        snake = new Snake();
        buttonsPane = new JPanel();
        buttons = new JButton[Direction.values().length];

        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = new JButton(Direction.values()[i].toString()); // We create a JButton with the current value of the direction
            buttons[i].addActionListener(listener); // We set their ActionListeners
            buttonsPane.add(buttons[i]); // And add them to the buttonsPane
        }

        currentDirection = Direction.RIGHT; // We set a default direction
        timer = new Timer(1000, listener); // And start our Swing Timer

        // We add our components and then pack the frame, after that we start the timer.
        frame.add(snake);
        frame.add(buttonsPane, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        timer.start();
    }

    // Our ActionListener for moving the snake
    private ActionListener listener = e -> { // Using Java 8 lambda expressions again
        // We set the current direction using a ternary, if the source of the event is
        // the timer we leave the current direction as is
        // otherwise we set it to the direction from the button clicked
        currentDirection = e.getSource().equals(timer) ? currentDirection : Direction.valueOf(e.getActionCommand());
        snake.move(currentDirection); // And we call the move method
    };

    @SuppressWarnings("serial")
    class Snake extends JPanel {
        private int xPos;
        private int yPos;
        private static final int SPEED = 10; // We set the speed as a constant (10 pixels at a time) in any direction

        // We determine the movement direction
        public void move(Direction direction) {
            switch (direction) {
            case TOP:
                yPos -= SPEED;
                break;
            case LEFT:
                xPos -= SPEED;
                break;
            case BOTTOM:
                yPos += SPEED;
                break;
            case RIGHT:
                xPos += SPEED;
                break;
            }
            this.repaint(); // And repaint the snake
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.DARK_GRAY);
            g2d.fill(new Rectangle2D.Double(xPos, yPos, 10, 10)); // We draw a rectangle using the Shape API
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300); // We set the preferredSize of the JPanel to 300 x 300
        }
    }
}

Приведенный выше код приводит к следующему результату для Java 7 и ниже или, если вы не хотите использовать лямбда-выражения или слишком сложны для вас, отметьте пункт № 2 в этом ответе, он показывает, как разместить программу на EDT без лямбда-выражений и этот ответ показывает, как написать ActionListener без них.

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

enter image description here

...