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.\n" + 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
java之数字彩虹雨的更多相关文章
- 原码,反码,补码,及Java中数字表示方法
原码:原码是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 如:如果是八位二进制1即用00000001表示,-1即用10000001表示. 反码:正数的反码就是其本身,负数的反码是在其 ...
- java 将数字转成成16进制
java 将数字转成成16进制 CreationTime--2018年6月11日17点11分 Author:Marydon 1.前提 数字必须是byte类型,即[-128,127] 2.代码实现 ...
- 实验三 Java猜数字游戏开发
课程:Java实验 班级:201352 姓名:程涵 学号:20135210 成绩: 指导教师:娄佳鹏 实验日期:15.06.03 实验密级: ...
- java大数字操作:BigInteger,BigDecimal(浮点型)
java大数字操作: BigInteger:大数字整型的 BigDecimal(浮点型):大数字小数的,也适用大的整数 BigInteger: String num1 = "10038182 ...
- 【Java】Java与数字证书
Java与数字证书 Java与数字证书 证书的签发和应用 证书的内容和意义 其它 证书(Certificate,也称public-key certificate)是用某种签名算法对某些内容(比如公钥) ...
- java的数字精确计算问题-BigDecimal
java的数字运算,偶尔会出现精度的问题,以下阐述的 java的BigDecimal类的使用. 例如: System.out.println(0.9+0.3); 结果1.2 System.out.pr ...
- Java中数字的格式化输出
Java中数字的格式化输出 double d = 345.678; String s = "hello!"; int i = 1234; //"%"表示进行格式 ...
- java 猜数字游戏
作用:猜数字游戏.随机产生1个数字(1~10),大了.小了或者成功后给出提示. 语言:java 工具:eclipse 作者:潇洒鸿图 时间:2016.11.10 >>>>> ...
- java猜数字游戏
import java.util.Scanner; //导入包 class GuessNum { public static void main(String[] args) { int num = ...
随机推荐
- RQNOJ PID217 / [NOIP1999]拦截导弹【n^2 / LIS】
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
- poj3264(Sparse-Table 算法模板)
poj3264 题意 询问区间最大值最小值之差. 分析 dp_max[i][j] 表示以 i 为起点,长度为 \(2^j\) 的区间最大值. 利用递推预处理出区间最大值最小值. code #inclu ...
- Controlled Tournament(状态压缩DP)
Controlled Tournament 题意 n 名选手进行淘汰赛,R[i][j] = 1 表示 i 能胜过 j.要求通过安排淘汰赛使得,m 选手获得最终胜利,问使得比赛数最少的方案数. 分析 设 ...
- HashSet、LinkedHashSet和TreeSet
关键技术: HashSet采用散列函数对元素进行排序,是专门为快速查询而设计的.存入HashSet的对象必须定义hashCode方法. TreeSet采用红黑树的数据结构进行排序元素,使用它可以从Se ...
- 五. 面向对象高级特性6. Java 泛型
我们知道,使用变量之前要定义,定义一个变量时必须要指明它的数据类型,什么样的数据类型赋给什么样的值. 假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数.小数和字符串,例如: x = 1 ...
- Java中使用HttpRequest调用RESTfull的DELETE方法接口提示:How to fix HTTP method DELETE doesn't support output
说明:无论是Spring框架还是Spring Boot的Feign形式的客户端,以下的解决方法都适用. 解决方法:直接升级JDK 1.8,这个问题是1.7的BUG. 参考: https://sales ...
- ostu进行遥感图像的分割
城市地区道路网的简单的阈值分割.采用的是单ostu(最佳阈值分割)算法,废话少说,如果不太清楚该算法,请参考文献[1]中的图像分割这一章的介绍.程序直接运行的效果如下.
- CM3大礼包
- Android控件之GridView探究
GridView是一项显示二维的viewgroup,可滚动的网格.一般用来显示多张图片. 以下模拟九宫图的实现,当鼠标点击图片时会进行相应的跳转链接. 目录结构 main.xml布局文件,存放Grid ...
- depth linear
float ConvertDepth( float depthFromTex, float4 cameraParams ){ const float near = cameraParams.z; co ...