KeyBindings似乎工作不正常,不知道为什么| Java的

时间:2016-05-09 17:59:40

标签: java swing key-bindings

问题

<小时/> 我正在为我的一个班级做最后一个项目的游戏,我正在研究Keybinding。 Keybindings的工作方式并非如此。让我解释一下:

因此,目标是在朝向出口(黑点)移动时,一次将角色移动一个“方形”。每次按指定方向(A,S,D,W)的键绑定时,它应检查“地形”并将其移至“地板”。

侧注:我还没有添加移除地形,因为我需要移动才能正常工作。

回到解释: 所以最大的问题是,当我第一次敲击键绑定时,它会将角色从原始位置移开三个“方块”。那之后的任何动作都是随机的,有时会让玩家超出范围。我已将其设置为每次激活键绑定时打印出播放器的位置(参见下面的代码)。我有一种感觉,我做了一些错误的键绑定过程,因为这是我第一次键入绑定的东西。
这是我的节目为我的角色运动提供的打印输出之一:

E:\StackOverflow\KeyBindings>java gamePanelMain
Player Start X: 0
Player Start Y: 0

Direction: Right, New X: 3
Direction: Right, New Y: 0

Direction: Right, New X: 9
Direction: Right, New Y: 0

Direction: Right, New X: 12
Direction: Right, New Y: 0

Direction: Down, New X: 12
Direction: Down, New Y: 3

Direction: Down, New X: 12
Direction: Down, New Y: 6

Direction: Down, New X: 12
Direction: Down, New Y: 8

Direction: Left, New X: 10
Direction: Left, New Y: 8

Direction: Left, New X: 7
Direction: Left, New Y: 8

Direction: Left, New X: 4
Direction: Left, New Y: 8

Direction: Down, New X: 4
Direction: Down, New Y: 11

Direction: Down, New X: 4
Direction: Down, New Y: 13

Direction: Down, New X: 4
Direction: Down, New Y: 17

Direction: Right, New X: 7
Direction: Right, New Y: 17

Direction: Right, New X: 17
Direction: Right, New Y: 17

Direction: Right, New X: 20
Direction: Right, New Y: 17

Direction: Right, New X: 23
Direction: Right, New Y: 17

Direction: Down, New X: 23
Direction: Down, New Y: 20

Direction: Down, New X: 23
Direction: Down, New Y: 23

