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

数字彩虹雨:

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

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

实例:

1.代码结构

2.pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3.  
  4. <modelVersion>4.0.0</modelVersion>
  5.  
  6. <groupId>org.game.BinaryRain</groupId>
  7. <artifactId>BinaryRain</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <packaging>jar</packaging>
  10.  
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. </properties>
  14.  
  15. <dependencies>
  16. <!-- junit -->
  17. <dependency>
  18. <groupId>junit</groupId>
  19. <artifactId>junit</artifactId>
  20. <version>4.12</version>
  21. <scope>test</scope>
  22. </dependency>
  23. </dependencies>
  24. </project>

3.BinaryRain.properties

  1. foreground=default
  2. background=default
  3. width=default
  4. height=default
  5. characters=default
  6. colorful=true
  7. music=BinaryRainMusic.wav

4.BinaryRain.java

  1. package org.game.BinaryRain;
  2.  
  3. import java.applet.Applet;
  4. import java.applet.AudioClip;
  5. import java.awt.BorderLayout;
  6. import java.awt.Color;
  7. import java.awt.Dimension;
  8. import java.awt.Font;
  9. import java.awt.Graphics;
  10. import java.awt.Graphics2D;
  11. import java.awt.Point;
  12. import java.awt.Toolkit;
  13. import java.awt.event.KeyAdapter;
  14. import java.awt.event.KeyEvent;
  15. import java.awt.event.WindowAdapter;
  16. import java.awt.event.WindowEvent;
  17. import java.awt.image.BufferedImage;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.InputStream;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Iterator;
  24. import java.util.Properties;
  25.  
  26. import javax.swing.JDialog;
  27. import javax.swing.JOptionPane;
  28. import javax.swing.JPanel;
  29.  
  30. /**
  31. * 数字彩虹雨
  32. *
  33. */
  34. public class BinaryRain extends JDialog {
  35.  
  36. private static final long serialVersionUID = 1L;
  37.  
  38. private Color foreground, background;// 前景色、背景色
  39. private Dimension size;//Dimension类封装单个对象中组件的高度和宽度(精确到整数)
  40. private char[] RAIN_CHARACTERS;// 字符数组
  41. private boolean isColorful;// 颜色是否铺满
  42. private boolean hasMusic;// 是否播放音乐
  43. private AudioClip music;// 音频对象
  44. private boolean isStart = false;// 是否开始
  45. private RainPanel panel = new RainPanel();// RainPanel对象
  46. private ArrayList<Rain> rains = new ArrayList<Rain>();
  47. private Font rainFont = new Font("arial", Font.BOLD, 15);;// 创建文字雨的字体
  48.  
  49. /**
  50. * 通过构造方法初始化
  51. */
  52. private BinaryRain() {
  53.  
  54. try {
  55. initProperties();
  56. init();
  57. } catch (Exception e) {
  58. JOptionPane.showMessageDialog(null, "Failed to init.\n" + e,
  59. "BinaryRain", JOptionPane.ERROR_MESSAGE);
  60. System.exit(1);// 非正常退出
  61. }
  62.  
  63. }
  64.  
  65. /**
  66. * 读取配置文件并初始化
  67. *
  68. * @throws Exception
  69. */
  70. private void initProperties() throws Exception {
  71.  
  72. Properties props = new Properties();
  73. File file = new File(System.getProperty("user.dir")
  74. + "/src/main/resources/BinaryRain.properties");// 获取配置文件
  75. boolean dw = true, dh = true, df =true, db = true, dc = true, dcf = true;
  76.  
  77. if (file.exists() && file.isFile()) {
  78. InputStream fis = new FileInputStream(file);// 创建文件输入流
  79. props.load(fis);// 加载属性文件
  80.  
  81. // 获取前景色,默认default
  82. String strFore = props.getProperty("foreground", "default").toLowerCase();
  83. if (!"default".equals(strFore)) {
  84. df = false;
  85. foreground = getColor(strFore);// 获取颜色
  86. if (foreground == null) {
  87. foreground = Color.getColor(strFore, Color.GREEN);// 获取颜色对象,默认绿色
  88. }
  89. }
  90.  
  91. // 获取背景色,默认default
  92. String strBack = props.getProperty("background", "default").toLowerCase();
  93. if (!"default".equals(strBack)) {
  94. db = false;
  95. background = getColor(strBack);// 获取颜色
  96. if (background == null) {
  97. background = Color.getColor(strBack, Color.GREEN);// 获取颜色对象,默认绿色
  98. }
  99. }
  100.  
  101. // 获取宽度
  102. size = new Dimension();
  103. String strW = props.getProperty("width", "default").toLowerCase();
  104. if (!"default".equals(strW)) {
  105. dw = false;
  106. size.width = Integer.valueOf(strW);
  107. }
  108.  
  109. // 获取高度
  110. String strH = props.getProperty("height", "default").toLowerCase();
  111. if (!"default".equals(strH)) {
  112. dh = false;
  113. size.width = Integer.valueOf(strH);
  114. }
  115.  
  116. // 获取字符数组
  117. String strC = props.getProperty("characters", "default");
  118. if (!"default".equalsIgnoreCase(strC)) {
  119. dc = false;
  120. String[] cs = strC.split(",");
  121. RAIN_CHARACTERS = new char[cs.length];
  122. for (int i = 0, s = RAIN_CHARACTERS.length; i < s; i++) {
  123. RAIN_CHARACTERS[i] = cs[i].charAt(0);
  124. }
  125. }
  126.  
  127. // 判断颜色是否铺满
  128. String strCF = props.getProperty("colorful", "default");
  129. if (!"default".equalsIgnoreCase(strCF)) {
  130. dcf = false;
  131. isColorful = Boolean.valueOf(strCF);
  132. }
  133.  
  134. // 判断是否播放音乐
  135. String strM = props.getProperty("music", "default");
  136. if (!"default".equalsIgnoreCase(strM)) {
  137. File musicFile = new File(System.getProperty("user.dir")
  138. + "/src/main/resources/" + strM);
  139. if (musicFile.exists() && musicFile.isFile()) {
  140. if ((music = Applet.newAudioClip(musicFile.toURI().toURL())) != null) {
  141. hasMusic = true;
  142. }
  143. }
  144. }
  145.  
  146. fis.close();
  147.  
  148. }
  149.  
  150. if (dw & dh) {// 高度和宽度都是default,获取屏幕高和宽
  151. size = Toolkit.getDefaultToolkit().getScreenSize();
  152. } else if (dw) {// 宽度是default,获取屏幕宽度
  153. size.width = Toolkit.getDefaultToolkit().getScreenSize().width;
  154. } else if (dh) {// 高度是default,获取屏幕高度
  155. size.height = Toolkit.getDefaultToolkit().getScreenSize().height;
  156. }
  157.  
  158. if (df) {// 前景色是default
  159. foreground = Color.GREEN;
  160. }
  161.  
  162. if (db) {// 背景色是default
  163. background = Color.BLACK;
  164. }
  165.  
  166. if (dc) {// 字符数组是的default
  167. RAIN_CHARACTERS = new char[126 - 33 + 1];
  168. for (int c = 0, i = 33, l = RAIN_CHARACTERS.length; c < l; c++, i++) {
  169. RAIN_CHARACTERS[c] = (char) i;
  170. }
  171. }
  172.  
  173. if (dcf) {// 颜色铺满是default
  174. isColorful = false;
  175. }
  176.  
  177. }
  178.  
  179. /**
  180. * 根据字符串获取其对应的颜色
  181. *
  182. * @param color
  183. * 颜色
  184. * @return
  185. */
  186. private Color getColor(String color) {
  187.  
  188. if (color == null || color.isEmpty()) {
  189. return null;
  190. }
  191. if (color.startsWith("#")) {
  192. int i = Integer.valueOf(color.substring(1), 16);
  193. return new Color(i);
  194. }
  195. // [\\d]:数字 [\\p{Blank}]:空格或制表符
  196. if (color.matches("[\\d]+[\\p{Blank}]*,[\\p{Blank}]*[\\d]+[\\p{Blank}]*,[\\p{Blank}]*[\\d]+")) {
  197. String[] cs = color.split("[\\p{Blank}]*,[\\p{Blank}]");
  198. if (cs.length != 3) {
  199. return null;
  200. }
  201. int r = Integer.valueOf(cs[0]);
  202. int g = Integer.valueOf(cs[1]);
  203. int b = Integer.valueOf(cs[2]);
  204. return new Color(r, g, b);
  205. }
  206. return null;
  207.  
  208. }
  209.  
  210. /**
  211. * 初始化窗口
  212. */
  213. private void init() {
  214.  
  215. setAlwaysOnTop(true);// 设置窗口靠前
  216. setResizable(false);// 不能改变大小
  217. setUndecorated(true);// 设置此frame窗口失去边框和标题栏的修饰(必须在setVisible之前)
  218. setTitle("Binary Rain");// 设置标题
  219. // 创建一个BufferedImage对象
  220. BufferedImage cursor = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB_PRE);
  221. setCursor(Toolkit.getDefaultToolkit().createCustomCursor(cursor,
  222. new Point(8, 8), "Disable Cursor"));// 确认光标的形状
  223. setSize(size);// 设置窗口大小
  224. setLocationRelativeTo(null);// 设置窗口相对于指定组件的位置,null表示位于屏幕的中央
  225.  
  226. addKeyListener(new KeyAdapter() {// 新增一个按键侦听器
  227. @Override
  228. public void keyPressed(KeyEvent e) {
  229. if ((e.isAltDown() && e.getKeyCode() == KeyEvent.VK_F4)
  230. || (e.getKeyCode() == KeyEvent.VK_ESCAPE)) {// 按下Alt+F4或者Esc键
  231. setVisible(false);// 设置窗口不可见
  232. System.exit(0);// 正常停止程序
  233. }
  234. }
  235. });
  236.  
  237. addWindowListener(new WindowAdapter() {
  238. @Override
  239. public void windowClosing(WindowEvent e) {
  240. if (isRaining()) {
  241. stop();
  242. }
  243. System.exit(0);// 正常停止程序
  244. }
  245. });
  246.  
  247. add(panel, BorderLayout.CENTER);// 将指定组件添加到此容器
  248.  
  249. }
  250.  
  251. /**
  252. * 重写setVisible方法,当不显示时停止创建文字雨
  253. */
  254. public void setVisible(boolean flag) {
  255.  
  256. super.setVisible(flag);
  257. if (!flag) {
  258. stop();
  259. }
  260.  
  261. }
  262.  
  263. /**
  264. * 是否开始创建文字雨
  265. *
  266. * @return
  267. */
  268. public boolean isRaining() {
  269.  
  270. return isStart;
  271.  
  272. }
  273.  
  274. /**
  275. * 停止文字雨
  276. */
  277. public void stop() {
  278.  
  279. isStart = false;// 开始标识置为false
  280. if (hasMusic) {// 播放音乐
  281. music.stop();// 停止播放音乐
  282. }
  283.  
  284. }
  285.  
  286. /**
  287. * 开始一个新的线程,创建一条文字雨,使用synchronized保证一个时间内只有一条线程可以执行
  288. */
  289. private synchronized void newRain() {
  290.  
  291. Rain r = new Rain(getRandomLength(), (int) (Math.random() * size.width),
  292. (int) (Math.random() * -60 * 15), (int) (Math.random() * 8 + 2),
  293. (float) (Math.random() * 10 + 10));
  294. rains.add(r);
  295. new Thread(r).start();
  296.  
  297. }
  298.  
  299. /**
  300. * 获取随机长度(10-50)
  301. *
  302. * @return
  303. */
  304. public int getRandomLength() {
  305.  
  306. return (int) (Math.random() * 40 + 10);
  307.  
  308. }
  309.  
  310. /**
  311. * 获取随机字符串
  312. *
  313. * @return
  314. */
  315. public String getRandomChar() {
  316.  
  317. return String.valueOf(RAIN_CHARACTERS[(int) (Math.random() * RAIN_CHARACTERS.length)]);
  318.  
  319. }
  320.  
  321. /**
  322. * 获取面板大小
  323. *
  324. * @return
  325. */
  326. public Dimension getFrameSize() {
  327.  
  328. return size;
  329.  
  330. }
  331.  
  332. public void start() {
  333.  
  334. if (hasMusic) {// 播放音乐
  335. music.loop();// 循环播放
  336. }
  337.  
  338. for (int c = 0, s = 108; c < s; c++) {// 创建108条文字雨
  339. newRain();
  340. }
  341.  
  342. isStart = true;
  343.  
  344. for (Rain r: rains) {
  345. new Thread(r).start();
  346. }
  347.  
  348. new Thread(new Runnable() {
  349.  
  350. public void run() {
  351.  
  352. while (isStart) {
  353. panel.repaint();
  354. }
  355.  
  356. }
  357. }).start();
  358.  
  359. }
  360.  
  361. /**
  362. * 创建文字雨面板
  363. *
  364. */
  365. private final class RainPanel extends JPanel {
  366.  
  367. private static final long serialVersionUID = 1L;
  368.  
  369. public RainPanel() {
  370.  
  371. }
  372.  
  373. private final Color[] COLORS = new Color[] {// 文字雨文本颜色集合
  374. new Color(255, 0, 0),
  375. new Color(255, 165, 0),
  376. new Color(255, 255, 0),
  377. new Color(0, 255, 0),
  378. new Color(0, 127, 0),
  379. new Color(0, 127, 255),
  380. new Color(139, 0, 255)
  381. };
  382.  
  383. @Override
  384. public void paint(Graphics g) {
  385.  
  386. if (isStart) {
  387. BufferedImage img = new BufferedImage(size.width, size.height,
  388. BufferedImage.TYPE_INT_RGB);// 创建一个BufferedImage对象
  389. Graphics2D g2 = (Graphics2D) img.getGraphics();// 获取Graphics2D对象
  390. g2.setColor(background);// 设置颜色
  391. g2.fillRect(0, 0, size.width, size.height);// 用预定的颜色填充一个矩形
  392. g2.setColor(foreground);// 设置颜色
  393. // 克隆所有文字雨信息到Collection中
  394. @SuppressWarnings("unchecked")
  395. Collection<Rain> collection = (Collection<Rain>) rains.clone();
  396. for (Iterator<Rain> it = collection.iterator(); it.hasNext();) {
  397. Rain r = it.next();
  398. if (r.isEnd()) {// 该条文字雨已经结束
  399. rains.remove(r);// 将该条文字雨从集合中移除
  400. newRain();// 创建一条新的文字雨
  401. continue;
  402. }
  403. if (isColorful) {// 颜色铺满
  404. g2.setFont(rainFont.deriveFont(r.getSize()));// 设置文字雨文本大小
  405. String[] ss = r.getRainChars();// 获取文字雨文本内容
  406. int x = r.getX();// 获取文字雨X轴坐标
  407. int y = r.getY() - ss.length * 15;// 获取文字雨Y轴坐标
  408. for (int i = 0, sl = ss.length; i < sl; i++) {
  409. if (i < 7) {
  410. g2.setColor(COLORS[i]);
  411. } else {
  412. g2.setColor(COLORS[i % 7]);
  413. }
  414. g2.drawString(ss[i], x, y);
  415. y += 15;
  416. }
  417. } else {
  418. g2.setFont(rainFont.deriveFont(r.getSize()));// 设置文字雨文本大小
  419. String[] ss = r.getRainChars();// 获取文字雨文本内容
  420. int x = r.getX();// 获取文字雨X轴坐标
  421. int y = r.getY() - ss.length * 15;// 获取文字雨Y轴坐标
  422. for (String s: ss) {
  423. g2.drawString(s, x, y);
  424. y += 15;
  425. }
  426. }
  427. }
  428. g.drawImage(img, 0, 0, this);// 绘制指定图像
  429. }
  430.  
  431. }
  432.  
  433. }
  434.  
  435. /**
  436. * 通过线程创建一条条文字雨
  437. *
  438. */
  439. private final class Rain implements Runnable {
  440.  
  441. private int rainSpeed;// 下雨的速度
  442. private final String[] rainChars;// 下雨的文本
  443. private int rainX, rainY;// 文本坐标系
  444. private float fontSize;// 文本大小
  445.  
  446. /**
  447. * 初始化一条文字雨
  448. *
  449. * @param length
  450. * 文字雨的文本长度
  451. * @param x
  452. * x坐标
  453. * @param y
  454. * y坐标
  455. * @param speed
  456. * 下雨速度
  457. * @param size
  458. * 文本大小
  459. */
  460. public Rain(int length, int x, int y, int speed, float size) {
  461.  
  462. if (speed < 1) {
  463. throw new RuntimeException("The speed must be greater than or equal to 1.");
  464. }
  465.  
  466. if (length < 5) {
  467. length = getRandomLength();
  468. }
  469.  
  470. if (size < 1.0f) {
  471. size = 15.0f;
  472. }
  473.  
  474. rainChars = new String[length + 1];
  475. for (int i = 0; i < length; i++) {
  476. rainChars[i] = getRandomChar();
  477. }
  478. rainChars[length] = " ";
  479. this.rainX = x;
  480. this.rainY = y;
  481. this.rainSpeed = speed;
  482. this.fontSize = size;
  483.  
  484. }
  485.  
  486. /**
  487. * 执行文字雨
  488. */
  489. public void run() {
  490.  
  491. while (isRaining() && rainY < getFrameSize().height + (rainChars.length + 1) * 15) {
  492. if (rainSpeed <= 0) {// 文字雨的速度小于等于0,结束
  493. break;
  494. }
  495. try {
  496. Thread.sleep(rainSpeed);// 睡眠
  497. } catch (InterruptedException ex) {
  498. ex.printStackTrace();
  499. }
  500. rainY += 2;// 每次向下运动2
  501. }
  502. rainSpeed = -1;// 文字雨结束,速度置为-1
  503.  
  504. }
  505.  
  506. /**
  507. * 获取文本内容
  508. *
  509. * @return
  510. */
  511. public String[] getRainChars() {
  512.  
  513. return rainChars;
  514.  
  515. }
  516.  
  517. /**
  518. * 获取文字雨X轴坐标
  519. *
  520. * @return
  521. */
  522. public int getX() {
  523.  
  524. return rainX;
  525.  
  526. }
  527.  
  528. /**
  529. * 获取文字雨Y轴坐标
  530. *
  531. * @return
  532. */
  533. public int getY() {
  534.  
  535. return rainY;
  536.  
  537. }
  538.  
  539. /**
  540. * 获取文字雨文本大小
  541. *
  542. * @return
  543. */
  544. public float getSize() {
  545.  
  546. return fontSize;
  547.  
  548. }
  549.  
  550. /**
  551. * 判断文字雨是否结束
  552. *
  553. * @return
  554. */
  555. public boolean isEnd() {
  556.  
  557. return rainSpeed <= 0;
  558.  
  559. }
  560.  
  561. }
  562.  
  563. public static void main(String[] args) {
  564.  
  565. BinaryRain rain = new BinaryRain();
  566. rain.setVisible(true);
  567. rain.start();
  568.  
  569. }
  570.  
  571. }

