多彩泡泡屏保特效(JAVA版)

原创
2016/12/09 12:22
阅读数 501
  • 一个多彩泡泡屏保特效(JS+CSS版) https://my.oschina.net/darkness/blog/360394 

    package screensaver;
    import java.awt.AlphaComposite;
    import java.awt.Composite;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    import com.abigdreamer.infinity.common.util.IntegerValue;
    import com.sun.awt.AWTUtilities;
    
    @SuppressWarnings("restriction")
    public class BubblesScreensaver {
    	// 常量
    	static int D = 222; // 泡泡直径
    	static double K = 0.999;
    
    	static double POW_RATE = 0.0001; // 补偿概率
    	static double POW_RANGE = 0.8; // 补偿范围(基于诞生速度)
    
    	public static double SPEED_X() {
    		return 8 + (RND() * 4);
    	}
    
    	public static double SPEED_Y() {
    		return 6 + (RND() * 2);
    	}
    
    	static List<Bubble> arrBubs = new ArrayList<>();
    
    	static double iBottom;
    	static double iRight;
    
    	public static double SQRT(double a) {
    		return Math.sqrt(a);
    	}
    
    	public static double RND() {
    		return Math.random();
    	}
    
    	static int clientWidth;
    	static int clientHeight;
    
    	public static void main(String[] args) {
    		JFrame frame = new JFrame();
    		frame.setAlwaysOnTop(true);
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.setUndecorated(true);
    		frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    		AWTUtilities.setWindowOpaque(frame, false);
    
    		final JPanel pane = new JPanel() {
    
    			private static final long serialVersionUID = 1L;
    
    			@Override
    			public void paint(Graphics g) {
    				super.paint(g);
    
    				Graphics2D g2d = (Graphics2D) g;
    
    				int n = arrBubs.size();
    
    				for (int j = 0; j < n; j++) {
    					Bubble bub = arrBubs.get(j);
    
    					float v;
    					g2d.translate(bub.x, bub.y);
    
    					g2d.drawImage(bub.images[3], 0, 0, null);
    
    					Composite old = g2d.getComposite();
    
    					for (int i = 0; i < 3; i++) {
    
    						v = (float) Math.abs(Math.sin(bub.kOpa[i] += bub.kStp[i] * Math.random()));
    						v *= bub.POW[i];
    
    						// v = ((v * 1e4) >> 0) / 1e4;
    
    						AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, v);
    						g2d.setComposite(alphaComposite);// 透明度
    
    						g2d.drawImage(bub.images[i], 0, 0, null);// 背景
    					}
    
    					g2d.setComposite(old);
    
    					g2d.translate(-bub.x, -bub.y);
    				}
    
    			}
    		};
    
    		pane.setOpaque(false);
    		frame.setContentPane(pane);
    		frame.setVisible(true);
    
    		clientHeight = frame.getHeight();
    		clientWidth = frame.getWidth();
    
    		int MAX = 5;
    
    		IntegerValue integerValue = new IntegerValue();
    
    		Timer timer1 = new Timer();
    		timer1.schedule(new TimerTask() {
    			public void run() {
    				if (integerValue.get() < MAX) {
    					integerValue.add();
    					CreateBubble(frame);
    				} else {
    					timer1.cancel();
    				}
    			}
    		}, 10, 1000);// delay=2000毫秒 后执行该任务
    
    		Timer timer = new Timer();
    		timer.schedule(new TimerTask() {
    			public void run() {
    				update();
    				pane.repaint();
    			}
    		}, 10, 17);// delay=2000毫秒 后执行该任务
    
    	}
    
    	public static void CreateBubble(JFrame frame) {
    		Bubble bub = new Bubble();
    
    		bub.setX(0);
    		bub.setY(0);
    		bub.vx = SPEED_X();
    		bub.vy = SPEED_Y();
    
    		arrBubs.add(bub);
    	};
    
    	public static void update() {
    		int n = arrBubs.size();
    		int i, j;
    
    		updateWall();
    
    		for (i = 0; i < n; i++) {
    			Bubble bub = arrBubs.get(i);
    
    			bub.vx *= K;
    			bub.vy *= K;
    
    			if (RND() < POW_RATE) {
    				bub.vx = SPEED_X() * (1 + RND() * POW_RANGE);
    				bub.vy = SPEED_Y() * (1 + RND() * POW_RANGE);
    			}
    
    			bub.setX(bub.x + bub.vx);
    			bub.setY(bub.y + bub.vy);
    
    			checkWalls(bub);
    		}
    
    		Bubble bub, bub2;
    		for (i = 0; i < n - 1; i++) {
    			bub = arrBubs.get(i);
    
    			for (j = i + 1; j < n; j++) {
    				bub2 = arrBubs.get(j);
    				checkCollision(bub, bub2);
    			}
    		}
    	}
    
    	public static void updateWall() {
    		iRight = clientWidth - D;
    		iBottom = clientHeight - D;
    	}
    
    	public static void checkWalls(Bubble bub) {
    		if (bub.x < 0) {
    			bub.setX(0);
    			bub.vx *= -1;
    		} else if (bub.x > iRight) {
    			bub.setX(iRight);
    			bub.vx *= -1;
    		}
    
    		if (bub.y < 0) {
    			bub.setY(0);
    			bub.vy *= -1;
    		} else if (bub.y > iBottom) {
    			bub.setY(iBottom);
    			bub.vy *= -1;
    		}
    	}
    
    	static class Position {
    		public double x;
    		public double y;
    
    		public Position(double x, double y) {
    			this.x = x;
    			this.y = y;
    		}
    	}
    
    	public static Position rotate(double x, double y, double sin, double cos, boolean reverse) {
    		if (reverse)
    			return new Position((x * cos + y * sin), (y * cos - x * sin));
    		else
    			return new Position((x * cos - y * sin), (y * cos + x * sin));
    	}
    
    	public static void checkCollision(Bubble bub0, Bubble bub1) {
    		double dx = bub1.x - bub0.x;
    		double dy = bub1.y - bub0.y;
    		double dist = SQRT(dx * dx + dy * dy);
    
    		if (dist < D) {
    			// 计算角度和正余弦值
    			double angle = Math.atan2(dy, dx);
    			double sin = Math.sin(angle);
    			double cos = Math.cos(angle);
    
    			// 旋转 bub0 的位置
    			Position pos0 = new Position(0, 0);
    
    			// 旋转 bub1 的速度
    			Position pos1 = rotate(dx, dy, sin, cos, true);
    
    			// 旋转 bub0 的速度
    			Position vel0 = rotate(bub0.vx, bub0.vy, sin, cos, true);
    
    			// 旋转 bub1 的速度
    			Position vel1 = rotate(bub1.vx, bub1.vy, sin, cos, true);
    
    			// 碰撞的作用力
    			double vxTotal = vel0.x - vel1.x;
    			vel0.x = vel1.x;
    			vel1.x = vxTotal + vel0.x;
    
    			// 更新位置
    			double absV = Math.abs(vel0.x) + Math.abs(vel1.x);
    			double overlap = D - Math.abs(pos0.x - pos1.x);
    
    			pos0.x += vel0.x / absV * overlap;
    			pos1.x += vel1.x / absV * overlap;
    
    			// 将位置旋转回来
    			Position pos0F = rotate(pos0.x, pos0.y, sin, cos, false);
    			Position pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
    
    			// 将位置调整为屏幕的实际位置
    			bub1.setX(bub0.x + pos1F.x);
    			bub1.setY(bub0.y + pos1F.y);
    			bub0.setX(bub0.x + pos0F.x);
    			bub0.setY(bub0.y + pos0F.y);
    
    			// 将速度旋转回来
    			Position vel0F = rotate(vel0.x, vel0.y, sin, cos, false);
    			Position vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
    
    			bub0.vx = vel0F.x;
    			bub0.vy = vel0F.y;
    			bub1.vx = vel1F.x;
    			bub1.vy = vel1F.y;
    		}
    	}
    
    }
    
    class Bubble {
    
    	static int D = 222; // 泡泡直径
    
    	double APLHA = 0.8;
    	double[] POW = new double[] { 1.0, APLHA, APLHA * APLHA };
    
    	double vx;
    	double vy;
    
    	double x;
    	double y;
    
    	double[] kOpa;
    	double[] kStp;
    
    	Image[] images = new Image[4];
    
    	public Bubble() {
    		double[] kOpa = new double[4];
    		double[] kStp = new double[4];
    
    		for (int i = 0; i < 4; i++) {
    			// 泡泡顶层
    			if (i == 3) {
    				ImageIcon imageIcon = new ImageIcon(getClass().getResource("heart.png"));
    				images[i] = imageIcon.getImage();
    
    			} else {
    				ImageIcon imageIcon = new ImageIcon(getClass().getResource("ch" + i + ".png"));
    				images[i] = imageIcon.getImage();
    			}
    
    			kOpa[i] = 3 * Math.random();
    			kStp[i] = 0.02 * Math.random();
    		}
    
    		this.kOpa = kOpa;
    		this.kStp = kStp;
    	}
    
    	public void setX(double x) {
    		this.x = x;
    	}
    
    	public void setY(double y) {
    		this.y = y;
    	}
    
    }
    

     

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部