我试图通过按箭头键在网格周围移动蓝色方块。我已经设置了KeyListener
但是当我重新绘制框架时,我必须移动框架以便更新它。如何使其成为平滑动画(将方块从一个坐标移动到另一个坐标)?
示例:
if (keyCode == KeyEvent.VK_LEFT){
x5=x5-xChange;
frame.repaint();
}
我的图像是缓冲图像,并且都设置为特定坐标。 这是我的图形类:
public static class myGraphicsPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(block1,x1,y1,null);
g.drawImage(block2,x2,y2,null);
g.drawImage(block3,x3,y3,null);
g.drawImage(block4,x4,y4,null);
g.drawImage(block5,x5,y5,null);
g.drawImage(block6,x6,y6,null);
g.drawImage(block7,x7,y7,null);
g.drawImage(block8,x8,y8,null);
g.drawImage(blue,x9,y9,null);
}
答案 0 :(得分:1)
你的问题是缺少很多信息,屏幕是如何更新的?屏幕是如何创建的?这些物体之间有什么关系?
其中许多问题可以通过MCVE
来解答动画是随时间变化的幻觉。所以你需要一些东西。您需要一些方法来更改当前状态以及某种方式随着时间的推移触发和更新UI。
在Swing中执行此操作的最简单(也是最安全)的方法是使用Swing Timer
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.Timer;
public class TestAnimation {
public static void main(String[] args) {
new TestAnimation();
}
public TestAnimation() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private int xDelta, yDelta;
private int xPos, yPos;
public TestPane() throws IOException {
img = ImageIO.read(new File("/Users/shane/Dropbox/MegaTokyo/thumnails/2.jpg"));
Random rnd = new Random();
do {
xDelta = rnd.nextInt(4);
} while (xDelta == 0);
do {
yDelta = rnd.nextInt(4);
} while (yDelta == 0);
if (rnd.nextBoolean()) {
xDelta *= -1;
}
if (rnd.nextBoolean()) {
yDelta *= -1;
}
xPos = (getPreferredSize().width - img.getWidth()) / 2;
yPos = (getPreferredSize().height - img.getHeight()) / 2;
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
yPos += yDelta;
if (xPos + img.getWidth() > getWidth()) {
xPos = getWidth() - img.getWidth();
xDelta *= -1;
} else if (xPos < 0) {
xPos = 0;
xDelta *= -1;
}
if (yPos + img.getHeight() > getHeight()) {
yPos = getHeight() - img.getHeight();
yDelta *= -1;
} else if (yPos < 0) {
yPos = 0;
yDelta *= -1;
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(img, xPos, yPos, this);
g2d.dispose();
}
}
}
}
详细了解Concurrency in Swing和w to Use Swing Timers了解更多详情
但是,你如何使用键盘做到这一点?令人惊讶的是,它非常相似。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAnimation {
public static void main(String[] args) {
new TestAnimation();
}
public TestAnimation() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private int xPos, yPos;
public TestPane() throws IOException {
img = ImageIO.read(new File("/Users/shane/Dropbox/MegaTokyo/thumnails/2.jpg"));
xPos = (getPreferredSize().width - img.getWidth()) / 2;
yPos = (getPreferredSize().height - img.getHeight()) / 2;
addKeyBinding("up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new KeyAction(0, -4));
addKeyBinding("down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new KeyAction(0, 4));
addKeyBinding("left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new KeyAction(-4, 0));
addKeyBinding("right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new KeyAction(4, 0));
}
protected void addKeyBinding(String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(img, xPos, yPos, this);
g2d.dispose();
}
}
public class KeyAction extends AbstractAction {
private int xDelta, yDelta;
public KeyAction(int xDelta, int yDelta) {
this.xDelta = xDelta;
this.yDelta = yDelta;
}
@Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
yPos += yDelta;
if (xPos + img.getWidth() > getWidth()) {
xPos = getWidth() - img.getWidth();
} else if (xPos < 0) {
xPos = 0;
}
if (yPos + img.getHeight() > getHeight()) {
yPos = getHeight() - img.getHeight();
} else if (yPos < 0) {
yPos = 0;
}
repaint();
}
}
}
}
有关详细信息,请查看How to use key bindings和How to use actions
答案 1 :(得分:0)
尽量不重新绘制整个面板,只绘制将绘制正方形的区域,使用
repaint(int x, int y , int width , int height);
其中x和y是坐标,宽度和高度是你的方格的宽度和高度。
答案 2 :(得分:0)
您可以为每个BufferedImages提供一个目标变量。您将检查当前x位置是否大于或小于目标变量,并根据该值进行更改。您也可以使用y坐标执行此操作。
int x1 = 100;
int x2 = 100;
int xTarget1 = 200; // x target coordinate
int xTarget2 = 200;
// And so on, for as many BufferedImages
int xChange = 1;
// A loop, wherever it may be.
public void loop() {
if(x1 > xTarget1) {
x1 = x1 - xChange;
else if(x1 < xTarget1) {
x1 = x1 + xChange;
}
// Same for the other BufferedImages
}
然后你会画它。这应该可以创建更平滑的图像移动。除非您通过更改更改速度变量,否则它将是一个不变的移动。我希望这会有所帮助。