Direction: Up, New X: 23
Direction: Up, New Y: 21

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 24
        at gamePanel.right(gamePanel.java:259)
        at gamePanel.changeCoord(gamePanel.java:192)
        at gamePanel$1.actionPerformed(gamePanel.java:46)
        at javax.swing.Timer.fireActionPerformed(Unknown Source)
        at javax.swing.Timer$DoPostEvent.run(Unknown Source)
        at java.awt.event.InvocationEvent.dispatch(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

正如您所看到的那样,它是完全随机的,并且运动没有连接到随机发生器或类似的东西。此外,我还没有添加代码来检查是否有界限,但我更担心的是首先让这个动作正确。

现在我查看了一个关于键绑定(Can't repaint my JFrame/JPanel)的帖子,并尝试将该技术应用于我的游戏以进行键绑定操作。我不知道我做错了什么是问题的一部分。

以下是我为密钥绑定添加的代码:

public enum Direction{
        UP,
        LEFT,
        DOWN,
        RIGHT;
    }

    private Set<Direction>movement;

    public gamePanel()
    {
        setBounds(115,93,480,480);//sets the size and location of gamePanel (x,y,w,h)
        setFocusable(true);



        movement = new HashSet<>(4);

        addKeyPressedBinding(KeyEvent.VK_A, "left.pressed", new MoveAction(movement, Direction.LEFT, true));
        addKeyReleasedBinding(KeyEvent.VK_A, "left.released", new MoveAction(movement, Direction.LEFT, false));

        addKeyPressedBinding(KeyEvent.VK_D, "right.pressed", new MoveAction(movement, Direction.RIGHT, true));
        addKeyReleasedBinding(KeyEvent.VK_D, "right.released", new MoveAction(movement, Direction.RIGHT, false));

        addKeyPressedBinding(KeyEvent.VK_W, "up.pressed", new MoveAction(movement, Direction.UP, true));
        addKeyReleasedBinding(KeyEvent.VK_W, "up.released", new MoveAction(movement, Direction.UP, false));

        addKeyPressedBinding(KeyEvent.VK_S, "down.pressed", new MoveAction(movement, Direction.DOWN, true));
        addKeyReleasedBinding(KeyEvent.VK_S, "down.released", new MoveAction(movement, Direction.DOWN, false));

        Timer timer = new Timer(100, new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
                changeCoord();

            }
        });

        timer.start();

        System.out.println("Player Start X: " + pcX);
        System.out.println("Player Start Y: " + pcY + "\n");


    }

    protected void addKeyBinding(int keyCode, String name, Action action){
        addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
    }
        protected void addKeyPressedBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
        }

        protected void addKeyReleasedBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
        }

        protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();
            inputMap.put(keyStroke, name);
            actionMap.put(name, action);
        }   


    //Later in the code after the generation and painting of the map...............

              public void changeCoord() {

            if (movement.contains(Direction.UP)) {
                up();//checks position and moves player if it is "safe"
                System.out.println("Direction: Up, New X: " + pcX);
                System.out.println("Direction: Up, New Y: " + pcY + "\n");
            } else if (movement.contains(Direction.DOWN)) {
                down();//checks position and moves player if it is "safe"
                System.out.println("Direction: Down, New X: " + pcX);
                System.out.println("Direction: Down, New Y: " + pcY + "\n");                
            }
            if (movement.contains(Direction.LEFT)) {
                left();//checks position and moves player if it is "safe"
                System.out.println("Direction: Left, New X: " + pcX);
                System.out.println("Direction: Left, New Y: " + pcY + "\n");                
            } else if (movement.contains(Direction.RIGHT)) {
                right();//checks position and moves player if it is "safe"
                System.out.println("Direction: Right, New X: " + pcX);
                System.out.println("Direction: Right, New Y: " + pcY + "\n");               
            }

            repaint();
        }

        public class MoveAction extends AbstractAction{
            private Set<Direction> movement;
            private Direction direction;
            private boolean pressed;

        public MoveAction(Set<Direction> movement, Direction direction, boolean pressed) {
            this.movement = movement;
            this.direction = direction;
            this.pressed = pressed;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (pressed) {
                movement.add(direction);
            } else {
                movement.remove(direction);
            }
        }           
        }

问题 我是否在键绑定过程中出错了?如果是这样,我该如何解决?如果不是我做错了什么?

如果您想自己搞砸一下,可以使用以下代码:

主要类

import javax.swing.JFrame;

public class gamePanelMain{
    public static void main(String[] args){
        JFrame frame = new JFrame();    
        gamePanel panel = new gamePanel();
        frame.add(panel);       
        frame.setSize(520,540);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        panel.mapGen();

    }//end main
}

执行所有操作的代码

