Java Swing模拟水波纹扩散效果动画

基于Java语言模拟水波纹运动效果,分为两种方法,一种采用简单的叠加计算

不使用sine函数模拟水波纹,好处是计算量小,另外一种采用sine函数来计算

水波纹扩展,计算量大,但是效果比较真实。


第一种简单的叠加效果水波模拟,是很多简单的2D游戏中会用的,关键是计

算水波的迁移,然后剩以能量衰减因子。Java实现的代码如下:

for(y=1; y= Math.abs(-100))
		{
			n = n % Math.abs(-100);
		}*/
		waveMapData[next][y][x] = n;
		// System.out.print(" " + n);
	}
	// System.out.println();
}
解释:

主要是利用前两个水波的位置,计算出下一个将要出现的水波的位置,因此非常

重要的是保存前两个水波的迁移信息,然后实现波的叠加计算,在加上能量损失

因子,即可获得下个波的位置。

这种方法模拟出来的水波不是很圆,如果想得到那种很圆的水波效果,建议看

这里:http://blog.csdn.net/jia20003/article/details/13159535

解释完水波模拟的原理部分,下面来说说JAVA Swing的动画原理

主要是利用一个线程来计算水波的新位置,然后重新绘制图片,图片绘制好

以后调用repaint()方法,自动触发Swing重绘机制,实现刷新显示效果。

水波计算线程代码如下:

Thread animationThread = new Thread () {
    @Override
    public void run() {
    	int k = 0;
       while (true) {
    	  startWaterWave();
    	  // sinWaterRipple();
    	  updateText("水波开展:" + k);
          repaint();  // Refresh the display
          try {
             Thread.sleep(1000 / 30); // delay and yield to other threads
          } catch (InterruptedException ex) { }
          k++;
          if(k>=100){
        	  break;
          }
       }
    }
 };
 animationThread.start();
最后说一下Java的一个数据Copy的函数System.arraycopy,如果在多维数据中交

换数据你可能发现由于它是指针交换,交换完以后对新的数组赋值会同时跑到旧的

里面去。这个是我在debug程序的时候才发现。惭愧啊!程序效果如下:

Java Swing模拟水波纹扩散效果动画_第1张图片
UI加水波计算的完全源代码如下:

package com.gloomyfish.water.ripple.study;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import com.gloomyfish.filter.study.WaterFilter;

public class MyDemoUI extends JFrame implements ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3702707300863726479L;
	private BufferedImage textureImg = null;
	private BufferedImage resultImg = null;
	private int waveWidth = 40;
	private int waveHeight = 40;
	private int damp = 16;
	private int[][][] waveMapData;
	private int before = 0, current = 1, next = 2;
	private int x = 1, y = 1 /*n = 0*/;
	private WaterPixelRender imageRender;
	private WaterFilter filter;
	private JButton runBtn;
	private JLabel txtLabel;
	private boolean text = false;
	public MyDemoUI()
	{
		super("Water Ripple");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        getContentPane().setLayout(new BorderLayout());  
          
        // Display the window.  
        getContentPane().add(createWaterPanel(), BorderLayout.CENTER);  
        runBtn = new JButton("Run it");
        runBtn.addActionListener(this);
        
        txtLabel = new JLabel();
        txtLabel.setText("水纹:0");
        getContentPane().add(runBtn, BorderLayout.SOUTH);
        getContentPane().add(txtLabel, BorderLayout.NORTH);
        setPreferredSize(new Dimension(300 + 25,500));  
        pack();  
        setVisible(true);  
	}
	
	public void updateText(String textContent)
	{
		txtLabel.setText(textContent);
		this.invalidate();
	}

	private JPanel createWaterPanel() {
		try {
			File file = new File("D:\\resource\\flower_001.png");
			textureImg = ImageIO.read(file);
			resultImg = textureImg;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		imageRender = new WaterPixelRender();
		filter = new WaterFilter();
		JPanel wPanel = new JPanel()
		{
			protected void paintComponent(Graphics g) {
				Graphics2D g2 = (Graphics2D) g;
				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				if (resultImg != null) {
					g2.drawImage(resultImg, 0, 0, resultImg.getWidth(), resultImg.getHeight(), null);
				}
			}
		};
		return wPanel;
	}
	
	public void swapData()
	{
		for(int i=0; i=100){
		        	  break;
		          }
		       }
		    }
		 };
		 animationThread.start();
	}
    
	protected void sinWaterRipple() {
		resultImg = filter.filter(textureImg, null);
		filter.setRadius(filter.getRadius() + 5);
		if(filter.getRadius() > 150)
		{
			filter.setRadius(50);
		}
		float wl = filter.getWavelength();
		if(wl > 4)
		{
			wl = wl / 2;
		}
		else
		{
			wl = 32;
		}
		filter.setWavelength(wl);
	}

	protected void startWaterWave(/*int sx, int sy, Graphics2D g2*/) 
	{
		for(y=1; y= Math.abs(-100))
//				{
//					n = n % Math.abs(-100);
//				}
				waveMapData[next][y][x] = n;
				// System.out.print(" " + n);
			}
			// System.out.println();
		}
		// render image pixel and display water ripple at here
		imageRender.setWaveData(waveMapData[next]);
		resultImg = imageRender.filter(textureImg, null);
		// prepare for the next water ripple
		// Java System.arraycopy give very bad result due to reference issue!!!!
		// System.arraycopy(waveMapData[next], 0, waveMapData[current], 0, waveMapData[next].length);
		swapData();
	}

	public static void main(String[] args)
	{
		new MyDemoUI();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run(){
				simulateWaterRipple();		
			}
		});		
	}
}
绘制水波像素的生产新图片的代码如下:

package com.gloomyfish.water.ripple.study;

import java.awt.image.BufferedImage;

import com.gloomyfish.filter.study.AbstractBufferedImageOp;


public class WaterPixelRender extends AbstractBufferedImageOp {

	private int[][] waveData;
	private double rIndex = 2.0;
	private int counter = 0;
	public WaterPixelRender()
	{
		
	}
	
	public int[][] getWaveData() {
		return waveData;
	}
	public void setWaveData(int[][] waveData) {
		this.waveData = waveData;
	}
	@Override
	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
		counter++;
		int width = src.getWidth();
        int height = src.getHeight();

        if ( dest == null )
        	dest = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0;
        int nrow = 0, ncol = 0;
        for(int row=0; row= height)
            	{
            		nrow = 0;
            	}
            	if(ncol < 0 || ncol >= width)
            	{
            		ncol = 0;
            	}
            	
            	
        		index = nrow * width + ncol;
        		ta = (inPixels[index] >> 24) & 0xff;
                tr = (inPixels[index] >> 16) & 0xff;
                tg = (inPixels[index] >> 8) & 0xff;
                tb = inPixels[index] & 0xff;
                index = row * width + col;
                outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
        	}
        }
        setRGB( dest, 0, 0, width, height, outPixels );
        return dest;
	}
}
复制代码以后替换图片路径即可运行,转载请注明出处

你可能感兴趣的:(Java Swing模拟水波纹扩散效果动画)