5.效果预览

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

java之数字彩虹雨的更多相关文章

  1. 原码,反码,补码,及Java中数字表示方法

    原码:原码是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 如:如果是八位二进制1即用00000001表示,-1即用10000001表示. 反码:正数的反码就是其本身,负数的反码是在其 ...

  2. java 将数字转成成16进制

      java 将数字转成成16进制 CreationTime--2018年6月11日17点11分 Author:Marydon 1.前提 数字必须是byte类型,即[-128,127] 2.代码实现 ...

  3. 实验三 Java猜数字游戏开发

    课程:Java实验   班级:201352     姓名:程涵  学号:20135210 成绩:             指导教师:娄佳鹏   实验日期:15.06.03 实验密级:         ...

  4. java大数字操作:BigInteger,BigDecimal(浮点型)

    java大数字操作: BigInteger:大数字整型的 BigDecimal(浮点型):大数字小数的,也适用大的整数 BigInteger: String num1 = "10038182 ...

  5. 【Java】Java与数字证书

    Java与数字证书 Java与数字证书 证书的签发和应用 证书的内容和意义 其它 证书(Certificate,也称public-key certificate)是用某种签名算法对某些内容(比如公钥) ...

  6. java的数字精确计算问题-BigDecimal

    java的数字运算,偶尔会出现精度的问题,以下阐述的 java的BigDecimal类的使用. 例如: System.out.println(0.9+0.3); 结果1.2 System.out.pr ...

  7. Java中数字的格式化输出

    Java中数字的格式化输出 double d = 345.678; String s = "hello!"; int i = 1234; //"%"表示进行格式 ...

  8. java 猜数字游戏

    作用:猜数字游戏.随机产生1个数字(1~10),大了.小了或者成功后给出提示. 语言:java 工具:eclipse 作者:潇洒鸿图 时间:2016.11.10 >>>>> ...

  9. java猜数字游戏

    import java.util.Scanner; //导入包 class GuessNum { public static void main(String[] args) { int num = ...

