提问者:小点点

如何移动多边形对象与KeyListener在Java


作为一个学习项目,我正在开发一个2D游戏,我遇到了一个挫折。我不知道如何在JPanel(添加到JFrame中)中使用KeyListener移动多边形对象。我尝试了frog.转译(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;
            }
        }
    }
}

共3个答案

匿名用户

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

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

标记的行用一个新实例覆盖了青蛙,每次画青蛙时,都会将其重置到原点。除了明显的问题,这是意外行为的原因之外,永远不要在的画中画组件(…)-method中进行任何不必要的计算。任何预计算、对象生成等都应该在画中画组件之外完成!!!

匿名用户

首先,我强烈建议您不要使用KeyListener,这是最麻烦的,更好的选择是使用键绑定API这是为了修复KeyListenerAPI的短开头。

其次,你不应该修改多边形的点,2D图形API实际上能够使用一些非常简洁的技巧,这使得改变你正在绘制的内容的位置(以及旋转和缩放)变得更加容易和快速。

请仔细查看2D图形以获取更多详细信息。

您可以简单地使用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#翻译,主要原因是,它很容易应用其他转换,比如旋转…

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

    }

}

看,妈妈,没有数学!

匿名用户

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