Java 在JFrame中看不到矩形播放器类

Java 在JFrame中看不到矩形播放器类,java,swing,Java,Swing,我是java新手,正在尝试创建一个基本的游戏,现在正在尝试编写player类。但是,当我运行游戏时,只有JFRame出现。这些是我的thress类,它们没有显示错误 import java.awt.Color; import javax.swing.JFrame; public class Game extends JFrame { public final static int WIDTH = 700, HEIGHT = 450; public GamePanel pa

我是java新手,正在尝试创建一个基本的游戏,现在正在尝试编写player类。但是,当我运行游戏时,只有JFRame出现。这些是我的thress类,它们没有显示错误

import java.awt.Color;

import javax.swing.JFrame;

public class Game extends JFrame {
    public
 final static int WIDTH = 700, HEIGHT = 450;
    public
 GamePanel panel;

    public Game() {
        setSize(WIDTH, HEIGHT);
        setTitle("Game");
        setBackground(Color.WHITE);
        setResizable(false);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
         add(panel);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        new Game();
    }
}

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements ActionListener, KeyListener {
    public
 Game game;
    public
 Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        addKeyListener(this);
        setFocusable(true);
    }

    public
 void update() {
        player.update();
    }

    public void actionPerformed(ActionEvent e) {
        update();
        repaint();
    }

        public Player getPlayer(int playerNo) {
          return player; 
        }

    public void keyPressed(KeyEvent e) {
        player.pressed(e.getKeyCode());
    }

    public void keyReleased(KeyEvent e) {
        player.released(e.getKeyCode());
    }

    public void keyTyped(KeyEvent e) {
        ;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        player.paint(g);
    }
}

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Color;

public class Player {
    public
 static final int WIDTH = 50, HEIGHT = 50;
    public
 Game game;
    public
 int left, right;
    public
 int y;
    public
 int x, xa;

    public Player(Game game, int left, int right, int x) {
        this.game = game;
        this.x = x;
        y = game.getHeight() - 20;
        this.left = left;
        this.right = right;
        this.y = y;
        x = game.getWidth() - 36;
    }

    public void update() {
        if (x > 0 && x < game.getWidth() - WIDTH - 36)
            x += xa;
        else if (x == 0)
            x++;
        else if (x == game.getWidth() - WIDTH - 36)
            x--;
    }

    public void pressed(int keyCode) {
        if (keyCode == left)
            xa = -1;
        else if (keyCode == right)
            xa = 1;
    }

    public void released(int keyCode) {
        if (keyCode == left || keyCode == right)
            xa = 0;
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, WIDTH, HEIGHT);
    }

    public void paint(Graphics g) {
        g.fillRect(x, y, WIDTH, HEIGHT);
        g.setColor(Color.ORANGE);
    }
}
导入java.awt.Color;
导入javax.swing.JFrame;
公共类游戏扩展JFrame{
公众的
最终静态整型宽度=700,高度=450;
公众的
游戏面板;
公共游戏(){
设置尺寸(宽度、高度);
片名(“游戏”);
挫折地面(颜色:白色);
可设置大小(假);
setVisible(真);
setDefaultCloseOperation(关闭时退出);
panel=新游戏面板(此);
添加(面板);
}
公共游戏面板getPanel(){
返回面板;
}
公共静态void main(字符串[]args){
新游戏();
}
}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.KeyEvent;
导入java.awt.event.KeyListener;
导入javax.swing.JPanel;
公共类GamePanel扩展JPanel实现ActionListener、KeyListener{
公众的
游戏;
公众的
玩家;
公共游戏面板(游戏){
挫折背景(颜色:绿色);
这个游戏=游戏;
player=新玩家(game,KeyEvent.VK_左,KeyEvent.VK_右,game.getWidth()-36);
addKeyListener(此);
设置聚焦(真);
}
公众的
无效更新(){
player.update();
}
已执行的公共无效操作(操作事件e){
更新();
重新油漆();
}
公共播放器getPlayer(int playerNo){
返回球员;
}
按下公共无效键(按键事件e){
player.pressed(如getKeyCode());
}
公共无效密钥已释放(密钥事件e){
player.released(如getKeyCode());
}
public void keyTyped(KeyEvent e){
;
}
@凌驾
公共组件(图形g){
超级组件(g);
球员。油漆(g);
}
}
导入java.awt.Graphics;
导入java.awt.Rectangle;
导入java.awt.Color;
公开课选手{
公众的
静态最终整型宽度=50,高度=50;
公众的
游戏;
公众的
int左,右;
公众的
int-y;
公众的
int x,xa;
公共玩家(游戏,整数左,整数右,整数x){
这个游戏=游戏;
这个.x=x;
y=game.getHeight()-20;
this.left=左;
这个。右=右;
这个。y=y;
x=game.getWidth()-36;
}
公共无效更新(){
如果(x>0&&x
Take
setVisible(true)
并将其移动到
游戏的最后一个
构造函数。此外,在构建UI时,还应确保您在EDT的上下文中工作,有关更多详细信息,请参阅

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Game extends JFrame {

    public final static int WIDTH = 700, HEIGHT = 450;
    public GamePanel panel;

    public Game() {
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        setSize(WIDTH, HEIGHT);
        setVisible(true);
    }

    public GamePanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new Game();
            }
        });
    }
}
基本上,Swing的布局管理是懒惰的,它不会尝试更新容器层次结构,除非您告诉它(
revalidate
),或者它实现或调整大小,这是一件好事,因为操作可能会很昂贵

