Java的动画 [英] Java Animations
问题描述
我已经开始采取在Java制作动画(幻灯片,背景等)的兴趣。我知道,JavaFX是多少这样做的更好,但我只是顽固打扰切换。
I've started to take interest with making animations(slideshows, backgrounds etc) in Java. I know that JavaFX is much better for doing this, but I'm just to stubborn to bother switching over.
下面是我得到那么远。
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BlurredLightCells extends JPanel {
private static final long serialVersionUID = 4610174943257637060L;
private Random random = new Random();
private ArrayList<LightCell> lightcells;
private float[] blurData = new float[500];
public static void main(String[] args) {
JFrame frame = new JFrame("Swing animated bubbles");
frame.setSize(1000, 750);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BlurredLightCells(60));
frame.setVisible(true);
}
public BlurredLightCells(int amtOfBCells) {
setSize(1000, 750);
/**
* Below we initiate all the cells that are going to be drawn on screen
*/
Arrays.fill(blurData, 1f / 20f);
lightcells = new ArrayList<LightCell>(amtOfBCells);
for (int i = 0; i < amtOfBCells; i++) {
/**
* Below we generate all the values for each cell(SHOULD be random for each one)
*/
int baseSpeed = random(0, 3);
int xSpeed = (int) Math.floor((Math.random() * (baseSpeed - -baseSpeed + baseSpeed)) + -baseSpeed);
int ySpeed = (int) Math.round((Math.random() * baseSpeed) + 0.5);
int radius = random(25, 100);
int x = (int) Math.floor(Math.random() * getWidth());
int y = (int) Math.floor(Math.random() * getHeight());
int blurrAmount = (int) (Math.floor(Math.random() * 10) + 5);
int alpha = (int) ((Math.random() * 15) + 3);
/**
* Now we draw a image, and apply transparency and a slight blur to it
*/
Kernel kernel = new Kernel(blurrAmount, blurrAmount, blurData);
BufferedImageOp op = new ConvolveOp(kernel);
BufferedImage circle = new BufferedImage(150, 150, BufferedImage.TYPE_INT_ARGB);
Graphics2D circlegfx = circle.createGraphics();
circlegfx.setColor(new Color(255, 255, 255, alpha));
circlegfx.fillOval(20, 20, radius, radius);
circle = op.filter(circle, null);
LightCell bubble = new LightCell(x, y, xSpeed, ySpeed, radius, getDirection(random.nextInt(3)), circle);
lightcells.add(bubble);
}
}
public int random(int min, int max) {
final int n = Math.abs(max - min);
return Math.min(min, max) + (n == 0 ? 0 : random.nextInt(n));
}
@Override
public void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
final Graphics2D g2 = (Graphics2D) g;
GradientPaint gp = new GradientPaint(-w, -h, Color.LIGHT_GRAY, w, h, Color.DARK_GRAY);
g2.setPaint(gp);
g2.fillRect(0, 0, w, h);
long start = System.currentTimeMillis();
for (int i = 0; i < lightcells.size(); i++) {
LightCell cell = lightcells.get(i);
cell.process(g2);
}
System.out.println("Took " + (System.currentTimeMillis() - start) + " milliseconds to draw ALL cells.");
repaint();
}
public String getDirection(int i) {
switch (i) {
case 0:
return "right";
case 1:
return "left";
case 2:
return "up";
case 3:
return "down";
}
return "";
}
private class LightCell {
private int x, y, xSpeed, ySpeed, radius;
private String direction;
private BufferedImage image;
public LightCell(int x, int y, int xSpeed, int ySpeed, int radius, String direction, BufferedImage image) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.radius = radius;
this.direction = direction;
this.image = image;
}
public void process(Graphics g) {
switch (direction) {
case "right":
moveRight();
break;
case "left":
moveLeft();
break;
case "up":
moveUp();
break;
case "down":
moveDown();
break;
}
g.drawImage(image, x, y, null);
}
private void moveUp() {
x += xSpeed;
y -= ySpeed;
if (y + (radius / 2) < 0) {
y = getHeight() + (radius / 2);
x = (int) Math.floor(Math.random() * getWidth());
}
if ((x + radius / 2) < 0 || (x - radius / 2) > getWidth()) {
y = radius + (radius / 2);
x = (int) Math.floor(Math.random() * getWidth());
}
}
private void moveDown() {
x += xSpeed;
y += ySpeed;
if (y - (radius / 2) > getHeight()) {
y = 0 - (radius / 2);
x = (int) Math.floor(Math.random() * getWidth());
}
if ((x + radius / 2) < 0 || (x - radius / 2) > getWidth()) {
y = getHeight() + (radius / 2);
x = (int) Math.floor(Math.random() * getWidth());
}
}
private void moveRight() {
x += ySpeed;
y += xSpeed;
if (y - (radius / 2) > getHeight() || y + (radius / 2) < 0) {
x = 0 - (radius / 2);
y = (int) Math.floor(Math.random() * getHeight());
}
if ((x - radius / 2) > getWidth()) {
x = 0 - (radius / 2);
y = (int) Math.floor(Math.random() * getWidth());
}
}
private void moveLeft() {
x -= ySpeed;
y -= xSpeed;
if (y - (radius / 2) > getHeight() || y + (radius / 2) < 0) {
x = getWidth() + (radius / 2);
y = (int) Math.floor(Math.random() * getHeight());
}
if ((x + radius / 2) < 0) {
x = getWidth() + (radius / 2);
y = (int) Math.floor(Math.random() * getWidth());
}
}
}
}
如果您运行,你会看到电池的举动以非常高的速度,如果你看看通过code,你看我叫重绘()
在油漆
方法,其中我重写。我知道那并不好做。但我的问题是,是他们,我可以画重绘()
循环我现在外面每一个细胞的任何其他方式,因为这会导致其他部件闪烁/当我使用这与其他组件一个JFrame闪烁。
If you run that, you will see the cells move at a very high speed, and if you look through the code, you see I call repaint()
in the paint
method in which I override. I know thats not good to do. But my question is, is their any other way in which I could draw each cell outside of the repaint()
loop I have right now, because that causes other components to flash/flicker when I use this in a JFrame with other components.
FYI:Aventually我想实现类似于这样:<一href=\"http://activeden.net/item/background-animation-blurry-light-cells/21980?WT.ac=category_item&WT.seg_1=category_item&WT.z_author=ranfirefly\"相对=nofollow称号=点击我>点击这里
FYI: Aventually I'd like to achieve something similar to this: Click Here
谢谢!
推荐答案
<击>闪烁的问题是与事实顶层容器不是双缓冲的事。而不是从的JFrame
延伸(或其他顶层容器),你应该考虑使用更多的东西,比如的JPanel
并重写它的的paintComponent
。击>
The issue of flicker is to do with the fact that top level containers are not double buffered. Instead of extending from JFrame
(or other top level containers), you should consider using something more like JPanel
and override it's paintComponent
.
NB-在我的头上有它的OP从的JFrame
...
nb- Had it in my head that the OP was extending from JFrame
...
两个问题可能会造成闪烁。首先是覆盖油漆
,二是没有要求 super.paint(G)
和更新之间的时间。一个更好的解决办法是重写的paintComponent
,并确保您所呼叫 super.paintComponent方法
。也使用类似一个 javax.swing.Timer中的
计划更新和定期也将有助于...
Two issues could be causing the flickering. The first is overriding paint
, the second is not calling super.paint(g)
and the time between the updates. A better solution would be to override paintComponent
and make sure you are calling super.paintComponent
. Also using something like a javax.swing.Timer
to schedule updates and regular intervals would also help...
只能拨打重绘
当你想鼓励的RepaintManager
更新你的组件。不要叫重绘
任何 paintXxx
方法中,这将导致涂料的请求安排到无休止的循环事件队列,最终consuiming你的CPU
Only call repaint
when you want to encourage the RepaintManager
to update you component. Don't call repaint
from within any paintXxx
method, this will cause a never ending loop of paint requests to schedule onto the event queue, eventually consuiming your CPU
我会避免做你的 paintXxx
方法,任何可能需要一段时间才能完成,这会减慢渲染过程。相反,我会使用 javax.swing.Timer中的
简单的更新或更复杂的处理过程中,发
这可能在使用之前它呈现给屏幕更新模型
I would avoid doing anything in your paintXxx
methods that might take time to perform, this will slow down the rendering process. Instead, I would use a javax.swing.Timer
for simple updates or for more complicated processing, a Thread
which could be used to update the model before it is rendered to the screen.
这是一个<一个href=\"http://stackoverflow.com/questions/14886232/swing-animation-running-extremely-slow/14902184#14902184\">example一些简单的优化过程中我也拿500对象的动画,4500只在整体性能会有所沦落。
This is an example of some simple optimisation process I did to take animation of 500 objects to 4500 with only a slight degration in the overall performance.
更新
我改变了你code轻微并能正常工作...
I changed you code slight and it works fine...
我改变了你的油漆
方法的paintComponent
并添加 super.paintComponent方法(G)
I changed your paint
method to paintComponent
and added super.paintComponent(g)
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
final Graphics2D g2 = (Graphics2D) g;
GradientPaint gp = new GradientPaint(-w, -h, Color.LIGHT_GRAY, w, h, Color.DARK_GRAY);
g2.setPaint(gp);
g2.fillRect(0, 0, w, h);
for (int i = 0; i < lightcells.size(); i++) {
LightCell cell = lightcells.get(i);
cell.process(g2);
}
}
而在你的构造函数,我添加结束...
And at the end of your constructor I added...
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
要定期基地更新UI ...
To update the UI on a regular bases...
这篇关于Java的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!