【问题标题】:How to move Polygon Object with KeyListener in Java如何在 Java 中使用 KeyListener 移动多边形对象
【发布时间】:2016-02-15 20:07:38
【问题描述】:

我正在开发一个 2D 游戏作为一个学习项目,但我遇到了一些困难。我无法弄清楚如何使用 JPanel(添加到 JFrame)中的 KeyListener 来移动 Polygon 对象。我试过 frog.translate(int x, int y) 方法,它不会更新位置。我也尝试过手动更改数组坐标。我的代码示例如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Board extends JPanel implements KeyListener {

    private Frog frog;

    public Board() {
        setBackground(Color.GREEN);
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;        

        frog = new Frog();   

        // Frog graphics
        g2.setColor(Color.BLACK);
        g2.drawPolygon(frog);
        g2.setColor(new Color(0,150,15));
        g2.fillPolygon(frog);
    }

    @Override
    public void keyTyped(KeyEvent ke) {
    }

    @Override
    public void keyPressed(KeyEvent ke) {
        int c = ke.getKeyCode();
        if(c == KeyEvent.VK_LEFT){
            frog.moveFrogLeft(25);
            //frog.translate(-25,0);
        }

        if(c == KeyEvent.VK_RIGHT){
            frog.moveFrogRight(25);
            //frog.translate(25,0);
        }

        if(c == KeyEvent.VK_UP){
            frog.moveFrogUp(25);
            //frog.translate(0,-25);
        }

        if(c == KeyEvent.VK_DOWN){
            frog.moveFrogDown(25);
            //frog.translate(0,25);
        }
        repaint();
     }

     @Override
     public void keyReleased(KeyEvent ke) {
     } 
 }

/////////////////////

import java.awt.Polygon;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Frog extends Polygon {

    private Integer[] xcoord;
    private Integer[] ycoord;

    public Frog(){

        xcoord = new Integer[] {5,10,10,15,15,20,
            20,30,30,35,35,40,40,
            45,45,40,40,30,30,40,
            40,45,45,40,40,35,35,
            30,30,20,20,15,15,10,
            10,5,5,10,10,20,20,
            10,10,5,5};

        ycoord = new Integer[] {10,10,5,5,20,20,
            10,10,20,20,5,5,10,10,
            15,15,25,25,30,30,35,35,
            40,40,45,45,35,35,40,40,
            35,35,45,45,40,40,35,35,
            30,30,25,25,15,15,10};

        for(int i = 0; i < xcoord.length; i++){
            this.addPoint(xcoord[i],ycoord[i]);
        }
    }

    public void moveFrogLeft(int x) {
        if(xcoord[0] - x < 0){
            //do nothing
        } else {
            for(int i = 0; i < xcoord.length; i++){
                xcoord[i] = xcoord[i] - x;
            }
        }
    }

    public void moveFrogRight(int x){
        if(xcoord[0] + x > 600){
            //do nothing
        } else {
            for(int i = 0; i < xcoord.length; i++){
                xcoord[i] = xcoord[i] + x;
            }
        }
    }

    public void moveFrogUp(int y){
        if(ycoord[0] - y < 0){
            //do nothing
        } else {
            for(int i = 0; i < ycoord.length; i++){
                ycoord[i] = ycoord[i] - y;
            }
        }
    }

    public void moveFrogDown(int y){
        if(ycoord[0] + y > 600){
            //do nothing
        } else {
            for(int i = 0; i < ycoord.length; i++){
                ycoord[i] = ycoord[i] + y;
            }
        }
    }
}