接下来,看看
player=newplayer(game,KeyEvent.VK_左,KeyEvent.VK_右,game.getWidth()-36)

您正在将播放机的位置设置为
36
像素,小于组件
width
,但当调用此选项时,
width
将为
0

基本上,在进行此类调用之前,您需要允许UI“结算”。这其实不是那么容易。您可以使用
ComponentListener
并监视
ComponentResistized
事件,但窗口在首次初始化时可以多次调整大小,为此,您需要“等待”直到大小“确定”,例如

public Game() {
    addComponentListener(new ComponentAdapter() {
        private boolean initalised = false;
        private Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                initalised = true;
                panel.init();
                timer.stop();
            }
        });

        @Override
        public void componentResized(ComponentEvent e) {
            if (!initalised) {
                timer.restart();
            }
        }
    });
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
public static class Player {
    //...
    public Player(GamePanel game, int left, int right, int x) {
        this.game = game;
        this.left = left;
        this.right = right;
        this.x = x;
        y = game.getHeight() - HEIGHT;
    }
然后您需要更新
GamePanel
以提供
init
方法

public class GamePanel extends JPanel implements ActionListener, KeyListener {

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

    public void init() {
        player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
        repaint();
    }
    //...
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (player != null) {
            player.paint(g);
        }
    }
}
你有一系列的“神奇”数字,这些数字并不等同于你实际要做的事情,例如

public Game() {
    addComponentListener(new ComponentAdapter() {
        private boolean initalised = false;
        private Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                initalised = true;
                panel.init();
                timer.stop();
            }
        });

        @Override
        public void componentResized(ComponentEvent e) {
            if (!initalised) {
                timer.restart();
            }
        }
    });
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
public static class Player {
    //...
    public Player(GamePanel game, int left, int right, int x) {
        this.game = game;
        this.left = left;
        this.right = right;
        this.x = x;
        y = game.getHeight() - HEIGHT;
    }
这不应该是
game.getWidth()-Player.WIDTH

然后在
播放器中

public Player(Game game, int left, int right, int x) {
    this.game = game;
    this.x = x;
    y = game.getHeight() - 20;
    //...
    this.y = y;
    x = game.getWidth() - 36;
}
public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }
将参数
x
指定给字段
x
,然后在构造函数末尾更改它?而且,
this.y=y
毫无意义

现在,让我们谈谈设置大小(宽度、高度)的坏主意
,这与为什么您的播放机没有显示在您希望的位置有关

窗户有装饰,所以你的可视区域总是小于实际的窗户大小,更糟糕的是,装饰的大小是可变的。相反,您应该使用
JFrame#pack
将窗口围绕其内容进行打包,并让内容提供有关其想要的大的提示

请查看以了解更多详细信息

您应该使用
pack
,而不是设置帧的大小

public Player(Game game, int left, int right, int x) {
    this.game = game;
    this.x = x;
    y = game.getHeight() - 20;
    //...
    this.y = y;
    x = game.getWidth() - 36;
}
public class Game extends JFrame {

    public GamePanel panel;

    public Game() {
        addComponentListener(new ComponentAdapter() {
            private boolean initalised = false;
            private Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    initalised = true;
                    panel.init();
                    timer.stop();
                }
            });

            @Override
            public void componentResized(ComponentEvent e) {
                if (!initalised) {
                    timer.restart();
                }
            }
        });
        setTitle("Game");
        setBackground(Color.WHITE);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        panel = new GamePanel(this);
        add(panel);
        setResizable(false);
        pack();
        setVisible(true);
    }
并允许
GamePanel
决定它想要多大

public static class GamePanel extends JPanel implements ActionListener, KeyListener {

    public final static int WIDTH = 700, HEIGHT = 450;

    public Game game;
    public Player player;

    public GamePanel(Game game) {
        setBackground(Color.GREEN);
        this.game = game;
        addKeyListener(this);
        setFocusable(true);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(WIDTH, HEIGHT);
    }
这也意味着,您不应该将
Game
传递给对象,而应该将
GamePanel
传递给对象并使用其维度,例如

public Game() {
    addComponentListener(new ComponentAdapter() {
        private boolean initalised = false;
        private Timer timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                initalised = true;
                panel.init();
                timer.stop();
            }
        });

        @Override
        public void componentResized(ComponentEvent e) {
            if (!initalised) {
                timer.restart();
            }
        }
    });
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
public static class Player {
    //...
    public Player(GamePanel game, int left, int right, int x) {
        this.game = game;
        this.left = left;
        this.right = right;
        this.x = x;
        y = game.getHeight() - HEIGHT;
    }
您也不应该使用
KeyListener
,而应该使用instead,这将解决焦点相关的问题,并使配置按键笔划更容易

基本上,你是