import java.awt.*;

    import java.awt.event.*;
    import javax.swing.*;
    import java.util.*;
    import java.awt.image.*;
    import javax.swing.Timer;



        public class gamePanel extends JPanel 
        {

        public enum Direction{
            UP,
            LEFT,
            DOWN,
            RIGHT;
        }

        private Set<Direction>movement;

        public gamePanel()
        {
            setBounds(115,93,480,480);//sets the size and location of gamePanel (x,y,w,h)
            setFocusable(true);



            movement = new HashSet<>(4);

            addKeyPressedBinding(KeyEvent.VK_A, "left.pressed", new MoveAction(movement, Direction.LEFT, true));
            addKeyReleasedBinding(KeyEvent.VK_A, "left.released", new MoveAction(movement, Direction.LEFT, false));

            addKeyPressedBinding(KeyEvent.VK_D, "right.pressed", new MoveAction(movement, Direction.RIGHT, true));
            addKeyReleasedBinding(KeyEvent.VK_D, "right.released", new MoveAction(movement, Direction.RIGHT, false));

            addKeyPressedBinding(KeyEvent.VK_W, "up.pressed", new MoveAction(movement, Direction.UP, true));
            addKeyReleasedBinding(KeyEvent.VK_W, "up.released", new MoveAction(movement, Direction.UP, false));

            addKeyPressedBinding(KeyEvent.VK_S, "down.pressed", new MoveAction(movement, Direction.DOWN, true));
            addKeyReleasedBinding(KeyEvent.VK_S, "down.released", new MoveAction(movement, Direction.DOWN, false));

            Timer timer = new Timer(100, new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent e){
                    changeCoord();

                }
            });

            timer.start();

            System.out.println("Player Start X: " + pcX);
            System.out.println("Player Start Y: " + pcY + "\n");


        }

        protected void addKeyBinding(int keyCode, String name, Action action){
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
        }
            protected void addKeyPressedBinding(int keyCode, String name, Action action) {
                addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
            }

            protected void addKeyReleasedBinding(int keyCode, String name, Action action) {
                addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
            }

            protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
                InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                ActionMap actionMap = getActionMap();
                inputMap.put(keyStroke, name);
                actionMap.put(name, action);
            }   

        private Random tGenerator = new Random();//initialize a random number generator

        int tmin = 1;
        int tmax = 20;

        int floor = 0;  //initializes the variable floor to zero for later use
        int dirt = 1;  //initializes the variable dirt to one for later use
        int stone = 2; //initializes the variable stone to two for later use

        int width = 24; // width of playing area
        int height = 24; //height of playing area
        int x, y; // my x & y variables for coordinates


        int[][] coords = new int[width][height]; //my array that I want to store the coordinates for later use in painting


        int[] terrain = {floor, dirt, stone}; //my terrain that will determine the color of the paint


        public void mapGen() //what should mark/generate the JPanel
        {

            for(x = 0; x < width; x++)
            {

                for(y = 0; y < height; y++)
                {

                    int t = tGenerator.nextInt(tmax - tmin + 1) + tmin; // random generator for terrain

                    if(t <= 10)
                    {
                        coords[x][y] = terrain[floor]; //should mark the coordinates as floor

                    }

                    if(t >= 12 && t <=16)
                    {
                        coords[x][y] = terrain[stone]; //should mark the coordinates as stone
                    }

                    if(t >=17 && t <= 19)
                    {
                        coords[x][y] = terrain[dirt]; //should mark the coordinates as dirt
                    }
                }
            }
                        coords[0][0] = terrain[0]; // sets coordinate 0,0 to floor 
                        coords[23][23] = terrain[0]; // sets coordinate 24,24 to floor 

        }//end mapGen


        public int pcY = 0;
        public int pcX = 0;     

        @Override
        public void paintComponent(Graphics g)//what will paint each 20x20 square on the grid what it is assigned
        {
            super.paintComponent(g);


        for(int x = 0; x < width; x++)
            {

                for(int y = 0; y < height; y++)
                {   

                    if(coords[x][y] == terrain[floor])// paints floor color at marked coordinates
                    {
                        g.setColor(new Color(249,249,249));
                        g.fillRect((x*20), (y*20), 20, 20); 

                    }

                    if(coords[x][y] == terrain[dirt])// paints dirt color at marked coordinates
                    {
                        g.setColor(new Color(121,85,58));
                        g.fillRect((x*20), (y*20), 20, 20);
                    }

                    if(coords[x][y] == terrain[stone])// paints stone color at marked coordinates
                    {
                        g.setColor(new Color(143,143,143));
                        g.fillRect((x*20),(y*20),20,20);
                    }

                }
            }

            g.setColor(Color.red);//creates the player "model"
            g.fillOval((pcX*20),(pcY*20),20,20);

            g.setColor(Color.black);
            g.fillOval((23*20),(23*20),20,20);

        }//end paintComponent

            public void changeCoord() {

                if (movement.contains(Direction.UP)) {
                    up();
                    System.out.println("Direction: Up, New X: " + pcX);
                    System.out.println("Direction: Up, New Y: " + pcY + "\n");
                } else if (movement.contains(Direction.DOWN)) {
                    down();
                    System.out.println("Direction: Down, New X: " + pcX);
                    System.out.println("Direction: Down, New Y: " + pcY + "\n");                
                }
                if (movement.contains(Direction.LEFT)) {
                    left();
                    System.out.println("Direction: Left, New X: " + pcX);
                    System.out.println("Direction: Left, New Y: " + pcY + "\n");                
                } else if (movement.contains(Direction.RIGHT)) {
                    right();
                    System.out.println("Direction: Right, New X: " + pcX);
                    System.out.println("Direction: Right, New Y: " + pcY + "\n");               
                }

                repaint();
            }

            public class MoveAction extends AbstractAction{
                private Set<Direction> movement;
                private Direction direction;
                private boolean pressed;

            public MoveAction(Set<Direction> movement, Direction direction, boolean pressed) {
                this.movement = movement;
                this.direction = direction;
                this.pressed = pressed;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                if (pressed) {
                    movement.add(direction);
                } else {
                    movement.remove(direction);
                }
            }           
            }


        public void up(){
                if(coords[pcX][pcY--] == terrain[floor]){
                    coords[pcX][pcY] = coords[pcX][pcY--];
                }

                else if(coords[pcX][pcY--] == terrain[dirt]){
                    coords[pcX][pcY] = coords[pcX][pcY--];
                }

                else if(coords[pcX][pcY--] == terrain[stone]){
                    coords[pcX][pcY] = coords[pcX][pcY--];
                }

            }

        public void down(){

                if(coords[pcX][pcY++] == terrain[floor]){
                    pcY++;
                }

                else if(coords[pcX][pcY++] == terrain[dirt]){
                    pcY++;
                }

                else if(coords[pcX][pcY++] == terrain[stone]){
                    pcY++;
                }           

            }

            public void right(){

                if(coords[pcX++][pcY] == terrain[floor]){
                    pcX += pcX+1;
                }

                else if(coords[pcX++][pcY]  == terrain[dirt]){
                    pcX++;
                }

                else if(coords[pcX++][pcY]  == terrain[stone]){
                    pcX++;
                }           

            }

            public void left(){

                if(coords[pcX--][pcY] == terrain[floor]){
                    pcX--;
                }           

                else if(coords[pcX--][pcY] == terrain[dirt]){
                    pcX--;
                }

                else if(coords[pcX--][pcY] == terrain[stone]){
                    pcX--;
                }           
            }   
    }// end gamePanel

