作为一个学习项目,我正在开发一个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;
}
}
}
}
这段代码有一个简单的问题:
@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这是为了修复KeyListener
API的短开头。
其次,你不应该修改多边形的点,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按钮单击“创建一只新青蛙”。