• java之数字彩虹雨


    © 版权声明:本文为博主原创文章,转载请注明出处

    数字彩虹雨:

      从上至下,随机出现一串字符串,以不同的速度运行到底部;类似于黑客帝国里面的场景

    GitHub:https://github.com/TabooNight/BinaryRain

    实例:

    1.代码结构

    2.pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      
      	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>org.game.BinaryRain</groupId>
    	<artifactId>BinaryRain</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    	</properties>
    
    	<dependencies>
    		<!-- junit -->
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.12</version>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    </project>
    

    3.BinaryRain.properties

    foreground=default
    background=default
    width=default
    height=default
    characters=default
    colorful=true
    music=BinaryRainMusic.wav
    

    4.BinaryRain.java

    package org.game.BinaryRain;
    
    import java.applet.Applet;
    import java.applet.AudioClip;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Toolkit;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.Properties;
    
    import javax.swing.JDialog;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    
    /**
     * 数字彩虹雨
     *
     */
    public class BinaryRain extends JDialog {
    	
    	private static final long serialVersionUID = 1L;
    	
    	private Color foreground, background;// 前景色、背景色
    	private Dimension size;//Dimension类封装单个对象中组件的高度和宽度(精确到整数)
    	private char[] RAIN_CHARACTERS;// 字符数组
    	private boolean isColorful;// 颜色是否铺满
    	private boolean hasMusic;// 是否播放音乐
    	private AudioClip music;// 音频对象
    	private boolean isStart = false;// 是否开始
    	private RainPanel panel = new RainPanel();// RainPanel对象
    	private ArrayList<Rain> rains = new ArrayList<Rain>();
    	private Font rainFont = new Font("arial", Font.BOLD, 15);;// 创建文字雨的字体
    	
    	/**
    	 * 通过构造方法初始化
    	 */
    	private BinaryRain() {
    		
    		try {
    			initProperties();
    			init();
    		} catch (Exception e) {
    			JOptionPane.showMessageDialog(null, "Failed to init.
    " + e, 
    					"BinaryRain", JOptionPane.ERROR_MESSAGE);
    			System.exit(1);// 非正常退出
    		}
    		
    	}
    	
    	
    	/**
    	 * 读取配置文件并初始化
    	 * 
    	 * @throws Exception
    	 */
    	private void initProperties() throws Exception {
    		
    		Properties props = new Properties(); 
    		File file = new File(System.getProperty("user.dir") 
    				+ "/src/main/resources/BinaryRain.properties");// 获取配置文件
    		boolean dw = true, dh = true, df =true, db = true, dc = true, dcf = true;
    
    		if (file.exists() && file.isFile()) {
    			InputStream fis = new FileInputStream(file);// 创建文件输入流
    			props.load(fis);// 加载属性文件
    
    			// 获取前景色,默认default
    			String strFore = props.getProperty("foreground", "default").toLowerCase();
    			if (!"default".equals(strFore)) {
    				df = false;
    				foreground = getColor(strFore);// 获取颜色
    				if (foreground == null) {
    					foreground = Color.getColor(strFore, Color.GREEN);// 获取颜色对象,默认绿色
    				}
    			}
    			
    			// 获取背景色,默认default
    			String strBack = props.getProperty("background", "default").toLowerCase();
    			if (!"default".equals(strBack)) {
    				db = false;
    				background = getColor(strBack);// 获取颜色
    				if (background == null) {
    					background = Color.getColor(strBack, Color.GREEN);// 获取颜色对象,默认绿色
    				}
    			}
    			
    			// 获取宽度
    			size = new Dimension();
    			String strW = props.getProperty("width", "default").toLowerCase();
    			if (!"default".equals(strW)) {
    				dw = false;
    				size.width = Integer.valueOf(strW);
    			}
    			
    			// 获取高度
    			String strH = props.getProperty("height", "default").toLowerCase();
    			if (!"default".equals(strH)) {
    				dh = false;
    				size.width = Integer.valueOf(strH);
    			}
    			
    			// 获取字符数组
    			String strC = props.getProperty("characters", "default");
    			if (!"default".equalsIgnoreCase(strC)) {
    				dc = false;
    				String[] cs = strC.split(",");
    				RAIN_CHARACTERS = new char[cs.length];
    				for (int i = 0, s = RAIN_CHARACTERS.length; i < s; i++) {
    					RAIN_CHARACTERS[i] = cs[i].charAt(0);
    				}
    			}
    			
    			// 判断颜色是否铺满
    			String strCF = props.getProperty("colorful", "default");
    			if (!"default".equalsIgnoreCase(strCF)) {
    				dcf = false;
    				isColorful = Boolean.valueOf(strCF);
    			}
    			
    			// 判断是否播放音乐
    			String strM = props.getProperty("music", "default");
    			if (!"default".equalsIgnoreCase(strM)) {
    				File musicFile = new File(System.getProperty("user.dir") 
    						+ "/src/main/resources/" + strM);
    				if (musicFile.exists() && musicFile.isFile()) {
    					if ((music = Applet.newAudioClip(musicFile.toURI().toURL())) != null) {
    						hasMusic = true;
    					}
    				}
    			}
    			
    			fis.close();
    			
    		}
    		
    		if (dw & dh) {// 高度和宽度都是default,获取屏幕高和宽
    			size = Toolkit.getDefaultToolkit().getScreenSize();
    		} else if (dw) {// 宽度是default,获取屏幕宽度
    			size.width = Toolkit.getDefaultToolkit().getScreenSize().width;
    		} else if (dh) {// 高度是default,获取屏幕高度
    			size.height = Toolkit.getDefaultToolkit().getScreenSize().height;
    		}
    		
    		if (df) {// 前景色是default
    			foreground = Color.GREEN;
    		}
    		
    		if (db) {// 背景色是default
    			background = Color.BLACK;
    		}
    		
    		if (dc) {// 字符数组是的default
    			RAIN_CHARACTERS = new char[126 - 33 + 1];
    			for (int c = 0, i = 33, l = RAIN_CHARACTERS.length; c < l; c++, i++) {
    				RAIN_CHARACTERS[c] = (char) i;
    			}
    		}
    		
    		if (dcf) {// 颜色铺满是default
    			isColorful = false;
    		}
    		
    	}
    	
    	/**
    	 * 根据字符串获取其对应的颜色
    	 * 
    	 * @param color
    	 * 				颜色
    	 * @return
    	 */
    	private Color getColor(String color) {
    		
    		if (color == null || color.isEmpty()) {
    			return null;
    		}
    		if (color.startsWith("#")) {
    			int i = Integer.valueOf(color.substring(1), 16);
    			return new Color(i);
    		}
    		// [\d]:数字		[\p{Blank}]:空格或制表符
    		if (color.matches("[\d]+[\p{Blank}]*,[\p{Blank}]*[\d]+[\p{Blank}]*,[\p{Blank}]*[\d]+")) {
    			String[] cs = color.split("[\p{Blank}]*,[\p{Blank}]");
    			if (cs.length != 3) {
    				return null;
    			}
    			int r = Integer.valueOf(cs[0]);
    			int g = Integer.valueOf(cs[1]);
    			int b = Integer.valueOf(cs[2]);
    			return new Color(r, g, b);
    		}
    		return null;
    		
    	}
    	
    	/**
    	 * 初始化窗口
    	 */
    	private void init() {
    		
    		setAlwaysOnTop(true);// 设置窗口靠前
    		setResizable(false);// 不能改变大小
    		setUndecorated(true);// 设置此frame窗口失去边框和标题栏的修饰(必须在setVisible之前)
    		setTitle("Binary Rain");// 设置标题
    		// 创建一个BufferedImage对象
    		BufferedImage cursor = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB_PRE);
    		setCursor(Toolkit.getDefaultToolkit().createCustomCursor(cursor, 
    				new Point(8, 8), "Disable Cursor"));// 确认光标的形状
    		setSize(size);// 设置窗口大小
    		setLocationRelativeTo(null);// 设置窗口相对于指定组件的位置,null表示位于屏幕的中央
    		
    		addKeyListener(new KeyAdapter() {// 新增一个按键侦听器
    			@Override
    			public void keyPressed(KeyEvent e) {
    				if ((e.isAltDown() && e.getKeyCode() == KeyEvent.VK_F4) 
    						|| (e.getKeyCode() == KeyEvent.VK_ESCAPE)) {// 按下Alt+F4或者Esc键
    					setVisible(false);// 设置窗口不可见
    					System.exit(0);// 正常停止程序
    				}
    			}
    		});
    		
    		addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosing(WindowEvent e) {
    				if (isRaining()) {
    					stop();
    				}
    				System.exit(0);// 正常停止程序
    			}
    		});
    		
    		add(panel, BorderLayout.CENTER);// 将指定组件添加到此容器
    		
    	}
    	
    	/**
    	 * 重写setVisible方法,当不显示时停止创建文字雨
    	 */
    	public void setVisible(boolean flag) {
    		
    		super.setVisible(flag);
    		if (!flag) {
    			stop();
    		}
    		
    	}
    	
    	/**
    	 * 是否开始创建文字雨
    	 * 
    	 * @return
    	 */
    	public boolean isRaining() {
    		
    		return isStart;
    		
    	}
    	
    	/**
    	 * 停止文字雨
    	 */
    	public void stop() {
    		
    		isStart = false;// 开始标识置为false
    		if (hasMusic) {// 播放音乐
    			music.stop();// 停止播放音乐
    		}
    		
    	}
    	
    	/**
    	 * 开始一个新的线程,创建一条文字雨,使用synchronized保证一个时间内只有一条线程可以执行
    	 */
    	private synchronized void newRain() {
    		
    		Rain r = new Rain(getRandomLength(), (int) (Math.random() * size.width), 
    				(int) (Math.random() * -60 * 15), (int) (Math.random() * 8 + 2), 
    				(float) (Math.random() * 10 + 10));
    		rains.add(r);
    		new Thread(r).start();
    		
    	}
    	
    	/**
    	 * 获取随机长度(10-50)
    	 * 
    	 * @return
    	 */
    	public int getRandomLength() {
    		
    		return (int) (Math.random() * 40 + 10);
    		
    	}
    	
    	/**
    	 * 获取随机字符串
    	 * 
    	 * @return
    	 */
    	public String getRandomChar() {
    		
    		return String.valueOf(RAIN_CHARACTERS[(int) (Math.random() * RAIN_CHARACTERS.length)]);
    		
    	}
    	
    	/**
    	 * 获取面板大小
    	 * 
    	 * @return
    	 */
    	public Dimension getFrameSize() {
    		
    		return size;
    		
    	}
    	
    	public void start() {
    		
    		if (hasMusic) {// 播放音乐
    			music.loop();// 循环播放
    		}
    		
    		for (int c = 0, s = 108; c < s; c++) {// 创建108条文字雨
    			newRain();
    		}
    		
    		isStart = true;
    		
    		for (Rain r: rains) {
    			new Thread(r).start();
    		}
    		
    		new Thread(new Runnable() {
    			
    			public void run() {
    			
    				while (isStart) {
    					panel.repaint();
    				}
    				
    			}
    		}).start();
    		
    	}
    	
    	/**
    	 * 创建文字雨面板
    	 *
    	 */
    	private final class RainPanel extends JPanel {
    		
    		private static final long serialVersionUID = 1L;
    
    		public RainPanel() {
    			
    		}
    
    		private final Color[] COLORS = new Color[] {// 文字雨文本颜色集合
    			new Color(255, 0, 0),
                new Color(255, 165, 0),
                new Color(255, 255, 0),
                new Color(0, 255, 0),
                new Color(0, 127, 0),
                new Color(0, 127, 255),
                new Color(139, 0, 255)
            };
    
    		@Override
    		public void paint(Graphics g) {
    			
    			if (isStart) {
    				BufferedImage img = new BufferedImage(size.width, size.height, 
    						BufferedImage.TYPE_INT_RGB);// 创建一个BufferedImage对象
    				Graphics2D g2 = (Graphics2D) img.getGraphics();// 获取Graphics2D对象
    				g2.setColor(background);// 设置颜色
    				g2.fillRect(0, 0, size.width, size.height);// 用预定的颜色填充一个矩形
    				g2.setColor(foreground);// 设置颜色
    				// 克隆所有文字雨信息到Collection中
    				@SuppressWarnings("unchecked")
    				Collection<Rain> collection = (Collection<Rain>) rains.clone();
    				for (Iterator<Rain> it = collection.iterator(); it.hasNext();) {
    					Rain r = it.next();
    					if (r.isEnd()) {// 该条文字雨已经结束
    						rains.remove(r);// 将该条文字雨从集合中移除
    						newRain();// 创建一条新的文字雨
    						continue;
    					}
    					if (isColorful) {// 颜色铺满
    						g2.setFont(rainFont.deriveFont(r.getSize()));// 设置文字雨文本大小
    						String[] ss = r.getRainChars();// 获取文字雨文本内容
    						int x = r.getX();// 获取文字雨X轴坐标
    						int y = r.getY() - ss.length * 15;// 获取文字雨Y轴坐标
    						for (int i = 0, sl = ss.length; i < sl; i++) {
    							if (i < 7) {
    								g2.setColor(COLORS[i]);
    							} else {
    								g2.setColor(COLORS[i % 7]);
    							}
    							g2.drawString(ss[i], x, y);
    							y += 15;
    						}
    					} else {
    						g2.setFont(rainFont.deriveFont(r.getSize()));// 设置文字雨文本大小
    						String[] ss = r.getRainChars();// 获取文字雨文本内容
    						int x = r.getX();// 获取文字雨X轴坐标
    						int y = r.getY() - ss.length * 15;// 获取文字雨Y轴坐标
    						for (String s: ss) {
    							g2.drawString(s, x, y);
    							y += 15;
    						}
    					}
    				}
    				g.drawImage(img, 0, 0, this);// 绘制指定图像
    			}
    			
    		}
    		
    	}
    	
    	/**
    	 * 通过线程创建一条条文字雨
    	 *
    	 */
    	private final class Rain implements Runnable {
    		
    		private int rainSpeed;// 下雨的速度
    		private final String[] rainChars;// 下雨的文本
    		private int rainX, rainY;// 文本坐标系
    		private float fontSize;// 文本大小
    
    		/**
    		 * 初始化一条文字雨
    		 * 
    		 * @param length
    		 * 					文字雨的文本长度
    		 * @param x
    		 * 					x坐标
    		 * @param y
    		 * 					y坐标
    		 * @param speed
    		 * 					下雨速度
    		 * @param size
    		 * 					文本大小
    		 */
    		public Rain(int length, int x, int y, int speed, float size) {
    			
    			if (speed < 1) {
    				throw new RuntimeException("The speed must be greater than or equal to 1.");
    			}
    			
    			if (length < 5) {
    				length = getRandomLength();
    			}
    			
    			if (size < 1.0f) {
    				size = 15.0f;
    			}
    			
    			rainChars = new String[length + 1];
    			for (int i = 0; i < length; i++) {
    				rainChars[i] = getRandomChar();
    			}
    			rainChars[length] = " ";
    			this.rainX = x;
    			this.rainY = y;
    			this.rainSpeed = speed;
    			this.fontSize = size;
    			
    		}
    
    		/**
    		 * 执行文字雨
    		 */
    		public void run() {
    			
    			while (isRaining() && rainY < getFrameSize().height + (rainChars.length + 1) * 15) {
    				if (rainSpeed <= 0) {// 文字雨的速度小于等于0,结束
    					break;
    				}
    				try {
    					Thread.sleep(rainSpeed);// 睡眠
    				} catch (InterruptedException ex) {
    					ex.printStackTrace();
    				}
    				rainY += 2;// 每次向下运动2
    			}
    			rainSpeed = -1;// 文字雨结束,速度置为-1
    			
    		}
    		
    		/**
    		 * 获取文本内容
    		 * 
    		 * @return
    		 */
    		public String[] getRainChars() {
    			
    			return rainChars;
    			
    		}
    		
    		/**
    		 * 获取文字雨X轴坐标
    		 * 
    		 * @return
    		 */
    		public int getX() {
    			
    			return rainX;
    			
    		}
    		
    		/**
    		 * 获取文字雨Y轴坐标
    		 * 
    		 * @return
    		 */
    		public int getY() {
    			
    			return rainY;
    			
    		}
    		
    		/**
    		 * 获取文字雨文本大小
    		 * 
    		 * @return
    		 */
    		public float getSize() {
    			
    			return fontSize;
    			
    		}
    		
    		/**
    		 * 判断文字雨是否结束
    		 * 
    		 * @return
    		 */
    		public boolean isEnd() {
    			
    			return rainSpeed <= 0;
    			
    		}
    		
    	}
    	
    	public static void main(String[] args) {
    		
    		BinaryRain rain = new BinaryRain();
    		rain.setVisible(true);
    		rain.start();
    		
    	}
    	
    }
    

    5.效果预览

    参考:http://blog.csdn.net/simon_world/article/details/41791277

  • 相关阅读:
    vue 按需加载
    需要打印真实尺寸大小等需求的,css的单位可以使用mm等做单位
    d3 比例尺
    d3 根据数据绘制svg
    d3 svg简单学习
    d3 使用随机数据生成条形图
    d3 画简单的柱形图
    d3 使用数据
    d3 数据绑定
    d3 添加元素相关api
  • 原文地址:https://www.cnblogs.com/jinjiyese153/p/7122281.html
Copyright © 2020-2023  润新知