键绑定动作在开始时是 运行 但不是从实际按键开始
Keybind action being run at start but not from actual key press
我正在为 Java 中的期末项目编写游戏代码,我们的老师为我们提供了一个棋盘 class,它是一个允许我们在虚拟游戏中放置和移除钉子的组件板,而不必自己编写代码。我正在尝试将键绑定添加到 Board 组件,但是当我 运行 程序时,我想要在按键上执行的操作正在发生,但当我键入键时它不会 运行。
开发板 class 已经有一种方法可以让点击组件的位置,我认为这可能会干扰我的代码,但我不确定。
这是我的游戏class,我尝试在其中添加键绑定
package rpgGame;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
public class RPGGame
{
public static final GameWorld WORLD_MAP = new GameWorld();
public static Board LOCAL_MAP = new Board(20,50);
public static List<Mobile> allMobs = new ArrayList<Mobile>();
public static final Player PLAYER = new Player();
public static int xIndex = ((GameWorld.WORLD_SIZE-1)/2) - (50/2);
public static int yIndex = ((GameWorld.WORLD_SIZE-1)/2) - (20/2);
public static boolean boardUpdate = true;
public enum Direction {RIGHT,LEFT,UP,DOWN}
private static final String MOVE_PLAYER_UP = "move up";
private static final String MOVE_PLAYER_LEFT = "move left";
private static final String MOVE_PLAYER_RIGHT = "move right";
private static final String MOVE_PLAYER_DOWN = "move down";
public static final Thread SYNC_BOARD = new Thread()
{
public synchronized void run()
{
while (boardUpdate)
{
for (int i = 0; i < 50; i++)
{
for (int j = 0; j < 20; j++)
{
if (WORLD_MAP.isOccupied(i+xIndex, j+yIndex))
{
LOCAL_MAP.putPeg(Color.RED, j, i);
System.out.println("Successfully Updated");
}
else
{
LOCAL_MAP.putPeg(Color.GRAY, j,i);
}
}
}
boardUpdate = false;
}
}
};
public RPGGame()
{
generateMobs(200);
placeMobs();
placePlayer();
SYNC_BOARD.run();
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), MOVE_PLAYER_UP);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), MOVE_PLAYER_UP);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), MOVE_PLAYER_LEFT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), MOVE_PLAYER_LEFT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), MOVE_PLAYER_RIGHT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), MOVE_PLAYER_RIGHT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), MOVE_PLAYER_DOWN);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), MOVE_PLAYER_DOWN);
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_UP, new MoveAction(Direction.UP));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_LEFT, new MoveAction(Direction.LEFT));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_RIGHT, new MoveAction(Direction.RIGHT));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_DOWN, new MoveAction(Direction.DOWN));
}
public static void main(String[] args)
{
new RPGGame();
}
public static void generateMobs(int numOfMobs)
{
for (int i=0; i<numOfMobs; i++)
{
allMobs.add(new Mobile());
}
}
public static void generateMobs()
{
int numOfMobs = (int)(Math.random()*500);
for (int i=0;i<numOfMobs; i++)
{
allMobs.add(new Mobile());
}
}
public static void placeMobs()
{
for (int i=0; i<allMobs.size(); i++)
{
//i is used as a placeholder value for points until I create a random number generator.
WORLD_MAP.placeCharacter(i, i,allMobs.get(i));
allMobs.get(i).setLocation(i, i);
}
}
public static void placePlayer()
{
WORLD_MAP.placeCharacter(249, 249, PLAYER);
PLAYER.setLocation(249, 249);
}
@SuppressWarnings("serial")
public class MoveAction extends AbstractAction
{
Direction direction;
public MoveAction(Direction direction)
{
if (direction.equals(Direction.RIGHT))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x+1, y, x, y);
PLAYER.move(1, 0);
boardUpdate = true;
System.out.println("MOVE RIGHT");
}
if (direction.equals(Direction.LEFT))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x-1, y);
PLAYER.move(-1, 0);
boardUpdate = true;
System.out.println("MOVE LEFT");
}
if (direction.equals(Direction.UP))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x, y+1);
PLAYER.move(0, 1);
boardUpdate = true;
System.out.println("MOVE UP");
}
if (direction.equals(Direction.DOWN))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x, y-1);
PLAYER.move(0, -1);
boardUpdate = true;
System.out.println("MOVE DOWN");
}
}
@Override
public void actionPerformed(ActionEvent e)
{
}
}
}
这是董事会class
package rpgGame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/** Board GUI for implementation with various games
* Author: Kirill Levin, Troy Vasiga, Chris Ingram
*/
@SuppressWarnings("serial")
public class Board extends JPanel
{
private static final int X_DIM = 60;
private static final int Y_DIM = 60;
private static final int X_OFFSET = 30;
private static final int Y_OFFSET = 30;
private static final double MIN_SCALE = 0.25;
private static final int GAP = 10;
private static final int FONT_SIZE = 16;
// Grid colours
private static final Color GRID_COLOR_A = new Color(153,255,102);
private static final Color GRID_COLOR_B = new Color(136,255,77);
private Color[][] grid;
private Point lastClick; // How the mouse handling thread communicates
// to the board where the last click occurred
private String message = "";
private int numLines = 0;
private double[][] line = new double[4][100]; // maximum number of lines is 100
private int columns, rows;
private int originalWidth;
private int originalHeight;
private double scale;
/** A constructor to build a 2D board.
*/
public Board (int rows, int columns)
{
super( true );
JFrame boardFrame = new JFrame( "Board game" );
this.columns = columns;
this.rows = rows;
originalWidth = 2*X_OFFSET+X_DIM*columns;
originalHeight = 2*Y_OFFSET+Y_DIM*rows+GAP+FONT_SIZE;
this.setPreferredSize( new Dimension( originalWidth, originalHeight ) );
boardFrame.setResizable(true);
this.grid = new Color[columns][rows];
this.addMouseListener(
new MouseInputAdapter()
{
/** A method that is called when the mouse is clicked
*/
public void mouseClicked(MouseEvent e)
{
int x = (int)e.getPoint().getX();
int y = (int)e.getPoint().getY();
// We need to by synchronized to the parent class so we can wake
// up any threads that might be waiting for us
synchronized(Board.this)
{
int curX = (int)Math.round(X_OFFSET*scale);
int curY = (int)Math.round(Y_OFFSET*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*grid.length)*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale);
// Subtract one from high end so clicks on the black edge
// don't yield a row or column outside of board because of
// the way the coordinate is calculated.
if (x >= curX && y >= curY && x < nextX && y < nextY)
{
lastClick = new Point(y,x);
// Notify any threads that would be waiting for a mouse click
Board.this.notifyAll() ;
} /* if */
} /* synchronized */
} /* mouseClicked */
} /* anonymous MouseInputAdapater */
);
boardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
boardFrame.setContentPane( this );
boardFrame.pack();
boardFrame.setVisible(true);
}
/** A constructor to build a 1D board.
*/
public Board (int cols)
{
this(1, cols);
}
private void paintText(Graphics g)
{
g.setColor( this.getBackground() );
g.setFont(new Font(g.getFont().getFontName(), Font.ITALIC+Font.BOLD, (int)(Math.round(FONT_SIZE*scale))));
int x = (int)Math.round(X_OFFSET*scale);
int y = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale + GAP ) ;
g.fillRect(x,y, this.getSize().width, (int)Math.round(GAP+FONT_SIZE*scale) );
g.setColor( Color.black );
g.drawString(message, x, y + (int)Math.round(FONT_SIZE*scale));
}
private void paintGrid(Graphics g)
{
for (int i = 0; i < this.grid.length; i++)
{
for (int j = 0; j < this.grid[i].length; j++)
{
if ((i%2 == 0 && j%2 != 0) || (i%2 != 0 && j%2 == 0))
g.setColor(GRID_COLOR_A);
else
g.setColor(GRID_COLOR_B);
int curX = (int)Math.round((X_OFFSET+X_DIM*i)*scale);
int curY = (int)Math.round((Y_OFFSET+Y_DIM*j)*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*(i+1))*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*(j+1))*scale);
int deltaX = nextX-curX;
int deltaY = nextY-curY;
g.fillRect( curX, curY, deltaX, deltaY );
Color curColour = this.grid[i][j];
if (curColour != null) // Draw pegs if they exist
{
g.setColor(curColour);
g.fillOval(curX+deltaX/4, curY+deltaY/4, deltaX/2, deltaY/2);
}
}
}
((Graphics2D) g).setStroke( new BasicStroke(0.5f) );
g.setColor(Color.BLACK);
int curX = (int)Math.round(X_OFFSET*scale);
int curY = (int)Math.round(Y_OFFSET*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*grid.length)*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale);
g.drawRect(curX, curY, nextX-curX, nextY-curY);
}
private void drawLine(Graphics g)
{
for (int i =0; i < numLines; i++ )
{
((Graphics2D) g).setStroke( new BasicStroke( 5.0f*(float)scale) );
g.drawLine( (int)Math.round((X_OFFSET+X_DIM/2.0+line[0][i]*X_DIM)*scale),
(int)Math.round((Y_OFFSET+Y_DIM/2.0+line[1][i]*Y_DIM)*scale),
(int)Math.round((X_OFFSET+X_DIM/2.0+line[2][i]*X_DIM)*scale),
(int)Math.round((Y_OFFSET+Y_DIM/2.0+line[3][i]*Y_DIM)*scale) );
}
}
/**
* Convert a String to the corresponding Color defaulting to Black
* with an invald input
*/
/*private Color convertColour( String theColour )
{
for( int i=0; i<COLOUR_NAMES.length; i++ )
{
if( COLOUR_NAMES[i].equalsIgnoreCase( theColour ) )
return COLOURS[i];
}
return DEFAULT_COLOUR;
}*/
/** The method that draws everything
*/
public void paintComponent( Graphics g )
{
this.setScale();
this.paintGrid(g);
this.drawLine(g);
this.paintText(g);
}
public void setScale()
{
double width = (0.0+this.getSize().width) / this.originalWidth;
double height = (0.0+this.getSize().height) / this.originalHeight;
this.scale = Math.max( Math.min(width,height), MIN_SCALE );
}
/** Sets the message to be displayed under the board
*/
public void displayMessage(String theMessage)
{
message = theMessage;
this.repaint();
}
/** This method will save the value of the colour of the peg in a specific
* spot. theColour is restricted to
* "yellow", "blue", "cyan", "green", "pink", "white", "red", "orange"
* Otherwise the colour black will be used.
*/
public void putPeg(Color colour, int row, int col)
{
this.grid[col][row] = colour;
this.repaint();
}
/** Same as putPeg above but for 1D boards
*/
public void putPeg(Color colour, int col)
{
this.putPeg(colour, 0, col );
}
/** Remove a peg from the gameboard.
*/
public void removePeg(int row, int col)
{
this.grid[col][row] = null;
repaint();
}
/** Same as removePeg above but for 1D boards
*/
public void removePeg(int col)
{
this.grid[col][0] = null;
repaint();
}
/** Draws a line on the board using the given co-ordinates as endpoints
*/
public void drawLine(double row1, double col1, double row2, double col2)
{
this.line[0][numLines]=col1;
this.line[1][numLines]=row1;
this.line[2][numLines]=col2;
this.line[3][numLines]=row2;
this.numLines++;
repaint();
}
/** Removes one line from a board given the co-ordinates as endpoints
* If there is no such line, nothing happens
* If multiple lines, all copies are removed
*/
public void removeLine(int row1, int col1, int row2, int col2)
{
int curLine = 0;
while (curLine < this.numLines)
{
// Check for either endpoint being specified first in our line table
if ( (line[0][curLine] == col1 && line[1][curLine] == row1 &&
line[2][curLine] == col2 && line[3][curLine] == row2) ||
(line[2][curLine] == col1 && line[3][curLine] == row1 &&
line[0][curLine] == col2 && line[1][curLine] == row2) )
{
// found a matching line: overwrite with the last one
numLines--;
line[0][curLine] = line[0][numLines];
line[1][curLine] = line[1][numLines];
line[2][curLine] = line[2][numLines];
line[3][curLine] = line[3][numLines];
curLine--; // perhaps the one we copied is also a match
}
curLine++;
}
repaint();
}
/** Waits for user to click somewhere and then returns the click.
*/
public Point getClick()
{
Point returnedClick = null;
synchronized(this) {
lastClick = null;
while (lastClick == null)
{
try {
this.wait();
} catch(Exception e) {
// We'll never call Thread.interrupt(), so just consider
// this an error.
e.printStackTrace();
System.exit(-1) ;
} /* try */
}
int x = (int)Math.floor((lastClick.getY()-X_OFFSET*scale)/X_DIM/scale);
int y = (int)Math.floor((lastClick.getX()-Y_OFFSET*scale)/Y_DIM/scale);
// Put this into a new object to avoid a possible race.
returnedClick = new Point(x,y);
}
return returnedClick;
}
/** Same as getClick above but for 1D boards
*/
public double getPosition()
{
return this.getClick().getY();
}
public int getColumns()
{
return this.columns;
}
public int getRows()
{
return this.rows;
}
}
你用线程代码搬起石头砸自己的脚——你调用的是 运行() 而不是 start() 就可以了
SYNC_BOARD.run();
这将 运行 在 Swing 事件线程上并有完全冻结您的 GUI 的风险。
作为一般规则,您几乎不应该扩展 Thread,而是实现 Runnable,但无论如何,不要使用 Thread 代码——而是使用 Swing Timer,因为您的代码没有中断,没有 Thread.sleeps 并且它会让您的 CPU 非常忙碌,而 Swing 计时器将帮助确保您的代码遵守 Swing 线程规则。
你的MoveAction也是错误的。大多数代码应该放在 actionPerformed 方法中。构造函数应该只设置方向字段,仅此而已。
类似于:
@SuppressWarnings("serial")
public class MoveAction extends AbstractAction {
Direction direction;
public MoveAction(Direction direction) {
// this is the only code the constructor should have!
this.direction = direction;
}
@Override
public void actionPerformed(ActionEvent e) {
// use direction to help make move in here
}
}
了解这可能会导致一些重大问题,因为在程序创建时会调用构造函数(因此在程序启动时会调用键绑定 "work"),但在正确的时候实际调用的是 actionPerformed键被按下。
我正在为 Java 中的期末项目编写游戏代码,我们的老师为我们提供了一个棋盘 class,它是一个允许我们在虚拟游戏中放置和移除钉子的组件板,而不必自己编写代码。我正在尝试将键绑定添加到 Board 组件,但是当我 运行 程序时,我想要在按键上执行的操作正在发生,但当我键入键时它不会 运行。
开发板 class 已经有一种方法可以让点击组件的位置,我认为这可能会干扰我的代码,但我不确定。
这是我的游戏class,我尝试在其中添加键绑定
package rpgGame;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
public class RPGGame
{
public static final GameWorld WORLD_MAP = new GameWorld();
public static Board LOCAL_MAP = new Board(20,50);
public static List<Mobile> allMobs = new ArrayList<Mobile>();
public static final Player PLAYER = new Player();
public static int xIndex = ((GameWorld.WORLD_SIZE-1)/2) - (50/2);
public static int yIndex = ((GameWorld.WORLD_SIZE-1)/2) - (20/2);
public static boolean boardUpdate = true;
public enum Direction {RIGHT,LEFT,UP,DOWN}
private static final String MOVE_PLAYER_UP = "move up";
private static final String MOVE_PLAYER_LEFT = "move left";
private static final String MOVE_PLAYER_RIGHT = "move right";
private static final String MOVE_PLAYER_DOWN = "move down";
public static final Thread SYNC_BOARD = new Thread()
{
public synchronized void run()
{
while (boardUpdate)
{
for (int i = 0; i < 50; i++)
{
for (int j = 0; j < 20; j++)
{
if (WORLD_MAP.isOccupied(i+xIndex, j+yIndex))
{
LOCAL_MAP.putPeg(Color.RED, j, i);
System.out.println("Successfully Updated");
}
else
{
LOCAL_MAP.putPeg(Color.GRAY, j,i);
}
}
}
boardUpdate = false;
}
}
};
public RPGGame()
{
generateMobs(200);
placeMobs();
placePlayer();
SYNC_BOARD.run();
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), MOVE_PLAYER_UP);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), MOVE_PLAYER_UP);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), MOVE_PLAYER_LEFT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), MOVE_PLAYER_LEFT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), MOVE_PLAYER_RIGHT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), MOVE_PLAYER_RIGHT);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), MOVE_PLAYER_DOWN);
LOCAL_MAP.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), MOVE_PLAYER_DOWN);
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_UP, new MoveAction(Direction.UP));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_LEFT, new MoveAction(Direction.LEFT));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_RIGHT, new MoveAction(Direction.RIGHT));
LOCAL_MAP.getActionMap().put(MOVE_PLAYER_DOWN, new MoveAction(Direction.DOWN));
}
public static void main(String[] args)
{
new RPGGame();
}
public static void generateMobs(int numOfMobs)
{
for (int i=0; i<numOfMobs; i++)
{
allMobs.add(new Mobile());
}
}
public static void generateMobs()
{
int numOfMobs = (int)(Math.random()*500);
for (int i=0;i<numOfMobs; i++)
{
allMobs.add(new Mobile());
}
}
public static void placeMobs()
{
for (int i=0; i<allMobs.size(); i++)
{
//i is used as a placeholder value for points until I create a random number generator.
WORLD_MAP.placeCharacter(i, i,allMobs.get(i));
allMobs.get(i).setLocation(i, i);
}
}
public static void placePlayer()
{
WORLD_MAP.placeCharacter(249, 249, PLAYER);
PLAYER.setLocation(249, 249);
}
@SuppressWarnings("serial")
public class MoveAction extends AbstractAction
{
Direction direction;
public MoveAction(Direction direction)
{
if (direction.equals(Direction.RIGHT))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x+1, y, x, y);
PLAYER.move(1, 0);
boardUpdate = true;
System.out.println("MOVE RIGHT");
}
if (direction.equals(Direction.LEFT))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x-1, y);
PLAYER.move(-1, 0);
boardUpdate = true;
System.out.println("MOVE LEFT");
}
if (direction.equals(Direction.UP))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x, y+1);
PLAYER.move(0, 1);
boardUpdate = true;
System.out.println("MOVE UP");
}
if (direction.equals(Direction.DOWN))
{
int x = PLAYER.getX();
int y = PLAYER.getY();
WORLD_MAP.moveCharacter(x, y, x, y-1);
PLAYER.move(0, -1);
boardUpdate = true;
System.out.println("MOVE DOWN");
}
}
@Override
public void actionPerformed(ActionEvent e)
{
}
}
}
这是董事会class
package rpgGame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/** Board GUI for implementation with various games
* Author: Kirill Levin, Troy Vasiga, Chris Ingram
*/
@SuppressWarnings("serial")
public class Board extends JPanel
{
private static final int X_DIM = 60;
private static final int Y_DIM = 60;
private static final int X_OFFSET = 30;
private static final int Y_OFFSET = 30;
private static final double MIN_SCALE = 0.25;
private static final int GAP = 10;
private static final int FONT_SIZE = 16;
// Grid colours
private static final Color GRID_COLOR_A = new Color(153,255,102);
private static final Color GRID_COLOR_B = new Color(136,255,77);
private Color[][] grid;
private Point lastClick; // How the mouse handling thread communicates
// to the board where the last click occurred
private String message = "";
private int numLines = 0;
private double[][] line = new double[4][100]; // maximum number of lines is 100
private int columns, rows;
private int originalWidth;
private int originalHeight;
private double scale;
/** A constructor to build a 2D board.
*/
public Board (int rows, int columns)
{
super( true );
JFrame boardFrame = new JFrame( "Board game" );
this.columns = columns;
this.rows = rows;
originalWidth = 2*X_OFFSET+X_DIM*columns;
originalHeight = 2*Y_OFFSET+Y_DIM*rows+GAP+FONT_SIZE;
this.setPreferredSize( new Dimension( originalWidth, originalHeight ) );
boardFrame.setResizable(true);
this.grid = new Color[columns][rows];
this.addMouseListener(
new MouseInputAdapter()
{
/** A method that is called when the mouse is clicked
*/
public void mouseClicked(MouseEvent e)
{
int x = (int)e.getPoint().getX();
int y = (int)e.getPoint().getY();
// We need to by synchronized to the parent class so we can wake
// up any threads that might be waiting for us
synchronized(Board.this)
{
int curX = (int)Math.round(X_OFFSET*scale);
int curY = (int)Math.round(Y_OFFSET*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*grid.length)*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale);
// Subtract one from high end so clicks on the black edge
// don't yield a row or column outside of board because of
// the way the coordinate is calculated.
if (x >= curX && y >= curY && x < nextX && y < nextY)
{
lastClick = new Point(y,x);
// Notify any threads that would be waiting for a mouse click
Board.this.notifyAll() ;
} /* if */
} /* synchronized */
} /* mouseClicked */
} /* anonymous MouseInputAdapater */
);
boardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
boardFrame.setContentPane( this );
boardFrame.pack();
boardFrame.setVisible(true);
}
/** A constructor to build a 1D board.
*/
public Board (int cols)
{
this(1, cols);
}
private void paintText(Graphics g)
{
g.setColor( this.getBackground() );
g.setFont(new Font(g.getFont().getFontName(), Font.ITALIC+Font.BOLD, (int)(Math.round(FONT_SIZE*scale))));
int x = (int)Math.round(X_OFFSET*scale);
int y = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale + GAP ) ;
g.fillRect(x,y, this.getSize().width, (int)Math.round(GAP+FONT_SIZE*scale) );
g.setColor( Color.black );
g.drawString(message, x, y + (int)Math.round(FONT_SIZE*scale));
}
private void paintGrid(Graphics g)
{
for (int i = 0; i < this.grid.length; i++)
{
for (int j = 0; j < this.grid[i].length; j++)
{
if ((i%2 == 0 && j%2 != 0) || (i%2 != 0 && j%2 == 0))
g.setColor(GRID_COLOR_A);
else
g.setColor(GRID_COLOR_B);
int curX = (int)Math.round((X_OFFSET+X_DIM*i)*scale);
int curY = (int)Math.round((Y_OFFSET+Y_DIM*j)*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*(i+1))*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*(j+1))*scale);
int deltaX = nextX-curX;
int deltaY = nextY-curY;
g.fillRect( curX, curY, deltaX, deltaY );
Color curColour = this.grid[i][j];
if (curColour != null) // Draw pegs if they exist
{
g.setColor(curColour);
g.fillOval(curX+deltaX/4, curY+deltaY/4, deltaX/2, deltaY/2);
}
}
}
((Graphics2D) g).setStroke( new BasicStroke(0.5f) );
g.setColor(Color.BLACK);
int curX = (int)Math.round(X_OFFSET*scale);
int curY = (int)Math.round(Y_OFFSET*scale);
int nextX = (int)Math.round((X_OFFSET+X_DIM*grid.length)*scale);
int nextY = (int)Math.round((Y_OFFSET+Y_DIM*grid[0].length)*scale);
g.drawRect(curX, curY, nextX-curX, nextY-curY);
}
private void drawLine(Graphics g)
{
for (int i =0; i < numLines; i++ )
{
((Graphics2D) g).setStroke( new BasicStroke( 5.0f*(float)scale) );
g.drawLine( (int)Math.round((X_OFFSET+X_DIM/2.0+line[0][i]*X_DIM)*scale),
(int)Math.round((Y_OFFSET+Y_DIM/2.0+line[1][i]*Y_DIM)*scale),
(int)Math.round((X_OFFSET+X_DIM/2.0+line[2][i]*X_DIM)*scale),
(int)Math.round((Y_OFFSET+Y_DIM/2.0+line[3][i]*Y_DIM)*scale) );
}
}
/**
* Convert a String to the corresponding Color defaulting to Black
* with an invald input
*/
/*private Color convertColour( String theColour )
{
for( int i=0; i<COLOUR_NAMES.length; i++ )
{
if( COLOUR_NAMES[i].equalsIgnoreCase( theColour ) )
return COLOURS[i];
}
return DEFAULT_COLOUR;
}*/
/** The method that draws everything
*/
public void paintComponent( Graphics g )
{
this.setScale();
this.paintGrid(g);
this.drawLine(g);
this.paintText(g);
}
public void setScale()
{
double width = (0.0+this.getSize().width) / this.originalWidth;
double height = (0.0+this.getSize().height) / this.originalHeight;
this.scale = Math.max( Math.min(width,height), MIN_SCALE );
}
/** Sets the message to be displayed under the board
*/
public void displayMessage(String theMessage)
{
message = theMessage;
this.repaint();
}
/** This method will save the value of the colour of the peg in a specific
* spot. theColour is restricted to
* "yellow", "blue", "cyan", "green", "pink", "white", "red", "orange"
* Otherwise the colour black will be used.
*/
public void putPeg(Color colour, int row, int col)
{
this.grid[col][row] = colour;
this.repaint();
}
/** Same as putPeg above but for 1D boards
*/
public void putPeg(Color colour, int col)
{
this.putPeg(colour, 0, col );
}
/** Remove a peg from the gameboard.
*/
public void removePeg(int row, int col)
{
this.grid[col][row] = null;
repaint();
}
/** Same as removePeg above but for 1D boards
*/
public void removePeg(int col)
{
this.grid[col][0] = null;
repaint();
}
/** Draws a line on the board using the given co-ordinates as endpoints
*/
public void drawLine(double row1, double col1, double row2, double col2)
{
this.line[0][numLines]=col1;
this.line[1][numLines]=row1;
this.line[2][numLines]=col2;
this.line[3][numLines]=row2;
this.numLines++;
repaint();
}
/** Removes one line from a board given the co-ordinates as endpoints
* If there is no such line, nothing happens
* If multiple lines, all copies are removed
*/
public void removeLine(int row1, int col1, int row2, int col2)
{
int curLine = 0;
while (curLine < this.numLines)
{
// Check for either endpoint being specified first in our line table
if ( (line[0][curLine] == col1 && line[1][curLine] == row1 &&
line[2][curLine] == col2 && line[3][curLine] == row2) ||
(line[2][curLine] == col1 && line[3][curLine] == row1 &&
line[0][curLine] == col2 && line[1][curLine] == row2) )
{
// found a matching line: overwrite with the last one
numLines--;
line[0][curLine] = line[0][numLines];
line[1][curLine] = line[1][numLines];
line[2][curLine] = line[2][numLines];
line[3][curLine] = line[3][numLines];
curLine--; // perhaps the one we copied is also a match
}
curLine++;
}
repaint();
}
/** Waits for user to click somewhere and then returns the click.
*/
public Point getClick()
{
Point returnedClick = null;
synchronized(this) {
lastClick = null;
while (lastClick == null)
{
try {
this.wait();
} catch(Exception e) {
// We'll never call Thread.interrupt(), so just consider
// this an error.
e.printStackTrace();
System.exit(-1) ;
} /* try */
}
int x = (int)Math.floor((lastClick.getY()-X_OFFSET*scale)/X_DIM/scale);
int y = (int)Math.floor((lastClick.getX()-Y_OFFSET*scale)/Y_DIM/scale);
// Put this into a new object to avoid a possible race.
returnedClick = new Point(x,y);
}
return returnedClick;
}
/** Same as getClick above but for 1D boards
*/
public double getPosition()
{
return this.getClick().getY();
}
public int getColumns()
{
return this.columns;
}
public int getRows()
{
return this.rows;
}
}
你用线程代码搬起石头砸自己的脚——你调用的是 运行() 而不是 start() 就可以了
SYNC_BOARD.run();
这将 运行 在 Swing 事件线程上并有完全冻结您的 GUI 的风险。
作为一般规则,您几乎不应该扩展 Thread,而是实现 Runnable,但无论如何,不要使用 Thread 代码——而是使用 Swing Timer,因为您的代码没有中断,没有 Thread.sleeps 并且它会让您的 CPU 非常忙碌,而 Swing 计时器将帮助确保您的代码遵守 Swing 线程规则。
你的MoveAction也是错误的。大多数代码应该放在 actionPerformed 方法中。构造函数应该只设置方向字段,仅此而已。
类似于:
@SuppressWarnings("serial")
public class MoveAction extends AbstractAction {
Direction direction;
public MoveAction(Direction direction) {
// this is the only code the constructor should have!
this.direction = direction;
}
@Override
public void actionPerformed(ActionEvent e) {
// use direction to help make move in here
}
}
了解这可能会导致一些重大问题,因为在程序创建时会调用构造函数(因此在程序启动时会调用键绑定 "work"),但在正确的时候实际调用的是 actionPerformed键被按下。