尝试让所有解释尽可能“愚蠢”,因为我还在学习,并且还不了解所有的编码术语。

2 个答案:

答案 0 :(得分:1)

if(coords[pcX][pcY++] == terrain[floor]){
    pcY++;
}

else if(coords[pcX][pcY++] == terrain[dirt]){
    pcY++;
}

else if(coords[pcX][pcY++] == terrain[stone]){
    pcY++;
}           
  

我第一次击中了一个键绑定,它将角色从原始位置移开了三个“方块”

您多次使用“pcY ++”。每次在if语句中使用该变量时,变量都会递增。

因此,您会得到随机结果,因为每次移动时都会调用随机数量的if语句。

不要在if语句中对变量使用“++”。只有在通过测试时才会增加变量。

此外,您不需要上/下/左/右方法。使用常见Action的目的是指定Action如何影响x / y位置。所以changeCoord()可能看起来像:

public void changeCoord()
{
    int potentialX = pcX;
    int potentialY = pcY;

    if (movement.contains(Direction.LEFT)) potentialX--;
    if (movement.contains(Direction.RIGHT)) potentialX++;
    if (movement.contains(Direction.UP)) potentialY--;
    if (movement.contains(Direction.DOWN)) potentialY++;

    if (isValidMove(potentialX, potentially)
    {
        pcX = potentialX;
        pcY = potentialY;
    }

    repaint();
}


private boolean isValidMove(int potentialX, int potentialY)
{
    if (cords[potentialX][potentialY] == terrain[floor])
        return true;

    ...

    return false;
}

另外,我不是使用枚举的忠实粉丝。您仅限于上/下/左/右。如果您想要添加对角线移动的能力,会发生什么?查看Motion Using the Keyboard中的KeyboardAnimation示例。该示例中的Action允许您指定要移动的点。因此,您不需要if / else检查枚举,只需使用Point中指定的值来确定下一个位置。

答案 1 :(得分:0)

您不应该使用addKeyPressedBinding和addKeyReleasedBinding。 这样它将触发动作两次,一次是当用户按下键时,一次是当用户释放它时。

我认为这不是你期望的行为。