Java 我与JPanel、getWidth和getHeight斗争

Java 我与JPanel、getWidth和getHeight斗争,java,swing,jpanel,Java,Swing,Jpanel,所以我昨天开始了这个“项目”,我想尝试一个立方体与windows边框碰撞的程序。看起来很简单 然而,我与边界作斗争。我似乎无法在窗户的右侧和底部找到“完美”的collison。立方体总是比预期的要远一点 我认为问题与我设置窗口大小的方式有关?我不确定,但我尝试了一些改变,但没有成功 代码如下: package spritesInJava; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; im

所以我昨天开始了这个“项目”,我想尝试一个立方体与windows边框碰撞的程序。看起来很简单

然而,我与边界作斗争。我似乎无法在窗户的右侧和底部找到“完美”的collison。立方体总是比预期的要远一点

我认为问题与我设置窗口大小的方式有关?我不确定,但我尝试了一些改变,但没有成功

代码如下:

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
}


}
package spritesInJava;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.Image;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.image.ImageObserver;
导入javax.swing.ImageIcon;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
导入javax.swing.Timer;
公开课游戏{
公共静态jframemygame;
公共静态定时器;
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
createGame();
timer.start();
}
});
}
公共静态void createGame(){
myGame=新JFrame(“Felicia”);
添加(新的MyPanel());
myGame.pack();
myGame.setSize(新维度(10001000));
myGame.setPreferredSize(新维度(10001000));
myGame.setVisible(true);
myGame.setDefaultCloseOperation(1);
MyPanel.loadImage();
}
}
类MyPanel扩展JPanel实现ActionListener{
私有静态映像;//Sprite
私有静态最终长serialVersionUID=1251340649341903871L;
专用静态图像观测器;
私人整数x=50;
私人int y=50;
私有整数宽度=200;
私人内部高度=100;
私人整数速度x=2;
私有int=2;
我的小组(){
Game.timer=新计时器(10,此);
}
@凌驾
已执行的公共无效操作(操作事件e){
int screenWidth=Game.myGame.getWidth();
int screenHeight=Game.myGame.getHeight();
x+=速度x;
y+=快速;
如果(x>=屏幕宽度-宽度){
speedx=-speedx;
}
else如果(x<0){
speedx=-speedx;
}
如果(y>=屏幕高度-高度){
迅捷=-迅捷;
}
else if(y<0){
迅捷=-迅捷;
}
重新油漆();
}
公共组件(图形g){
超级组件(g);
//g、 drawImage(图像,x,y,宽度,高度,观察者);//使用下面加载的图像并绘制它。
g、 fillRect(x,y,宽度,高度);
}
public static void loadImage(){//加载映像
ImageIcon=新的ImageIcon(“photos/Felicia.png”);
image=icon.getImage();//将“temp”ImageIcon图标设置为public ImageIcon
}
}
立方体应该撞击4个边界中的一个,然后变为“-速度”,因此如果速度为5,则速度应完全相反(负),并转向另一个方向。这是可行的,但有点太晚了。我做的碰撞系统似乎不起作用

很抱歉将所有代码放在一个类中


提前谢谢

所以,这似乎马上就错了

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-decorationSets
,这将成为以后问题的核心

因此,我将在
MyPanel
中覆盖
getPreferredSize
,并指定组件的“可视”范围

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
是有争议的,但我可能会尝试使用一个“更新引擎”来封装它和过度更新的工作流,但这就是我;)

我认为这不是必需的(必须是
静态的

功能应该在组件创建时由组件本身创建(或通过其他“设置”阶段)。我还鼓励使用
ImageIO.read
,因为当出现问题时,它会生成
IOException
,而不像
ImageIcon
那样会无声失败

作为一个附带的好处(使用
ImageIO.read
),您还可以知道图像何时完成加载,因为该方法在加载之前不会返回,这意味着您不必冒一些空帧的风险

你不需要

private static ImageObserver observer;

它也不需要是静态的(就像是私有的),但是,
JPanel实际上是一个
ImageObserver
,所以你可以把
这个
传递给
drawImage

,所以,很快,这似乎是错误的

myGame.add(new MyPanel());
myGame.pack();
myGame.setSize(new Dimension(1000, 1000));
myGame.setPreferredSize(new Dimension(1000, 1000));
myGame.setVisible(true);
在设置/确定首选大小之前,您将
pack
窗口,这意味着窗口将希望采用尽可能最小的大小(因为内容的
preferredSize