随机推荐

  1. RQNOJ PID217 / [NOIP1999]拦截导弹【n^2 / LIS】

    题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...

  2. poj3264(Sparse-Table 算法模板)

    poj3264 题意 询问区间最大值最小值之差. 分析 dp_max[i][j] 表示以 i 为起点,长度为 \(2^j\) 的区间最大值. 利用递推预处理出区间最大值最小值. code #inclu ...

  3. Controlled Tournament(状态压缩DP)

    Controlled Tournament 题意 n 名选手进行淘汰赛,R[i][j] = 1 表示 i 能胜过 j.要求通过安排淘汰赛使得,m 选手获得最终胜利,问使得比赛数最少的方案数. 分析 设 ...

  4. HashSet、LinkedHashSet和TreeSet

    关键技术: HashSet采用散列函数对元素进行排序,是专门为快速查询而设计的.存入HashSet的对象必须定义hashCode方法. TreeSet采用红黑树的数据结构进行排序元素,使用它可以从Se ...

  5. 五. 面向对象高级特性6. Java 泛型

    我们知道,使用变量之前要定义,定义一个变量时必须要指明它的数据类型,什么样的数据类型赋给什么样的值. 假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数.小数和字符串,例如: x = 1 ...

  6. 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 ...

  7. ostu进行遥感图像的分割

    城市地区道路网的简单的阈值分割.采用的是单ostu(最佳阈值分割)算法,废话少说,如果不太清楚该算法,请参考文献[1]中的图像分割这一章的介绍.程序直接运行的效果如下.

  8. CM3大礼包

  9. Android控件之GridView探究

    GridView是一项显示二维的viewgroup,可滚动的网格.一般用来显示多张图片. 以下模拟九宫图的实现,当鼠标点击图片时会进行相应的跳转链接. 目录结构 main.xml布局文件,存放Grid ...

  10. depth linear

    float ConvertDepth( float depthFromTex, float4 cameraParams ){ const float near = cameraParams.z; co ...