我试图通过CardLayout制作一个琐事游戏,以在单个JFrame中的屏幕之间切换。我有一个循环设置来遍历我的枚举中的状态。除了游戏结束时,如果我选择开始一个新游戏,它会以某种方式同时进入第一和第二个状态,一切都很顺利。我不确定这是怎么发生的,因为这是发生这种情况的唯一状态。
主要代码:
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.awt.CardLayout;
import java.awt.Color;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class Main
{
public enum State {SPLASH, PREQUESTION, QUESTION, WIN, LOSS};
public static JFrame frame;
public static JPanel content;
public static JPanel neutral;
public static int event;
public static Random rn = new Random();
public static Splash splash;
public static Prequestion eventStart;
public static Question question;
public static Win win;
public static Loss loss;
public static void main(String[] args) throws LineUnavailableException, UnsupportedAudioFileException, IOException
{
frame = new JFrame("DREWcathalon");
content = new JPanel();
neutral = new JPanel();
CardLayout cards = new CardLayout();
content.setLayout(cards);
neutral.setBackground(Color.WHITE);
content.add(neutral, "neutral");
frame.add(content);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 750);
frame.setVisible(true);
cards.show(content, "neutral");
State gameState = State.SPLASH;
while (true)
{
switch(gameState)
{
case SPLASH:
event = 0;
splash = new Splash(content, cards);
splash.splashSound();
while (splash.holdState()){};
cards.show(content, "neutral");
gameState = State.PREQUESTION;
splash = null;
break;
case PREQUESTION:
event++;
eventStart = new Prequestion(event, content, cards);
while (eventStart.holdState()){};
cards.show(content, "neutral");
gameState = State.QUESTION;
eventStart = null;
break;
case QUESTION:
question = new Question(event, rn.nextInt(5)+1, content, cards);
while (question.holdState()){};
cards.show(content, "neutral");
if (question.rightState() && event > 9)
{
gameState = State.WIN;
}
else if (question.rightState())
{
gameState = State.PREQUESTION;
}
else
{
gameState = State.LOSS;
}
question = null;
break;
case WIN:
win = new Win(content, cards);
while(win.holdState()){};
cards.show(content, "neutral");
gameState = State.SPLASH;
win = null;
break;
case LOSS:
loss = new Loss(content, cards);
while(loss.holdState()){};
cards.show(content, "neutral");
gameState = State.SPLASH;
loss = null;
break;
}
}
}
}
胜利代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.sound.sampled.*;
import java.io.*;
public class Win
{
static private Clip clip;
static private boolean hold = true;
public Win(JPanel content, CardLayout cards) throws UnsupportedAudioFileException, IOException, LineUnavailableException
{
JButton restart = new JButton("New Game+");
JButton quit = new JButton("Flee");
JLabel title = new JLabel("A Winnar is You!");
JPanel wContent = new JPanel();
wContent.add(title);
wContent.add(restart);
wContent.add(quit);
wContent.setBackground(Color.WHITE);
content.add(wContent, "win");
cards.show(content, "win");
File soundFile = new File("TEST.wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
restart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (clip.getMicrosecondPosition() < clip.getMicrosecondLength())
{
clip.stop();
}
hold = false;
}
});
quit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
public boolean holdState()
{
return hold;
}
}
答案 0 :(得分:3)
我没有具体问题的具体答案,这是我作为社区Wiki回答这个问题的一个原因,但我可以充满信心地说明你的程序结构已被破坏而且写的方式不是尊重面向对象的编程原则,如大量使用静态字段或GUI事件驱动的编码原则所证明,正如while (true)
循环所证明的那样。解决方案是完全重构您的程序,摆脱您的while (true)
循环,而是使用通知/观察者设计模式来驱动状态更改。
我几乎可以保证,如果您解决了这些问题,特别是通过摆脱while (true)
循环并将其替换为事件通知和收听,您的游戏重启问题将得到解决。
如果您需要更具体的帮助,则需要创建并发布有效的SSCCE(有关详细信息,请参阅链接)。我尝试用你的代码自己做这件事,但这花了我太长时间,努力真的应该是你的。
使用简单通知更改状态的非常简单的示例
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class Main2 extends JPanel {
private CardLayout cardLayout = new CardLayout();
private MyState myState = MyState.SPLASH;
private MySplash mySplash = new MySplash(this);
private MyPreQuestion myPreQuestion = new MyPreQuestion(this);
private MyQuestion myQuestion = new MyQuestion(this);
public Main2() {
setLayout(cardLayout);
add(mySplash, MyState.SPLASH.toString());
add(myPreQuestion, MyState.PREQUESTION.toString());
add(myQuestion, MyState.QUESTION.toString());
mySplash.startSplashTimer();
}
public void next() {
int index = 0;
for (int i = 0; i < MyState.values().length; i++) {
if (MyState.values()[i] == myState) {
index = i;
}
}
index++;
index %= MyState.values().length;
setState(MyState.values()[index]);
}
public void setState(MyState nextState) {
myState = nextState;
cardLayout.show(this, nextState.toString());
if (myState == MyState.SPLASH) {
mySplash.startSplashTimer();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Main2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
enum MyState {
SPLASH, PREQUESTION, QUESTION // ..., WIN, LOSS
}
@SuppressWarnings("serial")
class NextAction extends AbstractAction {
private Main2 main;
public NextAction(Main2 main) {
super("Next");
putValue(MNEMONIC_KEY, KeyEvent.VK_N);
this.main = main;
}
@Override
public void actionPerformed(ActionEvent e) {
main.next();
}
}
@SuppressWarnings("serial")
abstract class AbstractView extends JPanel {
private Main2 main;
public AbstractView(Main2 main) {
this.main = main;
}
public Main2 getMain() {
return main;
}
public void next() {
main.next();
}
}
@SuppressWarnings("serial")
class MySplash extends AbstractView {
private static final int TIMER_DELAY = 3000;
private Timer timer;
public MySplash(Main2 main) {
super(main);
setPreferredSize(new Dimension(300, 140));
add(new JLabel("My Splash"));
}
public void startSplashTimer() {
timer = new Timer(TIMER_DELAY, e -> {
next();
timer.stop();
});
timer.start();
}
}
@SuppressWarnings("serial")
class MyPreQuestion extends AbstractView {
public MyPreQuestion(Main2 main) {
super(main);
add(new JLabel("Prequestion"));
add(new JButton(new NextAction(main)));
}
}
@SuppressWarnings("serial")
class MyQuestion extends AbstractView {
public MyQuestion(Main2 main) {
super(main);
add(new JLabel("Question"));
add(new JButton(new NextAction(main)));
}
}