Keybind操作在开始时运行,但不是从实际按键操作

时间:2016-01-26 02:13:14

标签: java swing key-bindings

我用Java编写了最终项目的游戏编码,我们的老师为我们提供了一个Board类,它是一个允许我们在虚拟游戏板上放置和删除挂钩而不必自己编写代码的组件。我试图将键绑定添加到Board组件,但是当我运行程序时,我想要在按键上执行的操作发生但是当我键入键时它不会运行。

董事会类已经有一种方法来获取点击组件的位置,我认为这可能会干扰我的代码,但我不确定。

这是我试图添加键绑定的游戏类

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)
        {

        }

    }
}

这是董事会成员

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;
    }
}

1 个答案:

答案 0 :(得分:2)

你用脚本代码射击自己 - 你正在调用 run()而不是 start()

SYNC_BOARD.run();

这将在Swing事件线程上运行,可能会完全冻结您的GUI。

作为一般规则,你几乎不应该扩展Thread而是实现Runnable,但不管怎样,不要使用那个Thread代码 - 而是使用Swing Timer,因为你的代码没有中断,没有Thread。睡眠,它会让你的CPU非常繁忙,Swing Timer将帮助确保你的代码服从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
    }
}

理解这可能会导致一些重大问题,因为构造函数在程序创建时调用(因此你的键绑定&#34;工作&#34;当程序启动时),但它实际上是actionPerformed在按下右键时被调用。