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

KeyBindings seem to work improperly and don't know why | Java

问题


我正在为我的 class 中的最终项目制作游戏,并且我正在处理键绑定。键绑定的工作方式不尽如人意。让我解释一下:

所以 objective 是在向出口(黑点)移动的同时将你的角色一次 "square" 移动一个。每次您按指定方向(A、S、D、W)的键绑定时,它应该检查 "terrain" 并将您移动到 ​​"floor"。

旁注:我还没有添加移除地形,因为我需要先让运动正常工作。

回到说明: 所以最大的问题是,当我第一次按下键绑定时,它会将字符从原始位置移开三个 "squares"。然后之后的任何移动都是随机的,有时会使玩家出界。我设置了它,所以每次激活键绑定时它都会打印出玩家的位置(见下面的代码)。我觉得我在按键绑定过程中做错了,因为这是我第一次进行按键绑定。
这是我的程序为我的角色运动提供的打印输出之一:

E:\Whosebug\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.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.access0(Unknown Source)
        at java.awt.EventQueue.run(Unknown Source)
        at java.awt.EventQueue.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)

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

现在我看了一个关于键绑定的 post () 并尝试将该技术应用到我的游戏中进行键绑定操作。我不知道我做错了什么是问题的一部分。

这是我为键绑定添加的代码:

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

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

如果您想自己动手,这里有一些工作代码:

主要Class

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

尝试将所有解释保持 "dumbed" 尽可能低,因为我仍在学习并且还不完全理解所有编码行话。

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

我认为这不是您所期望的行为。

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

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

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

I hit a keybinding for the first time it moves the character three "squares" away from the original position

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

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

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

此外,您不需要 up/down/left/right 方法。使用通用 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;
}

此外,我不太喜欢使用枚举。您仅限 up/down/lef/right。如果你想添加对角线移动的能力会怎样?查看 Motion Using the Keyboard 中的 KeyboardAnimation 示例。该示例中的 Action 允许您指定要移动到的点。因此,您不需要 if/else 检查枚举,您只需使用 Point 中指定的值来确定下一个位置。