所以我遇到的问题是游戏玩法()。当我们(我自己没有写这个代码所以我可能在回答某些事情时遇到一些麻烦)尝试将ImageComponent更新为另一个图像时,刷新JPanel以显示两个新图像,延迟代码1秒,然后显示下一张图片,它没有用。当我运行代码时,屏幕会冻结预期的延迟,然后会出现在while循环的最后一次迭代中显示的内容。基本上,它从开始的2个图像跳到最后的2个。即使我拿出了repaint();和revalidate();它做了同样的事情,所以我相信它根本不令人耳目一新。我该怎么办?
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Background {
private Pokemon user;
private Pokemon computer;
private final JFrame frame = new JFrame();
private final JLabel userMove = new JLabel("");
private final JLabel aiMove = new JLabel("");
private final JLabel hu = new JLabel("");
private final JLabel pch = new JLabel("");
private final JLabel moveFirst = new JLabel("");
private final JPanel mainPanel = new JPanel();
private JPanel backS = new JPanel( new FlowLayout(FlowLayout.LEFT, 0, 0)); //coderanch.com, written by David Bryon
private JComponent left;
private JComponent right;
private final long PERIOD = 500L; // Adjust to suit timing
private long lastTime = System.currentTimeMillis() - PERIOD;
Timer timer;
public void execute(int choice){
frame.setSize( 1000, 500);
backS.setSize(300, 1000);
final JPanel buttonPanel = new JPanel();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
//user choice for a pokemon, takes number from selection screen
if(choice == 1){
user = new Kyogre();
computer = aiRandom();
}
else if(choice == 2){
user = new Groudon();
computer = aiRandom();
}
else if(choice == 3){
user = new Mewtwo();
computer = aiRandom();
}
else if(choice == 4){
user = new Arceus();
computer = aiRandom();
}
else if(choice == 5){
user = new Pikachu();
computer = aiRandom();
}
else if(choice == 6){
user = new Snorlax();
computer = aiRandom();
}
//health bars
JPanel healthBarUser = new JPanel();
healthBarUser.setSize(500, 100);
healthBarUser.setBackground(Color.GRAY);
String h1 = "";
for(int i = 0; i < user.getHealth(); i+=10){
h1 += "|";
}
String h2 = "";
for(int i = 0; i < computer.getHealth(); i+=10){
h2 += "|";
}
/*try{
Thread.sleep(100);
}
catch(Exception e)
{
System.out.println("Exception caught");
}*/
hu.setText("Your HP: " + h1 + user.getHealth() +" ");
healthBarUser.add(hu);
JPanel healthBarPC = new JPanel();
healthBarPC.setBackground(Color.GRAY);
healthBarPC.setSize(500, 100);
pch.setText("Computer's HP: " + h2+ computer.getHealth());
healthBarUser.add(pch);
left = user.leftSide();
right = computer.rightSide();
backS.add(left);
backS.add(right);
//move buttons
JButton button1 = new JButton(user.accessMoves(0).getName());
JButton button2 = new JButton(user.accessMoves(1).getName());
JButton button3 = new JButton(user.accessMoves(2).getName());
JButton button4 = new JButton(user.accessMoves(3).getName());
userMove.setText( "You used: " );
aiMove.setText( "Computer used: " + " ");
moveFirst.setText("_____ attacked first");
//4 different button listeners
class b1Listener implements ActionListener{
public void actionPerformed(ActionEvent event){
gamePlay(0);
if(computer.getHealth() <=0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(0);
}
else if(user.getHealth() <= 0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(1);
}
}
}
class b2Listener implements ActionListener{
public void actionPerformed(ActionEvent event){
gamePlay(1);
if(computer.getHealth() <=0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(0);
}
else if(user.getHealth() <= 0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(1);
}
}
}
class b3Listener implements ActionListener{
public void actionPerformed(ActionEvent event){
gamePlay(2);
if(computer.getHealth() <=0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(0);
}
else if(user.getHealth() <= 0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(1);
}
}
}
class b4Listener implements ActionListener{
public void actionPerformed(ActionEvent event){
gamePlay(3);
if(computer.getHealth() <=0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(0);
}
else if(user.getHealth() <= 0){
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(1);
}
}
}
//adds liteners to buttons
button1.addActionListener( new b1Listener() );
button2.addActionListener( new b2Listener());
button3.addActionListener( new b3Listener() );
button4.addActionListener( new b4Listener() );
//adds all panels, text fields, etc to final pane
mainPanel.add(healthBarUser);
mainPanel.add(healthBarPC);
mainPanel.add(backS);
mainPanel.add(button1);
mainPanel.add(button2);
mainPanel.add(button3);
mainPanel.add(button4);
mainPanel.add(userMove);
mainPanel.add(aiMove);
mainPanel.add(moveFirst);
mainPanel.setBackground(Color.GRAY);
frame.add(mainPanel);
frame.setVisible(true);
}
//returns user's pokemon
public Pokemon getUserPokemon(){
return user;
}
//returns computer's pokemon
public Pokemon getAIPokemon(){
return computer;
}
//chooses a random pokemon for the computer
private Pokemon aiRandom(){
int s = (int)(Math.random() * 6 );
if(s == 0)
return new Kyogre();
if(s == 1)
return new Groudon();
if(s == 2)
return new Mewtwo();
if(s == 3)
return new Arceus();
if(s == 4)
return new Pikachu();
if(s == 5)
return new Snorlax();
return null;
}
//generates a random number so we can choose an ai move
private int aiMove(){
int i = (int)(Math.random() * 4);
return i;
}
//creates pop-up window if somebody's health drops to 0
private void gameEnd(int i){
String rt;
if(i == 0)
rt = "Congratulations! You won! " + computer.getClass().getName() + " fainted. Would you like to play again?";
else if(i == 1)
rt = "Sorry. You lost to the computer. " + user.getClass().getName() + " fainted. Would you like to play again?";
else
rt = "You and the computer tied. Would you like to play again?";
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
p.add(user.leftSide());
p.add(computer.rightSide());
JLabel j1 = new JLabel(rt);
ButtonGroup groupD = new ButtonGroup();
final JRadioButton y = new JRadioButton("Yes"); //allows us to run program with f already selected
final JRadioButton n = new JRadioButton("No", true);
groupD.add(y);
groupD.add(n);
JButton button = new JButton("Select");
class ConvertListener implements ActionListener{
public void actionPerformed(ActionEvent event){
SelectionScreen s = new SelectionScreen();
if(y.isSelected()){
s.execute();
frame.setVisible(false);
frame.dispose();
}
else if(n.isSelected()){
frame.setVisible(false);
frame.dispose();
}
}
}
ActionListener listener = new ConvertListener();
button.addActionListener(listener);
p.add(j1);
p.add(y);
p.add(n);
p.add(button);
frame.add(p);
frame.setVisible(true);
}
//runs and updates health bar
private String healthBar(Pokemon x){
String rt = "";
for(int i = 0; i < x.getHealth(); i +=10 ){
rt += "|";
}
return rt;
}
private void gamePlay(int us){
String h1 = "";
String h2 = "";
int c;
do{
c = aiMove();
}while(computer.accessMoves(c).getPP() <= 0);
if(user.accessMoves(us).getPP() <= 0 ){
JOptionPane.showMessageDialog(frame, "The move you selected has no PP left. Select another.");
return;
}
long lastTime = System.currentTimeMillis();
if(user.getSpeed() >= computer.getSpeed()){ //if user's speed is quicker, computer gets attacked first
computer.updateHealth(user, us);
userMove.setText("You used: " + user.accessMoves(us).getName());
user.accessMoves(us).lowerPP();
h2 = healthBar(computer); //health bar is changed
int usCount = 0;
int compCount= 0;
while(usCount < user.leftNumFramesMove(us)){
long thisTime = System.currentTimeMillis();
if ((thisTime - lastTime) >= PERIOD) {
lastTime = thisTime;
// backS.remove(left);
// backS.remove(right);
if(us == 0)
left = user.LeftSideMove0(usCount + 1);
else if(us == 1)
left = user.LeftSideMove1(usCount + 1);
else if(us == 2)
left = user.LeftSideMove2(usCount + 1);
else
left = user.LeftSideMove3(usCount + 1);
//backS.add(left);
// backS.add(right);
backS.revalidate();
usCount += 1;
}
usCount += 1;
}
while(compCount < user.rightNumFramesMove(us)){
long thisTime = System.currentTimeMillis();
if ((thisTime - lastTime) >= PERIOD) {
lastTime = thisTime;
if(us == 0)
left = user.LeftSideMove0(usCount);
else if(us == 1)
left = user.LeftSideMove1(usCount);
else if(us == 2)
left = user.LeftSideMove2(usCount);
else
left = user.LeftSideMove3(usCount);
if(us == 0)
right = user.RightSideMove0(compCount + 1, computer);
else if(us == 1)
right = user.RightSideMove1(compCount + 1, computer);
else if(us == 2)
right = user.RightSideMove2(compCount + 1, computer);
else
right = user.RightSideMove3(compCount, computer);
// backS.add(left);
//backS.add(right);
backS.revalidate();
compCount += 1;
}
}
pch.setText("Computer's HP: " + h2+ computer.getHealth());
moveFirst.setText("You attacked first.");
if(computer.getHealth() == 0){ //if computer dies, user wins
return;
}
/* backS.remove(left);
backS.remove(right);
left = new ImageComponent(user.getName() + "Left.jpg");
right = new ImageComponent(computer.getName() + "Right.jpg");
backS.add(left);
backS.add(right);
backS.repaint();*/
user.updateHealth(computer, aiMove());
aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + " ");
computer.accessMoves(c).lowerPP();
h1= healthBar(user);
hu.setText("Your HP: " + h1 + user.getHealth() +" ");
if(user.getHealth() == 0){
return;
}
}
else {
user.updateHealth(computer, aiMove());
aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + " ");
computer.accessMoves(c).lowerPP();
h1= healthBar(user);
hu.setText("Your HP: " + h1 + user.getHealth() +" ");
moveFirst.setText("Computer attacked first.");
computer.updateHealth(user, us);
userMove.setText("You used: " + user.accessMoves(us).getName());
user.accessMoves(us).lowerPP();
h2 = healthBar(computer);
//creates pause between player move and computer move
int usCount = 0;
int compCount= 0;
while(usCount < user.leftNumFramesMove(us)){
long thisTime = System.currentTimeMillis();
if ((thisTime - lastTime) >= PERIOD) {
lastTime = thisTime;
// backS.remove(left);
//backS.remove(right);
if(us == 0)
left = user.LeftSideMove0(usCount + 1);
else if(us == 1)
left = user.LeftSideMove1(usCount + 1);
else if(us == 2)
left = user.LeftSideMove2(usCount + 1);
else if(us == 3)
left = user.LeftSideMove3(usCount + 1);
right = computer.rightSide();
// backS.add(left);
// backS.add(right);
frame.revalidate();
frame.repaint();
backS.revalidate();
backS.repaint();
usCount += 1;
}
}
usCount += 1;
while(compCount < user.rightNumFramesMove(us)){
long thisTime = System.currentTimeMillis();
if ((thisTime - lastTime) >= PERIOD) {
lastTime = thisTime;
// backS.remove(left);
// backS.remove(right);
if(us == 0)
left = user.LeftSideMove0(usCount);
else if(us == 1)
left = user.LeftSideMove1(usCount);
else if(us == 2)
left = user.LeftSideMove2(usCount);
else if(us == 3)
left = user.LeftSideMove3(usCount);
if(us == 0)
right = user.RightSideMove0(compCount + 1, computer);
else if(us == 1)
right = user.RightSideMove1(compCount + 1, computer);
else if(us == 2)
right = user.RightSideMove2(compCount + 1, computer);
else if(us == 3)
right = user.RightSideMove3(compCount + 1, computer);
// backS.add(left);
// backS.add(right);
frame.revalidate();
frame.repaint();
backS.revalidate();
backS.repaint();
;
compCount += 1;
}
}
pch.setText("Computer's HP: " + h2+ computer.getHealth());
if(computer.getHealth() == 0){
return;
}
/*backS.remove(left);
backS.remove(right);
left = new ImageComponent(user.getClass().getName() + "Left.jpg");
right = new ImageComponent(computer.getClass().getName() + "Right.jpg");
backS.add(left);
backS.add(right);
backS.repaint(); */
}
}
}
答案 0 :(得分:1)
基本上,你阻止事件调度线程,阻止它更新屏幕。
在gamePlay
方法存在之前(并且actionPerformed
方法存在),屏幕上不会绘制任何内容。
请查看Concurrency in Swing了解详情。
通常,您应该考虑使用javax.swing.Timer
在Swing中执行基本动画。您可以使用Thread
,但这只会使问题复杂化
有关详细信息,请查看How to use Swing Timers
另外,请记住,Swing不是线程安全的。如果需要更新UI,则必须在Event Dispatching Thread
的上下文中执行此操作<强>更新... 强>
好的,所以这真的很复杂。
基本上,javax.swing.Timer
在指定的时间段内在EDT之外等待,然后触发更新,以便在EDT的上下文中通知已注册的ActionListener
。
这意味着,当您启动Timer
时,代码将在Timer
等待时继续运行...
例如......
Timer timer = new Timer(PERIOD, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Executed later...
}
});
timer.start();
// Not waiting, continue execution...
这意味着,根据您的代码,您需要设计某种“执行后”链,或者更好地设置动画,例如......
private void gamePlay(int us) {
String h1 = "";
String h2 = "";
int c;
do {
c = aiMove();
} while (computer.accessMoves(c).getPP() <= 0);
if (user.accessMoves(us).getPP() <= 0) {
JOptionPane.showMessageDialog(frame, "The move you selected has no PP left. Select another.");
return;
}
long lastTime = System.currentTimeMillis();
if (user.getSpeed() >= computer.getSpeed()) { //if user's speed is quicker, computer gets attacked first
computer.updateHealth(user, us);
userMove.setText("You used: " + user.accessMoves(us).getName());
user.accessMoves(us).lowerPP();
h2 = healthBar(computer); //health bar is changed
//......
MoveAnimationHandler handler = new MoveAnimationHandler(this, us, user, computer, new Runnable() {
@Override
public void run() {
pch.setText("Computer's HP: " + h2 + computer.getHealth());
moveFirst.setText("You attacked first.");
if (computer.getHealth() == 0) { //if computer dies, user wins
return;
}
/* backS.remove(left);
backS.remove(right);
left = new ImageComponent(user.getName() + "Left.jpg");
right = new ImageComponent(computer.getName() + "Right.jpg");
backS.add(left);
backS.add(right);
backS.repaint();*/
user.updateHealth(computer, aiMove());
aiMove.setText("Computer used: " + computer.accessMoves(c).getName() + " ");
computer.accessMoves(c).lowerPP();
h1 = healthBar(user);
hu.setText("Your HP: " + h1 + user.getHealth() + " ");
if (user.getHealth() == 0) {
return;
}
}
});
Timer timer = new Timer(40, handler);
timer.start();
MoveAnimationHandler
....
public class MoveAnimationHandler implements ActionListener {
private int usCount = 0;
private int compCount = 0;
private Pokemon user;
private Pokemon computer;
private int left;
private int right;
private int us;
private JComponent parent;
private Runnable whenDone;
public MoveAnimationHandler(JComponent parent, int us, Pokemon user, Pokemon computer, Runnable whenDone) {
this.parent = parent;
this.user = user;
this.computer = computer;
left = user.leftSide();
right = computer.rightSide();
this.us = us;
this.whenDone = whenDone;
}
@Override
public void actionPerformed(ActionEvent e) {
if (usCount < user.leftNumFramesMove(us) && compCount < user.rightNumFramesMove(us)) {
if (usCount < user.leftNumFramesMove(us)) {
if (us == 0) {
left = user.LeftSideMove0(usCount + 1);
} else if (us == 1) {
left = user.LeftSideMove1(usCount + 1);
} else if (us == 2) {
left = user.LeftSideMove2(usCount + 1);
} else {
left = user.LeftSideMove3(usCount + 1);
}
usCount += 1;
}
if (compCount < user.rightNumFramesMove(us)) {
if (us == 0) {
left = user.LeftSideMove0(usCount);
} else if (us == 1) {
left = user.LeftSideMove1(usCount);
} else if (us == 2) {
left = user.LeftSideMove2(usCount);
} else {
left = user.LeftSideMove3(usCount);
}
if (us == 0) {
right = user.RightSideMove0(compCount + 1, computer);
} else if (us == 1) {
right = user.RightSideMove1(compCount + 1, computer);
} else if (us == 2) {
right = user.RightSideMove2(compCount + 1, computer);
} else {
right = user.RightSideMove3(compCount, computer);
}
compCount += 1;
}
parent.repaint();
} else {
((Timer) e.getSource()).stop();
whenDone.run();
}
}
}
现在,情况变得更糟,因为你的ActionListener
依赖于输出,所以你需要一些方法来链接这些调用......
class b1Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
gamePlay(0, new Runnable() {
@Override
public void run() {
if (computer.getHealth() <= 0) {
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(0, null);
} else if (user.getHealth() <= 0) {
frame.remove(mainPanel);
frame.setSize(1050, 500);
gameEnd(1, null);
}
}
});
}
}
private void gamePlay(int us, final Runnable doAfter) {
//...
if (user.getSpeed() >= computer.getSpeed()) { //if user's speed is quicker, computer gets attacked first
//...
MoveAnimationHandler handler = new MoveAnimationHandler(this, us, user, computer, new Runnable() {
@Override
public void run() {
//...
doAfter.run();
}
});
Timer timer = new Timer(40, handler);
} else {
//...
}
}
这就是我所说的“因为你想要动画完成后执行”
关于帖子的开头,我会认真地重新考虑整个设计......
您应该查看Model-View-Controller模式和Observer Pattern
这将允许您将游戏的各个元素分离到孤立的责任区域,同时提供有关各种状态更新的急需通知,以使它们保持同步...