我一直在努力解决这个问题超过一个星期,并且非常感谢一些帮助。我正在使用gui开发我的第一个Java游戏,目前我有大约20个课程。游戏是一个简单的基于网格的星际迷航表示,JLabel图标围绕星系网格移动。问题是通常在大约7到10次移动后,会发生以下两种情况之一:一,当前象限中的扇区网格将消失,左上角只留下一个扇区;或者两个,企业图标将消失。
我没有处理线程的经验,但经过一些阅读后我认为这可能是因为事件调度线程没有与程序逻辑正确同步。我阅读了更新GUI的正确方法,并用invokeLater和invokeAndWait块包围了我对GUI(我认为)有任何影响的所有语句。
然而,这并没有解决问题。所以,今天我将所有内容重写为最小的可编辑单元(它不是那么小,但我无法弄清楚如何使它更小),同时仍然保持我的基本游戏结构,看看是否会改变任何东西。它没有。在7到10次移动后,GUI仍然会被破坏。
我的斗智尽头。我真的很感激你的帮助。
这是我的代码。它按原样编译和运行。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;
public class GUI extends JFrame
{
int screenwidth;
int screenheight;
public static void main(String[] args)
{
GUI gui = new GUI();
run(gui);
}
public static void run(final GUI gui)
{
Quadrant[][] galaxy = new Quadrant[8][8];
//populate galaxy with quadrants
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
galaxy[i][j] = new Quadrant(i, j);
}
}
//Quadrant to put in the view when game starts
Quadrant startingQuadrant = galaxy[0][0];
final QuadrantView quadrantView = startingQuadrant.getQuadrantView();
Enterprise enterprise;
Sector startingSector;
//add SectorViews to the QuadrantView
for (int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
startingQuadrant.getQuadrantView().addSectorView(startingQuadrant.getSectorArray()[i][j].getSectorView(), i, j);
}
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//initialize gui with the starting quadrant quadrantView
gui.intiGUI(quadrantView);
}
});
//start on sector (0, 0)
startingSector = startingQuadrant.getSectorArray()[0][0];
enterprise = new Enterprise(startingQuadrant, startingSector);
startingSector.setContainsEnterprise(true);
Scanner input = new Scanner(System.in);
Sector destinationSector;
int qRow; //destination quadrant row
int qCol; //destination quadrant column
int sRow; //destination sector row
int sCol; //destination sector column
while(true)
{
System.out.println("Enter quadrant row: ");
qRow = input.nextInt();
System.out.println("Enter quadrant column: ");
qCol = input.nextInt();
System.out.println("Enter sector row: ");
sRow = input.nextInt();
System.out.println("Enter sector column: ");
sCol = input.nextInt();
destinationSector = galaxy[qRow][qCol].getSectorArray()[sRow][sCol];
enterprise.move(destinationSector, galaxy[qRow][qCol], gui);
}
}
public GUI()
{
super("Star Trek");
//create an anonymous listener to close window and end game
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});
// get user's screen width and height
screenwidth = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
screenheight = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();
//set layout
getContentPane().setLayout(new BorderLayout());
resizeGUI();
setVisible(true);
validate();
}
private void resizeGUI()
{
// set window size
if (screenwidth >= 1280)
setSize(1024, 768);
else if (screenwidth >= 1024)
setSize(800, 600);
else if (screenwidth >= 800)
setSize(640, 480);
// maximize window
setExtendedState(this.getExtendedState() | this.MAXIMIZED_BOTH);
}
//initialize this gui with the starting QuadrantView
public void intiGUI(QuadrantView quadrantView)
{
getContentPane().add(quadrantView, BorderLayout.CENTER);
validate();
}
//reset the gui to hold the new QuadrantView
public void resetGUI(QuadrantView newQuadrantView)
{
getContentPane().add(newQuadrantView, BorderLayout.CENTER);
validate();
}
static class Quadrant
{
private int row;
private int col;
private QuadrantView quadrantView;
private Sector[][] sectorArray;
public Quadrant(int r, int c)
{
// quadrant row
row = r;
// quadrant columns
col = c;
// the view object associated with this quadrant
setQuadrantView(new QuadrantView(8, 8));
// an array to hold the sectors in this quadrant (req. 3.1.0)
sectorArray = new Sector[8][8];
// create the 64 sectors in this quadrant and add them to the array (req. 3.1.0)
for (int i = 0; i < sectorArray.length; i ++)
{
for (int j = 0; j < sectorArray[i].length; j++)
{
sectorArray[i][j] = new Sector(i, j, this);
}
}
}
public int getRow()
{
return row;
}
public int getCol()
{
return col;
}
public void setRow(int r)
{
row = r;
}
public void setCol(int c)
{
col = c;
}
public Sector[][] getSectorArray()
{
return sectorArray;
}
public QuadrantView getQuadrantView()
{
return quadrantView;
}
public void setQuadrantView(QuadrantView quadrantView)
{
this.quadrantView = quadrantView;
}
}
static class Sector
{
//sector row
private int row;
//sector column
private int col;
//the quadrant this sector is in
private Quadrant quadrant;
//the view associated with this sector
private SectorView sectorView;
//boolean values to determine what this sector holds (Req. 4.1.0)
private boolean containsEnterprise;
//if the sector holds the Enterprise, store a reference to it
private Enterprise enterprise;
public Sector(int r, int c, Quadrant q)
{
row = r;
col = c;
quadrant = q;
setSectorView(new SectorView());
containsEnterprise = false;
//print the sector's coordinates on the gui
sectorView.setID(row + ", " + col);
}
public int getRow()
{
return row;
}
public int getCol()
{
return col;
}
public void setRow(int r)
{
row = r;
}
public void setCol(int c)
{
col = c;
}
public Quadrant getQuadrant()
{
return quadrant;
}
public boolean containsEnterprise()
{
return containsEnterprise;
}
public void setContainsEnterprise(boolean containsEnterprise)
{
this.containsEnterprise = containsEnterprise;
if (containsEnterprise)
{
sectorView.showEnterpriseIcon();
}
else
{
sectorView.hideEnterpriseIcon();
}
}
public Enterprise getEnterprise()
{
return enterprise;
}
public void addEnterprise(Enterprise enterprise)
{
this.enterprise = enterprise;
}
public void removeEnterprise()
{
enterprise = null;
}
public SectorView getSectorView()
{
return sectorView;
}
public void setSectorView(SectorView sectorView)
{
this.sectorView = sectorView;
}
public String toString()
{
return Integer.toString(row)+ "." + Integer.toString(col);
}
}
//end Sector class
static class SectorView extends JPanel
{
// default font for text
private final Font TREK_FONT = new Font("Verdana", Font.BOLD, 10);
// color for text
private final Color LABEL_COLOR = Color.BLACK;
// component layout
private SpringLayout layout;
// displays sector ID
private JLabel IDLabel;
//enterprise display
private JLabel enterpriseIcon;
/*
* create a new SectorView
*/
public SectorView()
{
super();
//create and set layout for child components
layout = new SpringLayout();
this.setLayout(layout);
//initialize child components
initComponents();
//position and display child components
layoutComponents();
//set background color
setBackground(Color.DARK_GRAY);
//set border
setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
//set size of sectors
setPreferredSize(new Dimension(QuadrantView.SECTOR_SIZE, QuadrantView.SECTOR_SIZE));
}
/*
* initialize components
*/
private void initComponents()
{
// displays ID of this view
IDLabel = new JLabel("");
IDLabel.setFont(TREK_FONT);
IDLabel.setForeground(Color.WHITE);
// create an enterprise icon and make it invisible
enterpriseIcon = new JLabel("E");
enterpriseIcon.setForeground(Color.WHITE);
enterpriseIcon.setVisible(false);
}
/*
* lay out components and add them to this view
*/
private void layoutComponents()
{
// position components:
// ID label
layout.putConstraint(SpringLayout.WEST, IDLabel, 1, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, IDLabel, 1, SpringLayout.NORTH, this);
// enterprise icon
layout.putConstraint(SpringLayout.WEST, enterpriseIcon, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enterpriseIcon, 30, SpringLayout.NORTH, this);
// add to view
this.add(IDLabel);
this.add(enterpriseIcon);
}
public void showEnterpriseIcon()
{
enterpriseIcon.setVisible(true);
}
public void hideEnterpriseIcon()
{
enterpriseIcon.setVisible(false);
}
//the sector's (row, col) coordinates within the quadrant
public void setID(String id)
{
IDLabel.setText(id);
}
}
//end SectorView class
static class QuadrantView extends JPanel
{
//size of sectors
public final static int SECTOR_SIZE = 100;
private final Color BACKGROUND_COLOR = Color.DARK_GRAY;
private SpringLayout layout;
/*
* create a new QuadrantView with the specified width
* and height
*
* @param quadrantHeight height of quad. in sectors
* @param quadrantWidth width of quad. in secors
*/
public QuadrantView(int quadrantHeight, int quadrantWidth)
{
//call JPanel constructor
super();
//create and set the layout
layout = new SpringLayout();
setLayout(layout);
//set the size of the QuadrantView we are creating using the inherited JComponent method
setPreferredSize(new Dimension(quadrantWidth * SECTOR_SIZE, quadrantHeight * SECTOR_SIZE));
//set background color using the inherited JComponent method
setBackground(BACKGROUND_COLOR);
}
/*
* add the specified Sector to this view
*
* each sector is represented by a (row, column) pair
* @param sectorView SectorView to be added to the QuadrantView
* @param row row coordinate
* @param col column coordinate
*/
public void addSectorView(SectorView sectorView, int row, int col)
{
//position the sector
layout.putConstraint(SpringLayout.WEST, sectorView, col * SECTOR_SIZE, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, sectorView, row * SECTOR_SIZE, SpringLayout.NORTH, this);
//add sectorView to the layout using inherited method of Container class
this.add(sectorView);
}
}
static class Enterprise
{
protected Sector sectorLocation;
protected Quadrant quadrantLocation;
public Enterprise(Quadrant quadrant, Sector sector)
{
sectorLocation = sector;
quadrantLocation = quadrant;
sector.addEnterprise(this);
sector.setContainsEnterprise(true);
}
// Requirement 9.4.0
public boolean move(Sector destinationSector, final Quadrant destinationQuadrant, final GUI gui)
{
//if the destination quadrant is not our current quadrant, we need to update the gui (is updating this way causing a problem?)
if (!destinationQuadrant.equals(this.quadrantLocation))
{
//Put the new SectorViews in the new quadrant.
for (int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
destinationQuadrant.getQuadrantView().addSectorView(destinationQuadrant.getSectorArray()[i][j].getSectorView(), i, j);
}
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//initialize gui with the starting quadrant quadrantView
//replace the old quadrant view with the new one
gui.resetGUI(destinationQuadrant.getQuadrantView());
}
});
}
//remove the reference to this starship from the current sector
sectorLocation.removeEnterprise();
//sector no longer contains the Enterprise
sectorLocation.setContainsEnterprise(false);
//move to destination quadrant
quadrantLocation = destinationQuadrant;
//move to destination sector
sectorLocation = destinationSector;
//add a reference to this starship to the new sector
sectorLocation.addEnterprise(this);
//new sector now contains Enterprise
sectorLocation.setContainsEnterprise(true);
return true;
}
}//end Enterprise class
}
答案 0 :(得分:2)
限制线程之间交换的数据量。唯一需要交换的数据是键盘输入。特别是避免在线程之间共享字段 - 这会导致竞争条件。您的主循环应如下所示:
while(true)
{
final int qRow = input.nextInt();
final int qCol = input.nextInt();
final int sRow = input.nextInt();
final int sCol = input.nextInt();
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
move(qRow,qCol,sRow,sCol);
}
});
}
删除所有其他invokeAndWait
和invokeLater
。根本不要使用invokeLater
。它使你的程序变得不可预测。
尝试在初始化之前声明变量并将其标记为final。可变状态会导致错误。
我无法弄清楚为什么表会缩小到1x1。尝试使用GridLayout
代替SpringLayout
。它似乎更适合这种情况。