2d 气泡特效

在这个例子里,我们会看到很多五颜六色的泡泡出现在屏幕上,逐渐变大然后消失,先来张截图看看效果

2d 气泡特效

 

效果还不错吧

 

程序的架构很简单,从JPanel继承并重写paintComponent,然后将其设置成JFrame的ContentPane即可

先来看看架构代码,具体的绘制代码稍后奉上

 

public class MyBubbles extends JPanel  {
	
	
	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub
		super.paintComponent(g);
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable(){
			@Override
			public void run() {
				JFrame frame=new JFrame();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setSize(400, 400);
				frame.setContentPane(new MyBubbles());
				frame.setLocationRelativeTo(null);
				frame.setVisible(true);
			}
		});
	}
}

 

 这些代码很简单,做过swing的童鞋应该毫无压力,需要注意的有两点:

1、setLocationRelativeTo方法可以很方便的将窗体居中

2、初始化窗体的代码是交给SwingUtilities来执行的,这涉及到swing的线程安全问题,这个话题很大,我在这就不赘述了,感兴趣的童鞋请猛戳这里:http://twaver.servasoft.com/?p=531

 

ok,我们开始思考怎样做成这种效果

首先气泡的个数和最大size都是固定的,代码如下:

 

 

Ellipse2D.Double[] ellipses;//气泡数组
int maxSize=60;//气泡最大像素
 

 

我们用椭圆来表示气泡,即Ellipse2D,Ellipse2D.Double是Ellipse2D的子类,它的坐标和大小都是double表示的,此外Ellipse2D还有个子类叫Ellipse2D.Float,顾名思义,它的坐标和大小用float来表示。

 

在构造方法中,我们初始化气泡数组

 

 

this.setBackground(Color.BLACK);//背景色
		ellipses=new Ellipse2D.Double[25];
		for(int i=0;i<ellipses.length;i++){
			ellipses[i]=new Ellipse2D.Double();
			double size=Math.random()*maxSize;
			this.setRandomXY(i, size, 400, 400);
		}
private void setRandomXY(int i,double size,double width,double height){
		double x=Math.random()*(width-maxSize/2);
		double y=Math.random()*(height-maxSize/2);
		ellipses[i].setFrame(x, y, size,size);
	}

 为了营造气泡大小不一的效果,我们使用随机数产生气泡size,为了实现代码重用,我们将设置气泡尺寸和位置的相关代码抽取到一个单独的方法中。

 

 

动画效果使用javax.swing.Timer实现(注意不是java.util.Timer),定时重绘气泡,改变气泡的尺寸。

在构造方法中创建一个Timer

 

timer=new Timer(30, this);
timer.start();

 为了简化代码,我们的MyBubbles实现了ActionListener接口,将自身交给timer调用。调用的代码很简单,只有一句话:repaint();

 

终于到了最关键的绘制部分了

 

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d=(Graphics2D)g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);   
		step(this.getWidth(),this.getHeight());
		render((Graphics2D)g);
	}
	private void step(double w,double h){
		for(int i=0;i<ellipses.length;i++){
			if(ellipses[i].width>maxSize){
				setRandomXY(i,1,w,h);
			}else{
				ellipses[i].setFrame(ellipses[i].getX(),ellipses[i].getY(), ellipses[i].getWidth()+1, ellipses[i].getHeight()+1);
			}
		}
	}
	private void render(Graphics2D g){
		for(int i=0;i<ellipses.length;i++){
			g.setColor(colors[i%colors.length]);
			g.setStroke(new BasicStroke(2));
			g.draw(ellipses[i]);
		}
	}

 paintComponent方法是我们重写JPanel的,每当Timer调用到repaint()时,这个方法也会马上被调用。

我们将改变气泡的尺寸的方法放到step中,将绘制方法放到render中,这样整个绘制过程看起来就很清晰了:

在step中,我们遍历气泡数组增大尺寸,当尺寸>maxSize时,就调用我们之前的setRandomXY方法重置气泡。

render方法中,遍历气泡设置颜色和画笔,并将气泡画到屏幕上。

我们在绘制的时候打开了反锯齿:g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

如果没有这句代码,画面会惨不忍睹,大家可以自行测试。  

 

完整的代码见附件。

参考:http://zetcode.com/tutorials/java2dtutorial/effects/

你可能感兴趣的:(特效)