【问题讨论】:

    标签: java swing polygon keylistener


    【解决方案1】:

    这段代码有一个简单的问题:

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;        
    
        frog = new Frog();// <-- !!!!!
    
        // Frog graphics
        g2.setColor(Color.BLACK);
        g2.drawPolygon(frog);
        g2.setColor(new Color(0,150,15));
        g2.fillPolygon(frog);
    }
    

    每次绘制青蛙时,标记的线都会用新实例覆盖青蛙,从而将其重置为原始点。除了这是导致意外行为的原因这一明显问题外,从不paintComponent(...)-方法中进行任何不必要的计算。任何预计算、对象生成等都应该在paintComponent之外完成!!!

    【讨论】:

    • 我真是个傻瓜......我知道这会是这样简单的事情。我实现了更改,现在它与 translate 方法完美配合。非常感谢您的帮助!
    • @ineverfinishanyth 很高兴为您提供帮助 :)
    【解决方案2】:

    首先,我强烈反对你使用KeyListener,它充其量是麻烦的,更好的选择是使用Key Bindings API,它旨在修复KeyListener的短消息API。

    其次,你不应该修改多边形的点,2D 图形 API 实际上有一些非常巧妙的技巧,可以更容易和更快地改变你的位置(以及旋转和缩放)绘图。

    请仔细查看2D Graphics 了解更多详情。

    您可以简单地使用AffineTransform...

    ,而不是更改不考虑可见边界的多边形的点
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        Point location = frog.getLocation();
        AffineTransform at = AffineTransform.getTranslateInstance(location.x, location.y);
        g2d.transform(at);
        g2d.setColor(new Color(0, 150, 15));
        g2d.fill(frog);
        g2d.setColor(Color.BLACK);
        g2d.draw(frog);
        g2d.dispose();
    }
    

    这只是简单地将Graphics 上下文的原点更改为您要绘制多边形的位置(是的,我使用AffineTransform 还有另一个原因

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Polygon;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.geom.AffineTransform;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.ActionMap;
    import javax.swing.InputMap;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new Board());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        protected enum VerticalDirection {
            NONE, UP, DOWN;
        }
    
        protected enum HorizontalDirection {
            NONE, LEFT, RIGHT;
        }
    
        public static class Board extends JPanel {
    
            protected static final int Y_DELTA = 4;
            protected static final int X_DELTA = 4;
    
            private Frog frog;
            private VerticalDirection verticalDirection = VerticalDirection.NONE;
            private HorizontalDirection horizontalDirection = HorizontalDirection.NONE;
    
            public Board() {
                setBackground(Color.GREEN);
                frog = new Frog();
    
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Point location = frog.getLocation();
                        switch (verticalDirection) {
                            case UP:
                                location.y -= Y_DELTA;
                                break;
                            case DOWN:
                                location.y += Y_DELTA;
                                break;
                        }
                        switch (horizontalDirection) {
                            case LEFT:
                                location.x -= X_DELTA;
                                break;
                            case RIGHT:
                                location.x += X_DELTA;
                                break;
                        }
    
                        Rectangle bounds = frog.getBounds();
                        int width = bounds.x + bounds.width;
                        int height = bounds.y + bounds.height;
                        if (location.y < 0) {
                            location.y = 0;
                        } else if (location.y + height > getHeight()) {
                            location.y = getHeight() - height;
                        }
                        if (location.x < 0) {
                            location.x = 0;
                        } else if (location.x + width > getWidth()) {
                            location.x = getWidth() - width;
                        }
                        frog.setLocation(location);
                        repaint();
                    }
                });
                timer.start();
    
                addPressedKeyBinding("up", KeyEvent.VK_UP, new VerticalMovementAction(VerticalDirection.UP));
                addPressedKeyBinding("down", KeyEvent.VK_DOWN, new VerticalMovementAction(VerticalDirection.DOWN));
                addPressedKeyBinding("left", KeyEvent.VK_LEFT, new HorizontalMovementAction(HorizontalDirection.LEFT));
                addPressedKeyBinding("right", KeyEvent.VK_RIGHT, new HorizontalMovementAction(HorizontalDirection.RIGHT));
    
                addReleasedKeyBinding("up", KeyEvent.VK_UP, new VerticalMovementAction(VerticalDirection.NONE));
                addReleasedKeyBinding("down", KeyEvent.VK_DOWN, new VerticalMovementAction(VerticalDirection.NONE));
                addReleasedKeyBinding("left", KeyEvent.VK_LEFT, new HorizontalMovementAction(HorizontalDirection.NONE));
                addReleasedKeyBinding("right", KeyEvent.VK_RIGHT, new HorizontalMovementAction(HorizontalDirection.NONE));
            }
    
            protected void addPressedKeyBinding(String name, int virtuaKey, Action action) {
                addKeyBinding(name + ".pressed", KeyStroke.getKeyStroke(virtuaKey, 0, false), action);
            }
    
            protected void addReleasedKeyBinding(String name, int virtuaKey, Action action) {
                addKeyBinding(name + ".released", KeyStroke.getKeyStroke(virtuaKey, 0, true), action);
            }
    
            protected void addKeyBinding(String name, KeyStroke ks, Action action) {
                InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                ActionMap am = getActionMap();
    
                im.put(ks, name);
                am.put(name, action);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                Point location = frog.getLocation();
                AffineTransform at = AffineTransform.getTranslateInstance(location.x, location.y);
                g2d.transform(at);
                g2d.setColor(new Color(0, 150, 15));
                g2d.fill(frog);
                g2d.setColor(Color.BLACK);
                g2d.draw(frog);
                g2d.dispose();
            }
    
            protected class VerticalMovementAction extends AbstractAction {
    
                private VerticalDirection direction;
    
                public VerticalMovementAction(VerticalDirection direction) {
                    this.direction = direction;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    verticalDirection = direction;
                }
    
            }
    
            protected class HorizontalMovementAction extends AbstractAction {
    
                private HorizontalDirection direction;
    
                public HorizontalMovementAction(HorizontalDirection direction) {
                    this.direction = direction;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    horizontalDirection = direction;
                }
    
            }
    
        }
    
        public static class Frog extends Polygon {
    
            private Integer[] xcoord;
            private Integer[] ycoord;
    
            private Point location;
    
            public Frog() {
    
                location = new Point(0, 0);
    
                xcoord = new Integer[]{5, 10, 10, 15, 15, 20,
                    20, 30, 30, 35, 35, 40, 40,
                    45, 45, 40, 40, 30, 30, 40,
                    40, 45, 45, 40, 40, 35, 35,
                    30, 30, 20, 20, 15, 15, 10,
                    10, 5, 5, 10, 10, 20, 20,
                    10, 10, 5, 5};
    
                ycoord = new Integer[]{10, 10, 5, 5, 20, 20,
                    10, 10, 20, 20, 5, 5, 10, 10,
                    15, 15, 25, 25, 30, 30, 35, 35,
                    40, 40, 45, 45, 35, 35, 40, 40,
                    35, 35, 45, 45, 40, 40, 35, 35,
                    30, 30, 25, 25, 15, 15, 10};
    
                for (int i = 0; i < xcoord.length; i++) {
                    this.addPoint(xcoord[i], ycoord[i]);
                }
            }
    
            public Point getLocation() {
                return location;
            }
    
            public void setLocation(Point location) {
                this.location = location;
            }
    
        }
    
    }
    

    现在,您可能想知道为什么我会使用AffineTransform 而不是Graphcis2D#translate,主要原因是,它很容易应用其他转换,例如旋转...

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        Point location = frog.getLocation();
    
        Rectangle bounds = frog.getBounds();
        int width = bounds.x + bounds.width;
        int height = bounds.y + bounds.height;
        AffineTransform at = AffineTransform.getTranslateInstance(location.x, location.y);
        at.rotate(Math.toRadians(angle), width / 2, height / 2);
        g2d.transform(at);
    
        g2d.setColor(new Color(0, 150, 15));
        g2d.fill(frog);
        g2d.setColor(Color.BLACK);
        g2d.draw(frog);
        g2d.dispose();
    }
    

    所有这些都是应用复合变换,移动 Graphics 上下文的原点和旋转矩阵

    还有一个完整的例子……

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Polygon;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.geom.AffineTransform;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.ActionMap;
    import javax.swing.InputMap;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new Board());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        protected enum VerticalDirection {
            NONE, UP, DOWN;
        }
    
        protected enum HorizontalDirection {
            NONE, LEFT, RIGHT;
        }
    
        public static class Board extends JPanel {
    
            protected static final int Y_DELTA = 4;
            protected static final int X_DELTA = 4;
    
            private Frog frog;
            private VerticalDirection verticalDirection = VerticalDirection.NONE;
            private HorizontalDirection horizontalDirection = HorizontalDirection.NONE;
    
            private double angle = 0; // Up...
    
            public Board() {
                setBackground(Color.GREEN);
                frog = new Frog();
    
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Point location = frog.getLocation();
                        switch (verticalDirection) {
                            case UP:
                                angle = 0;
                                location.y -= Y_DELTA;
                                break;
                            case DOWN:
                                angle = 180;
                                location.y += Y_DELTA;
                                break;
                        }
                        switch (horizontalDirection) {
                            case LEFT:
                                location.x -= X_DELTA;
                                angle = 270;
                                break;
                            case RIGHT:
                                location.x += X_DELTA;
                                angle = 90;
                                break;
                        }
    
                        Rectangle bounds = frog.getBounds();
                        int width = bounds.x + bounds.width;
                        int height = bounds.y + bounds.height;
                        if (location.y < 0) {
                            location.y = 0;
                        } else if (location.y + height > getHeight()) {
                            location.y = getHeight() - height;
                        }
                        if (location.x < 0) {
                            location.x = 0;
                        } else if (location.x + width > getWidth()) {
                            location.x = getWidth() - width;
                        }
                        frog.setLocation(location);
                        repaint();
                    }
                });
                timer.start();
    
                addPressedKeyBinding("up", KeyEvent.VK_UP, new VerticalMovementAction(VerticalDirection.UP));
                addPressedKeyBinding("down", KeyEvent.VK_DOWN, new VerticalMovementAction(VerticalDirection.DOWN));
                addPressedKeyBinding("left", KeyEvent.VK_LEFT, new HorizontalMovementAction(HorizontalDirection.LEFT));
                addPressedKeyBinding("right", KeyEvent.VK_RIGHT, new HorizontalMovementAction(HorizontalDirection.RIGHT));
    
                addReleasedKeyBinding("up", KeyEvent.VK_UP, new VerticalMovementAction(VerticalDirection.NONE));
                addReleasedKeyBinding("down", KeyEvent.VK_DOWN, new VerticalMovementAction(VerticalDirection.NONE));
                addReleasedKeyBinding("left", KeyEvent.VK_LEFT, new HorizontalMovementAction(HorizontalDirection.NONE));
                addReleasedKeyBinding("right", KeyEvent.VK_RIGHT, new HorizontalMovementAction(HorizontalDirection.NONE));
            }
    
            protected void addPressedKeyBinding(String name, int virtuaKey, Action action) {
                addKeyBinding(name + ".pressed", KeyStroke.getKeyStroke(virtuaKey, 0, false), action);
            }
    
            protected void addReleasedKeyBinding(String name, int virtuaKey, Action action) {
                addKeyBinding(name + ".released", KeyStroke.getKeyStroke(virtuaKey, 0, true), action);
            }
    
            protected void addKeyBinding(String name, KeyStroke ks, Action action) {
                InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                ActionMap am = getActionMap();
    
                im.put(ks, name);
                am.put(name, action);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                Point location = frog.getLocation();
    
                Rectangle bounds = frog.getBounds();
                int width = bounds.x + bounds.width;
                int height = bounds.y + bounds.height;
                AffineTransform at = AffineTransform.getTranslateInstance(location.x, location.y);
                at.rotate(Math.toRadians(angle), width / 2, height / 2);
                g2d.transform(at);
    
                g2d.setColor(new Color(0, 150, 15));
                g2d.fill(frog);
                g2d.setColor(Color.BLACK);
                g2d.draw(frog);
                g2d.dispose();
            }
    
            protected class VerticalMovementAction extends AbstractAction {
    
                private VerticalDirection direction;
    
                public VerticalMovementAction(VerticalDirection direction) {
                    this.direction = direction;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    verticalDirection = direction;
                }
    
            }
    
            protected class HorizontalMovementAction extends AbstractAction {
    
                private HorizontalDirection direction;
    
                public HorizontalMovementAction(HorizontalDirection direction) {
                    this.direction = direction;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    horizontalDirection = direction;
                }
    
            }
    
        }
    
        public static class Frog extends Polygon {
    
            private Integer[] xcoord;
            private Integer[] ycoord;
    
            private Point location;
    
            public Frog() {
    
                location = new Point(0, 0);
    
                xcoord = new Integer[]{5, 10, 10, 15, 15, 20,
                    20, 30, 30, 35, 35, 40, 40,
                    45, 45, 40, 40, 30, 30, 40,
                    40, 45, 45, 40, 40, 35, 35,
                    30, 30, 20, 20, 15, 15, 10,
                    10, 5, 5, 10, 10, 20, 20,
                    10, 10, 5, 5};
    
                ycoord = new Integer[]{10, 10, 5, 5, 20, 20,
                    10, 10, 20, 20, 5, 5, 10, 10,
                    15, 15, 25, 25, 30, 30, 35, 35,
                    40, 40, 45, 45, 35, 35, 40, 40,
                    35, 35, 45, 45, 40, 40, 35, 35,
                    30, 30, 25, 25, 15, 15, 10};
    
                // I rest the coordinates back to 0x0 because it's easier to 
                // deal with when applying a rotation...
                for (int index = 0; index < xcoord.length; index++) {
                    xcoord[index] -= 5;
                }
                for (int index = 0; index < ycoord.length; index++) {
                    ycoord[index] -= 5;
                }
    
                for (int i = 0; i < xcoord.length; i++) {
                    this.addPoint(xcoord[i], ycoord[i]);
                }
            }
    
            public Point getLocation() {
                return location;
            }
    
            public void setLocation(Point location) {
                this.location = location;
            }
    
        }
    
    }
    

    看,妈妈,没有数学!

    【讨论】:

      【解决方案3】:

      不要在您的 paintComponent() 方法中创建 Frog!那就是扔掉现有的青蛙并创建一个具有默认位置的新青蛙。 您应该在初始化面板时创建所有 Frog 实例,或者可能响应单击 b 按钮以“创建新青蛙”。

      【讨论】:

      • 感谢您的帮助,您也证实了 Paul 所说的话!
      猜你喜欢
      • 2017-02-18
      • 1970-01-01
      • 2023-03-22
      • 2018-10-05
      • 1970-01-01
      • 1970-01-01
      • 2022-12-01
      • 2014-07-29
      相关资源
      最近更新 更多