Я борюсь с JPanel, getWidth и getHeight [решено] - PullRequest
0 голосов
/ 08 марта 2020

Итак, я начал этот «Проект» вчера, я хотел попробовать программу, в которой куб столкнулся с границей windows. Казалось, довольно просто.

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

Я бы предположил, что проблема связана с моим способом установки размера окна? Я не уверен, но я попробовал некоторые изменения, но это не сработало.

Вот код:

package spritesInJava;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.ImageObserver;

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

public class Game {

public static JFrame myGame;
public static Timer timer;

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {


        public void run() {
            createGame();
            timer.start();

        }


    });

}
public static void createGame() {

    myGame = new JFrame("Felicia");
    myGame.add(new MyPanel());
    myGame.pack();
    myGame.setSize(new Dimension(1000,1000));
    myGame.setPreferredSize(new Dimension(1000,1000));
    myGame.setVisible(true);
    myGame.setDefaultCloseOperation(1);
    MyPanel.loadImage();
}


}
class MyPanel extends JPanel implements ActionListener {

private static Image image; //Sprite
private static final long serialVersionUID = 1251340649341903871L;
private static ImageObserver observer;
private  int x = 50;
private int y = 50;
private int width = 200;
private int height = 100;
private int speedx = 2;
private int speedy = 2;

MyPanel() {

    Game.timer = new Timer(10,this);


}
@Override
public void actionPerformed(ActionEvent e) {

    int screenWidth = Game.myGame.getWidth();
    int screenHeight = Game.myGame.getHeight();
    x+=speedx;
    y+=speedy;

    if(x >= screenWidth - width) {
        speedx = -speedx;

    }
    else if(x < 0 ) {
        speedx = -speedx;


    }

    if(y >= screenHeight- height ) {

        speedy = -speedy;
    }
    else if(y < 0 ) {
        speedy = -speedy;

    }

    repaint();

}
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    //g.drawImage(image, x, y,width,height,observer);   //Uses the image that was loaded below and draws it.
    g.fillRect(x, y, width, height);
}

public static void loadImage() {    //Load the image
    ImageIcon icon = new ImageIcon("photos/Felicia.png");
    image = icon.getImage();    //Set the "temp" ImageIcon icon to the public ImageIcon
}


}

Куб должен ударить по одной из 4 границ и затем изменить на «-скорость», поэтому, если скорость равна 5, скорость должна быть общей противоположный (отрицательный) и поверните в другую сторону. Это работает, но слишком поздно. Кажется, что созданная мной система столкновений не работает

Извините, что поместил весь код в один класс!

Заранее спасибо!

1 Ответ

2 голосов
/ 08 марта 2020

Итак, сразу, это кажется неправильным ...

myGame.add(new MyPanel());
myGame.pack();
myGame.setSize(new Dimension(1000, 1000));
myGame.setPreferredSize(new Dimension(1000, 1000));
myGame.setVisible(true);

Вы pack окно до того, как предпочтительный размер был установлен / определен, что означает, что окно захочет принять наименьший возможный размер (так как preferredSize содержимого по умолчанию 0x0).

Как правило, вам следует избегать вызова setPreferredSize, но я бы особенно избегал его использования на JFrame.

Почему? Поскольку JFrame имеет декорации (заголовок окна и границы), которые вставляются в окно, поэтому видимый размер на самом деле равен frameSize - decorationInsets, что позже станет ядром вашей проблемы.

Поэтому вместо этого я wold override getPreferredSize в вашем MyPanel и укажите «видимый» диапазон компонента

class MyPanel extends JPanel implements ActionListener {

    //...

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(1000, 1000);
    }

Тогда в вашем основном классе вы можете просто сделать ...

myGame = new JFrame("Felicia");
myGame.add(new MyPanel());
myGame.pack();
myGame.setVisible(true);

И API сработает для вас.

Хорошо, к следующему вопросу ...

public void actionPerformed(ActionEvent e) {

    int screenWidth = Game.myGame.getWidth();
    int screenHeight = Game.myGame.getHeight();

Game.myGame - это JFrame, вы запрашиваете окно размер, но, как я уже говорил ранее, у рамок есть украшения, которые вставляются в рамку, уменьшая видимую область, доступную для вашего компонента. Вместо этого вы должны использовать размер самого компонента

public void actionPerformed(ActionEvent e) {

    int screenWidth = getWidth();
    int screenHeight = getHeight();

Некоторые предложения ...

Я бы поспорил с необходимостью этих ...

public static JFrame myGame;
public static Timer timer;

Но у меня есть проблема с использованием static;). Создание myGame static делает его «легким» доступ к его функциям из тех мест в вашем коде, которые не несут за это никакой ответственности.

Timer в этом контексте является кое-чем спорным , но я мог бы испытать искушение иметь «механизм обновления», который инкапсулировал его и рабочий процесс чрезмерного обновления, но это я;)

Я бы сказал, что это не обязательно (быть static)

public static void loadImage() {    //Load the image
    ImageIcon icon = new ImageIcon("photos/Felicia.png");
    image = icon.getImage();    //Set the "temp" ImageIcon icon to the public ImageIcon
}

Функциональность должна создаваться самим компонентом при его создании (или через какой-либо другой этап «настройки»). Я также рекомендовал бы использовать ImageIO.read, так как он будет генерировать IOException, когда что-то пойдет не так, в отличие от ImageIcon, который потерпит неудачу.

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

Вам не нужно ...

private static ImageObserver observer;

Кроме того, он не должен быть static (как это было private, это как бы побеждает какую-либо выгоду), но JPanel на самом деле ImageObserver, так что вы можете просто передать this на drawImage

...