Gip*_*ing 4 java animation swing jpanel
我有一个难题,如何实现应用。我的 JPanel 宽度为 288,高度为 512,然后我创建了两个对象(图像)并使用坐标通过 PaintComponent 绘制它们
\n\n drawImage (Image1,288,128,this) ;\n drawImage (Image2, 288, 384, this);\nRun Code Online (Sandbox Code Playgroud)\n\n。它们在 X 轴上同时递减,当达到 x = 144 时,应在坐标 \xe2\x80\x98( x = 288 , y = (int)Math.random()* 512 处绘制新的(相同)图像)\xe2\x80\x99 并开始递减,并且第一个应该仍然递减。而这个过程应该是永无止境的。每个达到 x = 144 的新对象都应该构建新的对象。我尝试创建 ArrayList 并在其中添加坐标
\n\nArrayList arrayX = new ArrayList(); \narrayX.add(288)\narrayY.add((int) Math.random()* 512 )\nRun Code Online (Sandbox Code Playgroud)\n\n然后通过提取值
\n\narray.get()\nRun Code Online (Sandbox Code Playgroud)\n\n但那没有成功。\n我看到有人通过数组使用 JavaScript 完成此操作的视频
\n\nvar position = []\nposition = ({\nX : 288\nY : 256\n })\nRun Code Online (Sandbox Code Playgroud)\n\n然后通过这样的循环实现
\n\n function draw() {\n\n for (int i = 0; i < position.length; i++ ){\n cvs.drawImage(Image1,position[i].x , position[i].y)\n cvs.drawImage(Image2,position[i].x , position[i].y + 50)\n\n position [i] .x - -;\n if(position[i].x == 128)\n position.push({\n X : 288\n Y : Math.floor(Math.random()*512 })\n })\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n\n我不知道如何在 Java 中执行此操作。\n也许我也应该使用数组来保存带有坐标的变量,或者数组列表,但以不同的方式。请帮帮我 。\n提前致谢
\n从概念上讲,这个想法很简单,问题是,Swing 是信号线程,而不是线程安全的。
有关更多详细信息,请参阅Swing 中的并发性。
这意味着您可以在事件调度线程内运行长时间运行或阻塞操作(如永无休止的循环),但您也不应该从 EDT 上下文外部更新 UI(或 UI 所依赖的属性)。
虽然该问题有多种可能的解决方案,但最简单的可能是使用 Swing Timer,它提供了一种安全地安排延迟的方法(不会阻止 EDT),并且会在EDT,允许您从其中更新 UI。
有关更多详细信息,请参阅如何使用 Swing 计时器。
现在,因为您使用的是面向对象语言,所以您应该利用它提供的功能,对我来说,这意味着封装。
你有一个图像,你想在特定的位置绘制,但是它的位置会根据一些规则而改变,这只是简单的Java Old (POJO)
通常,我会从 a 开始interface描述基本属性和操作,但为了简洁起见,我直接跳到了一堂课......
public class Drawable {
private int x, y;
private Color color;
public Drawable(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public void update() {
x--;
if (x <= 144) {
reset();
}
}
protected void reset() {
x = 288;
y = (int) (Math.random() * (512 - 20));
}
public void paint(Graphics2D g2d) {
Graphics2D copy = (Graphics2D) g2d.create();
copy.translate(getX(), getY());
copy.setColor(getColor());
copy.drawOval(0, 0, 20, 20);
copy.dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
但是等等,你说,它正在使用Color而不是图像!?是的,我手头没有任何小图片,此外,我需要给你留点事做;)
现在,动画是重复更新和绘制的序列,直到达到所需状态。
在这种情况下,您不太关心最终状态,因此您可以让它继续运行。
“更新”周期由 Swing 处理Timer,它循环遍历List对象Drawable,调用它们的update方法,然后调度 a repaint,它触发对象被绘制的JPanels ,简单......paintComponentDrawable
public class TestPane extends JPanel {
private List<Drawable> drawables;
public TestPane() {
drawables = new ArrayList<>(2);
drawables.add(new Drawable(288, 128, Color.RED));
drawables.add(new Drawable(288, 384, Color.RED));
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (Drawable drawable : drawables) {
drawable.update();
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(288, 512);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drawable drawable : drawables) {
Graphics2D g2d = (Graphics2D) g.create();
drawable.paint(g2d);
g2d.dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
import java.awt.Color;
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.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Drawable {
private int x, y;
private Color color;
public Drawable(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public void update() {
x--;
if (x <= 144) {
reset();
}
}
protected void reset() {
x = 288;
y = (int) (Math.random() * (512 - 20));
}
public void paint(Graphics2D g2d) {
Graphics2D copy = (Graphics2D) g2d.create();
copy.translate(getX(), getY());
copy.setColor(getColor());
copy.drawOval(0, 0, 20, 20);
copy.dispose();
}
}
public class TestPane extends JPanel {
private List<Drawable> drawables;
public TestPane() {
drawables = new ArrayList<>(2);
drawables.add(new Drawable(288, 128, Color.RED));
drawables.add(new Drawable(288, 384, Color.RED));
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (Drawable drawable : drawables) {
drawable.update();
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(288, 512);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drawable drawable : drawables) {
Graphics2D g2d = (Graphics2D) g.create();
drawable.paint(g2d);
g2d.dispose();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
“有没有更简单的解决方案”?是的,当然,我总是先用最难的方法来解决问题。首先,好的动画很难。严重地。我已经研究这个东西近20年了,制作一个优秀的动画引擎,能够灵活地满足它可能遇到的所有可能的需求,这几乎是不可能的任务,特别是在一个没有真正设计的框架中为了它。
如果你不相信我,你可以看看
这只是动画有多复杂的几个例子
抱歉,当谈到动画时,你会惊讶地发现我经常被问到“可以更简单吗”;)
“每个达到 x = 144 的新物体都应该构建新的物体
所以,显然我可能对这一点感到困惑。如果这意味着“达到 144 后添加新对象”,那么这会引发一些新问题。主要问题是 GC 开销,这会导致动画速度减慢。当然,我们只处理大约 4-6 个对象,但如果你不小心,它就是其中之一。
所以我就拿上面的例子,对更新周期做了一些修改。这增加了reusePool旧对象的放置位置并可以重复使用,从而减少了重复创建和销毁短命对象的 GC 开销。
只是decaying List确保一旦对象通过了swanPoint,就不会考虑重新生成新对象。当然,您可以在 POJO 本身上放置一个标志,但我不认为这是 POJO 责任的一部分
public TestPane() {
drawables = new ArrayList<>(2);
reusePool = new ArrayList<>(2);
decaying = new ArrayList<>(2);
timer = new Timer(5, new ActionListener() {
private List<Drawable> spawned = new ArrayList<>(5);
@Override
public void actionPerformed(ActionEvent e) {
spawned.clear();
Iterator<Drawable> it = drawables.iterator();
int swapnPoint = getWidth() / 2;
while (it.hasNext()) {
Drawable drawable = it.next();
drawable.update();
if (drawable.getX() > 0 && drawable.getX() < swapnPoint) {
if (!decaying.contains(drawable)) {
decaying.add(drawable);
Drawable newDrawable = null;
if (reusePool.isEmpty()) {
newDrawable = new Drawable(
getWidth() - 20,
randomVerticalPosition(),
randomColor());
} else {
newDrawable = reusePool.remove(0);
newDrawable.reset(getWidth() - 20,
randomVerticalPosition(),
randomColor());
}
spawned.add(newDrawable);
}
} else if (drawable.getX() <= -20) {
System.out.println("Pop");
it.remove();
decaying.remove(drawable);
reusePool.add(drawable);
}
}
drawables.addAll(spawned);
repaint();
}
});
}
Run Code Online (Sandbox Code Playgroud)
现在,这将允许对象在整个宽度上行进,并在经过中点时生成新对象。一旦它们超出视图的可视范围,它们将被放置到视图中,reuse List以便在需要新对象时可以再次重用它们。
import java.awt.Color;
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.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
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();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
testPane.start();
}
});
}
});
}
public class Drawable {
private int x, y;
private Color color;
public Drawable(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public void update() {
x--;
}
protected void reset(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void paint(Graphics2D g2d) {
Graphics2D copy = (Graphics2D) g2d.create();
copy.translate(getX(), getY());
copy.setColor(getColor());
copy.fillOval(0, 0, 20, 20);
copy.setColor(Color.BLACK);
copy.drawOval(0, 0, 20, 20);
copy.dispose();
}
}
public class TestPane extends JPanel {
private List<Drawable> drawables;
private List<Drawable> decaying;
private List<Drawable> reusePool;
private Color[] colors = new Color[]{Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW};
private Random rnd = new Random();
private Timer timer;
public TestPane() {
drawables = new ArrayList<>(2);
reusePool = new ArrayList<>(2);
decaying = new ArrayList<>(2);
timer = new Timer(40, new ActionListener() {
private List<Drawable> spawned = new ArrayList<>(5);
@Override
public void actionPerformed(ActionEvent e) {
spawned.clear();
Iterator<Drawable> it = drawables.iterator();
int swapnPoint = getWidth() / 2;
while (it.hasNext()) {
Drawable drawable = it.next();
drawable.update();
if (drawable.getX() > 0 && drawable.getX() < swapnPoint) {
if (!decaying.contains(drawable)) {
decaying.add(drawable);
Drawable newDrawable = null;
if (reusePool.isEmpty()) {
System.out.println("New");
newDrawable = new Drawable(
getWidth() - 20,
randomVerticalPosition(),
randomColor());
} else {
System.out.println("Reuse");
newDrawable = reusePool.remove(0);
newDrawable.reset(getWidth() - 20,
randomVerticalPosition(),
randomColor());
}
spawned.add(newDrawable);
}
} else if (drawable.getX() <= -20) {
System.out.println("Pop");
it.remove();
decaying.remove(drawable);
reusePool.add(drawable);
}
}
drawables.addAll(spawned);
repaint();
}
});
}
public void start() {
drawables.add(new Drawable(getWidth(), 128, randomColor()));
drawables.add(new Drawable(getWidth(), 384, randomColor()));
timer.start();
}
protected int randomVerticalPosition() {
return rnd.nextInt(getHeight() - 20);
}
protected Color randomColor() {
return colors[rnd.nextInt(colors.length - 1)];
}
@Override
public Dimension getPreferredSize() {
return new Dimension(288, 512);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drawable drawable : drawables) {
Graphics2D g2d = (Graphics2D) g.create();
drawable.paint(g2d);
g2d.dispose();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
637 次 |
| 最近记录: |