我挣扎于 JPanel、getWidth 和 getHeight

I struggle with JPanel, getWidth and getHeight

所以我昨天开始了这个 "Project",我想尝试一个立方体与 windows 边界相撞的程序。看起来很简单。

然而,我在边界上挣扎。我似乎无法在 window 的右侧和底部找到 "perfect" collison。立方体总是比预期走得更远。

我认为问题与我设置 window 大小的方式有关?我不确定,但我确实尝试了一些更改,但没有奏效。

代码如下:

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 个边界之一,然后变为“-speed”,因此如果速度为 5,则速度应为完全相反(负)并转向另一方向。这行得通,但为时已晚。我做的碰撞系统好像不行

很抱歉将所有代码放在一个文件中 class!

提前致谢!

所以,马上,这似乎是错误的...

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

pack window 之前的首选尺寸是 set/determined,这意味着 window 将希望采用尽可能小的尺寸(因为 [=内容的19=]默认为0x0)。

作为一般规则,您应该避免调用 setPreferredSize,但我会特别避免在 JFrame.

上使用它

为什么?因为JFrame 有装饰(window 标题和边框),它们被插入window,所以可见尺寸实际上是frameSize - decorationInsets,这成为你问题的核心稍后。

因此,我将覆盖 MyPanel 中的 getPreferredSize 并指定组件的 "viewable" 范围

class MyPanel extends JPanel implements ActionListener {

    //...

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

然后在你的 main class 你可以做...

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.myGameJFrame,你要求的是 window 尺寸,但正如我之前所说,框架有装饰,嵌入框架中,减少了您的组件可用的可视区域。相反,您应该使用组件本身的大小

public void actionPerformed(ActionEvent e) {

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

一些建议...

我认为需要这些...

public static JFrame myGame;
public static Timer timer;

但我在使用 static 时遇到问题 ;)。使 myGame static 成为 "easy" 以从代码中的位置访问它的功能,这些位置对此不承担任何责任。

在这种情况下 Timer 是有争议的,但我可能想要一个 "update engine" 来封装它和过度更新工作流程,但这就是我 ;)

我认为这不是必需的(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
}

功能应该在组件创建时由组件本身创建(或通过其他 "setup" 阶段)。我也鼓励使用 ImageIO.read,因为它会在出现问题时生成 IOException,这与 ImageIcon 不同,后者会静默失败。

作为(ImageIO.read)的附带好处,您还将知道图像何时完成加载,因为该方法不会 return 直到它完成,这意味着您不必冒险一些空框。

你不需要...

private static ImageObserver observer;

也不需要是 static(因为 private 它会破坏任何好处),但是,JPanel 实际上是一个 ImageObserver,所以你可以将 this 传递给 drawImage