所以我正在制作一个太空入侵者克隆。最初,我可以将游戏与一个简单的主类(创建框架,创建游戏玩法并启动线程)一起使用时没有问题。
但是后来我尝试实现开始菜单,结果全都废了。菜单显示成功,但是当我按开始键时,游戏性没有出现。
我的想法不多了,我完全陷入了困境。我对SO也有些陌生,因此,如果有什么遗漏,我将不胜感激。
以下是原始文件,没有任何菜单可以正常工作:
public static void main(String[] args) {
JFrame frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Gameplay gameplay = new Gameplay();
frame.add(gameplay);
frame.setVisible(true);
Thread t1 = new Thread(gameplay);
t1.start();
}
但是,当我尝试实现一个菜单然后玩游戏时,我遇到了种种麻烦。我创建了一个UI类以及一个实际的“游戏”类,如下所示:
public class UI {
JFrame frame, f2;
JPanel titrePanel, startButtonPanel, loadButtonPanel, p2;
JLabel nomJeu;
JButton startButton, loadButton;
Font fontTitre, fontStart;
Gameplay gameplay;
public void createUI(ChoixJeu cj) {
frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.black);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//------------------ECRAN MENU---------------------
//Titre
titrePanel = new JPanel();
titrePanel.setBounds(100, 100, 400, 100);
titrePanel.setBackground(Color.BLUE);
Font fontTitre = new Font("Times New Roman", Font.BOLD, 50);
Font fontStart = new Font("Times New Roman", Font.PLAIN, 20);
nomJeu = new JLabel("SpaceRaiders");
nomJeu.setForeground(Color.white);
nomJeu.setFont(fontTitre);
titrePanel.add(nomJeu);
//Start button
startButtonPanel = new JPanel();
startButtonPanel.setBounds(200, 400, 200, 40);
startButtonPanel.setBackground(Color.BLACK);
startButton = new JButton("START");
startButton.setBackground(Color.BLACK);
startButton.setForeground(Color.WHITE);
startButton.setFont(fontStart);
startButton.setFocusPainted(false);
startButton.addActionListener(cj);
startButton.setActionCommand("start");
startButtonPanel.add(startButton);
//Load Button
loadButtonPanel = new JPanel();
loadButtonPanel.setBounds(200, 440, 200, 100);
loadButtonPanel.setBackground(Color.BLACK);
loadButton = new JButton("LOAD");
loadButton.setBackground(Color.BLACK);
loadButton.setForeground(Color.WHITE);
loadButton.setFont(fontStart);
loadButton.setFocusPainted(false);
titrePanel.add(nomJeu);
loadButtonPanel.add(loadButton);
frame.add(startButtonPanel);
frame.add(titrePanel);
//------------------ECRAN MENU FIN---------------------
frame.setVisible(true);
}
还有游戏课...
public class Jeu {
ChoixJeu cj = new ChoixJeu();
UI ui = new UI();
Ecrans e = new Ecrans(ui);
Gameplay gp;
public static void main(String[] args) {
new Jeu();
}
public Jeu() {
ui.createUI(cj);
Gameplay gameplay = new Gameplay();
this.gp = gameplay;
}
public class ChoixJeu implements ActionListener {
@Override
public void actionPerformed(ActionEvent ae) {
String yourChoice = ae.getActionCommand();
switch (yourChoice) {
case "start":
e.montrerEcranJeu();
new Thread(gp).start();
ui.frame.add(gp);
break;
default:
break;
}
}
}
}
我还试图创建一种隐藏菜单面板的类/方法
public void montrerEcranJeu() {
//Cache Menu
ui.titrePanel.setVisible(false);
ui.startButtonPanel.setVisible(false);
//Montre Jeu
// ui.frame.add(gameplay);
}
以防万一Gameplay类。 run()方法位于底部
public class Gameplay extends JPanel implements KeyListener, ActionListener, Runnable {
private Ship player = new Ship(new Point(200, 555));
Timer t = new Timer(5, this);
private ArrayList<Laser> lasers = new ArrayList<Laser>();
private int laserNb;
private boolean readytofire;
private boolean shot = false;
private ArrayList<Invader> invaders = new ArrayList<Invader>();
private boolean pause;
public Gameplay() {
super();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
for (int j = 0; j < 80; j += 20) {
for (int i = 0; i < 20; i++) {
invaders.add(new Invader(5 + i * 30, j));
}
}
}
public boolean addLaser(Laser a) {
lasers.add(a);
return true;
}
public boolean addPlayer(Ship p) {
this.player = p;
return true;
}
@Override
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_RIGHT == e.getKeyCode()) {
moveRight();
}
if (KeyEvent.VK_LEFT == e.getKeyCode()) {
moveLeft();
}
if (KeyEvent.VK_SPACE == e.getKeyCode()) {
shoot();
System.out.println("Space Action from Gameplay is working");
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent ae) {
repaint();
}
public void moveRight() {
if (player.getCentre().getX() >= 580) {
player.setX(580);
} else {
double movement = player.getCentre().getX();
movement += 10;
player.setX(movement);
}
this.repaint();
}
public void moveLeft() {
if (player.getCentre().getX() <= 20) {
player.setX(20);
} else {
double movement = player.getCentre().getX();
movement -= 10;
player.setX(movement);
}
this.repaint();
}
public void shoot() {
shot = true;
if (readytofire) {
Point top = new Point(player.getTopX(), player.getTopY());
Laser laser = new Laser(top);
addLaser(laser);
}
}
public void moveShot() {
if (shot) {
for (Laser l : lasers) {
l.setY(l.getTopLeft().getY() - 1);
}
}
}
@Override
public void paint(Graphics g) {
setBackground(Color.black);
super.paint(g);
player.draw(g);
for (Laser l : lasers) {
l.draw(g);
}
for (Invader i : invaders) {
i.draw(g);
}
}
// public void paintComponent (Graphics g){
// Controle Thread
public void run() {
while (true) {
moveShot();
for (Invader i : invaders) {
i.moveAndUpdate();
}
// for (Invader i : invaders) {
// if (){
// System.out.println("YOU ARE DEAD!");
// }
// }
try {
Thread.sleep(10);
readytofire = true;
} catch (InterruptedException ex) {
Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
答案 0 :(得分:1)
因此,使用null
布局是您问题的开始。我可能建议使用CardLayout
,它旨在帮助您在视图之间动态切换。有关更多详细信息,请参见How to Use CardLayout。我还建议您花些时间通读Laying Out Components Within a Container,并找到一种或多种合适的布局来支持您的菜单。
您还会犯很多基本错误。 Swing并不是线程安全的,因此您应避免从EDT上下文外部更新UI(或UI依赖的内容)-有关更多信息,请参见Concurrency in Swing,有关可能的解决方案,请参见How to Use Swing Timers。 / p>
作为一般建议,应避免覆盖paint
,对于从JComponent
扩展的类,应改用paintComponent
。您还应该避免使用可能在绘制周期内更改组件状态的调用方法,这会增加重新绘制请求的数量并降低程序的性能(即,不要在绘制内部调用setBackground
)。
请查看Performing Custom Painting和Painting in AWT and Swing,以了解有关绘画系统如何工作以及如何最好地使用它的更多详细信息。
您还应该避免使用KeyListener
,当您在图片中引入其他可聚焦的组件时,这很可能会引起问题。相反,您应该改用Key bindings API
我已阅读[插入链接或教程],但仍然无济于事...
请原谅我,如果这不是一直发生的话。
为您提供教程链接的目的是鼓励您学习一些东西;
话虽如此,他们并不总是对解决方案“很明显”。在这种情况下,我要做的工作是从一个或多个新项目开始,这些项目专门致力于我试图理解的API方面。在这里,我可以孤立地探索概念,当我“认为”我理解它们时,尝试将其实现到我正在研究的项目中。这可能需要很多次迭代,但是一旦成功,我将对API有了更深入的了解和欣赏,然后我将获得一个简单的“复制-粘贴”解决方案