看见很多人用C语言实现黑客帝国中的字符雨,看起来还挺好看的,那么我们今天也来实现一下。

准备:

    我们的小项目呢,使用到了   panel绘制,定时器,数组   ;

    其中定时器得注意,我们使用的定时器是 javax.swing.Timer; 中的定时器,而不是 javax.util.Timer;包的。


思路:

   我们在panel中绘制字符,把面板分成合适的行和列,利用随机位置,去绘制字符串,然后利用定时器去不停的重新绘制,这样就会有下落的动画。废话不多说,开始:


过程:

   1.我们首先创建一个窗体,为了代码整体的可读性,我们把它写出一个类:


import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.WindowConstants;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Dimension2D;
import java.util.Random;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

//上面是所有用到的包,在这里全部给出

class digital_study {
	    //定义窗口
		public windows Win;
		private JFrame jf;
		
		
		//定义获取到的窗体大小
		private int width;
		private int height;
		
	public digital_study() {
		//定义窗体并获取JFrame对象和宽高
		Win = new windows();
		jf = Win.jf();
		width = Win.width;
		height = Win.height;
		
		
		
	}	
	
		
	//为了使代码灵活性更高,我们全部写到digital_study 这个类中
	public static void main(String[] args) {
		new digital_study();
     }
}


class windows extends JFrame{
	public int width;
	public int height;
	private JFrame jf;
	public windows(){
		jf = new JFrame("黑客数字雨"); // 实例化一个JFrame对象
		Container contentPane = jf.getContentPane();
		jf.setVisible(true); // 使窗体可视
		jf.setBounds(200,120,1500, 900); // 设置窗体大小
		setLocationRelativeTo(null);   //设置窗口剧中
		jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//点击时关闭程序
		
		//窗体返回大小
		width = (int)jf.getSize().getWidth();
		height = (int)jf.getSize().getHeight();
		
	}
	public JFrame jf() {
		return this.jf;  //返回JP实例
	}
	
}

我们运行可以看到,我们创建了一个Jframe窗体,并设置了一些属性,然后获取这个窗体的Jframe对象和宽高大小。



2.接下来我们去创建Panel画板  然后放到JFrame中,接下来我们可以看到,JFrame中背景成了黑色,因为我们把Jpanel设置为黑色,并且布满了Jpanel

class digital_study {
	    //定义窗口
		public windows Win;
		private JFrame jf;
		
		
		//定义获取到的窗体大小
		private int width;
		private int height;
		
		//定义画板
		private DigtalRainHPanel panel;
		
	public digital_study() {
		//定义窗体并获取JFrame对象和宽高
		Win = new windows();
		jf = Win.jf();
		width = Win.width;
		height = Win.height;
		
		//创建Jpanel画板并添加到jf中
		panel = new DigtalRainHPanel();
		jf.add(panel);
		
		
	}	
		
	
	//绘制数字雨   
	private class DigtalRainHPanel extends JPanel{
			
			public int length = 15; //每一串字符长度
			@Override
			public void paint(Graphics g){
				Graphics2D g2d= (Graphics2D) g;    //转换成2D画布
				g2d.setFont(getFont().deriveFont(Font.BOLD));   //设置字体
				g2d.setColor(Color.black);    //设置画板背景
				g2d.fillRect(0, 0, width, height);		//使Jpanel布满整个JFrame 从0,0位置开始,大小为窗体大小
				
			}
		}
	
	
	//为了使代码灵活性更高,我们全部写到digital_study 这个类中
	public static void main(String[] args) {
		new digital_study();
     }
}


class windows extends JFrame{
	public int width;
	public int height;
	private JFrame jf;
	public windows(){
		jf = new JFrame("黑客数字雨"); // 实例化一个JFrame对象
		Container contentPane = jf.getContentPane();
		jf.setVisible(true); // 使窗体可视
		jf.setBounds(200,120,1500, 900); // 设置窗体大小
		setLocationRelativeTo(null);   //设置窗口剧中
		jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//点击时关闭程序
		
		//窗体返回大小
		width = (int)jf.getSize().getWidth();
		height = (int)jf.getSize().getHeight();
		
	}
	public JFrame jf() {
		return this.jf;  //返回JP实例
	}
	
}

可以看到这样的

JAVA--简单实现黑客帝国字符雨(图1)


3.接下来,我们设置随机字符串,并且把它写到Jpanel中

class digital_study {
	//定义窗口
	public windows Win;
	private JFrame jf;
	
     //定义获取到的窗体大小
	private int width;
	private int height;
		
	//定义画板
	private DigtalRainHPanel panel;
	//定义行和列
	private int rows;
	private int columns;
		
	//定义屏幕划分的行和列的比例
	private int grid = 20;
		
	//初始化每列字母出现位置的数组,并记录出现的位置
	int[] pointsFirstArr;
		
	//获取随机字符串,用于首字母
	public char getRandomStr() {
		Random random = new Random();
		return (char)(random.nextInt(94)+33);
	}
		
	public digital_study() {
		//定义窗体并获取JFrame对象和宽高
		Win = new windows();
		jf = Win.jf();
		width = Win.width;
		height = Win.height;
		
		//创建Jpanel画板并添加到jf中
		panel = new DigtalRainHPanel();
		jf.add(panel);
		
		//后面是新增的代码
		//一共多少行,多少列
		rows = height/grid;
		columns = width/grid;
				
				
		//初始化每列字母出现位置的数组,并记录出现的位置
		pointsFirstArr = new int[columns + 1];
				
		//每列字母出现的随机位置
		Random random = new Random();
		for (int i = 0; i < pointsFirstArr.length; i++) {
			pointsFirstArr[i] = random.nextInt(rows);
		}
		
	}		
		
	
	//绘制数字雨   
	private class DigtalRainHPanel extends JPanel{
			
			public int length = 15; //每一串字符长度
			@Override
			public void paint(Graphics g){
				Graphics2D g2d= (Graphics2D) g;    //转换成2D画布
				g2d.setFont(getFont().deriveFont(Font.BOLD));   //设置字体
				g2d.setColor(Color.black);    //设置画板背景
				g2d.fillRect(0, 0, width, height);		//使Jpanel布满整个JFrame 从0,0位置开始,大小为窗体大小
				
				
				//把它画到画布里
				//绘制每一列首字母
				
				int currentColum = 0;
				Random random = new Random();
				for (int x = 0; x < width; x += grid) {
					//第一个字母的位置
					int endPos = pointsFirstArr[currentColum];
					g2d.setColor(Color.CYAN);
					g2d.drawString(String.valueOf(getRandomStr()), x, endPos * grid);
					
				}
			}
		}
	
	
	//为了使代码灵活性更高,我们全部写到digital_study 这个类中
	public static void main(String[] args) {
		new digital_study();
     }
}


class windows extends JFrame{
	public int width;
	public int height;
	private JFrame jf;
	public windows(){
		jf = new JFrame("黑客数字雨"); // 实例化一个JFrame对象
		Container contentPane = jf.getContentPane();
		jf.setVisible(true); // 使窗体可视
		jf.setBounds(200,120,1500, 900); // 设置窗体大小
		setLocationRelativeTo(null);   //设置窗口剧中
		jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//点击时关闭程序
		
		//窗体返回大小
		width = (int)jf.getSize().getWidth();
		height = (int)jf.getSize().getHeight();
		
	}
	public JFrame jf() {
		return this.jf;  //返回JP实例
	}
	
}

可以看到是这样的,这是每一行的首字母,因为是随机的,所以每次打开位置会不一致

JAVA--简单实现黑客帝国字符雨(图2)



4.接下来我们把每一行后面字符的也写上并且让他随机出现,然后让他随机下移1-5个大小

class digital_study {
	//定义窗口
	public windows Win;
	private JFrame jf;
	
     //定义获取到的窗体大小
	private int width;
	private int height;
		
	//定义画板
	private DigtalRainHPanel panel;
	//定义行和列
	private int rows;
	private int columns;
		
	//定义屏幕划分的行和列的比例
	private int grid = 20;
		
	//初始化每列字母出现位置的数组,并记录出现的位置
	int[] pointsFirstArr;
		
	//获取随机字符串,用于首字母
	public char getRandomStr() {
		Random random = new Random();
		return (char)(random.nextInt(94)+33);
	}
		
	public digital_study() {
		//定义窗体并获取JFrame对象和宽高
		Win = new windows();
		jf = Win.jf();
		width = Win.width;
		height = Win.height;
		
		//创建Jpanel画板并添加到jf中
		panel = new DigtalRainHPanel();
		jf.add(panel);
		
		//后面是新增的代码
		//一共多少行,多少列
		rows = height/grid;
		columns = width/grid;
				
				
		//初始化每列字母出现位置的数组,并记录出现的位置
		pointsFirstArr = new int[columns + 1];
				
		//每列字母出现的随机位置
		Random random = new Random();
		for (int i = 0; i < pointsFirstArr.length; i++) {
			pointsFirstArr[i] = random.nextInt(rows);
		}
		
	}		
		
	
	//绘制数字雨   
	private class DigtalRainHPanel extends JPanel{
			
			public int length = 15; //每一串字符长度
			@Override
			public void paint(Graphics g){
				Graphics2D g2d= (Graphics2D) g;    //转换成2D画布
				g2d.setFont(getFont().deriveFont(Font.BOLD));   //设置字体
				g2d.setColor(Color.black);    //设置画板背景
				g2d.fillRect(0, 0, width, height);		//使Jpanel布满整个JFrame 从0,0位置开始,大小为窗体大小
				
				
				//把它画到画布里
				//绘制每一列首字母
				
				int currentColum = 0;
				Random random = new Random();
				for (int x = 0; x < width; x += grid) {
					//第一个字母的位置
					int endPos = pointsFirstArr[currentColum];
					g2d.setColor(Color.CYAN);
					g2d.drawString(String.valueOf(getRandomStr()), x, endPos * grid);//写入字符
					
					//绘制每列后续字母
					int lc = 0;  //颜色程度
					//
					for (int i = endPos - length; i < endPos; i++) {
						lc += 30;  //颜色逐渐增加
						if(lc > 255) {
							lc = 255;
						}
						g2d.setColor(new Color( 0, lc, 0));  //设置颜色
						g2d.drawString(String.valueOf(getRandomStr()), x, i * grid);  //写入字符
					}
					//随机下移动1-5个单位
					pointsFirstArr[currentColum] += random.nextInt(5);
					//如果第一个字母超出了屏幕大小,则重新产生一个随机数,
					if(pointsFirstArr[currentColum] * grid > height) {  
						pointsFirstArr[currentColum] = random.nextInt(rows);
					}
					currentColum ++;
				}
			}
		}
	
	
	//为了使代码灵活性更高,我们全部写到digital_study 这个类中
	public static void main(String[] args) {
		new digital_study();
     }
}

我们可以看到,字符随机出现在窗口中,但是是静止的

JAVA--简单实现黑客帝国字符雨(图3)



5.我们可以看到上图是静止的,这时需要用到定时器,让我们的画布不同的重绘,实现流动效果   实现接口ActionListener  ,直接在函数中,new Timer(100,this).start();

import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.WindowConstants;


import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Dimension2D;
import java.util.Random;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.JPanel;
import javax.swing.WindowConstants;


class digital_study implements ActionListener{
	//定义窗口
	public windows Win;
	private JFrame jf;
	
     //定义获取到的窗体大小
	private int width;
	private int height;
		
	//定义画板
	private DigtalRainHPanel panel;
	//定义行和列
	private int rows;
	private int columns;
		
	//定义屏幕划分的行和列的比例
	private int grid = 20;
		
	//初始化每列字母出现位置的数组,并记录出现的位置
	int[] pointsFirstArr;
		
	//获取随机字符串,用于首字母
	public char getRandomStr() {
		Random random = new Random();
		return (char)(random.nextInt(94)+33);
	}
		
	public digital_study() {
		//定义窗体并获取JFrame对象和宽高
		Win = new windows();
		jf = Win.jf();
		width = Win.width;
		height = Win.height;
		
		//创建Jpanel画板并添加到jf中
		panel = new DigtalRainHPanel();
		jf.add(panel);
		
		//后面是新增的代码
		//一共多少行,多少列
		rows = height/grid;
		columns = width/grid;
				
				
		//初始化每列字母出现位置的数组,并记录出现的位置
		pointsFirstArr = new int[columns + 1];
				
		//每列字母出现的随机位置
		Random random = new Random();
		for (int i = 0; i < pointsFirstArr.length; i++) {
			pointsFirstArr[i] = random.nextInt(rows);
		}
		
		//设置定时器  时间100ms 事件this 因为我们实现了ActionListener接口,所以直接传入this
		new Timer(100,this).start();
    }		
	
	//ActionListener接口的抽象方法
	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		panel.repaint();   //不停重新绘制画布
	}
	
	//绘制数字雨   
	private class DigtalRainHPanel extends JPanel{
			
			public int length = 15; //每一串字符长度
			@Override
			public void paint(Graphics g){
				Graphics2D g2d= (Graphics2D) g;    //转换成2D画布
				g2d.setFont(getFont().deriveFont(Font.BOLD));   //设置字体
				g2d.setColor(Color.black);    //设置画板背景
				g2d.fillRect(0, 0, width, height);		//使Jpanel布满整个JFrame 从0,0位置开始,大小为窗体大小
				
				
				//把它画到画布里
				//绘制每一列首字母
				
				int currentColum = 0;
				Random random = new Random();
				for (int x = 0; x < width; x += grid) {
					//第一个字母的位置
					int endPos = pointsFirstArr[currentColum];
					g2d.setColor(Color.CYAN);
					g2d.drawString(String.valueOf(getRandomStr()), x, endPos * grid);//写入字符
					
					//绘制每列后续字母
					int lc = 0;  //颜色程度
					//
					for (int i = endPos - length; i < endPos; i++) {
						lc += 30;  //颜色逐渐增加
						if(lc > 255) {
							lc = 255;
						}
						g2d.setColor(new Color( 0, lc, 0));  //设置颜色
						g2d.drawString(String.valueOf(getRandomStr()), x, i * grid);  //写入字符
					}
					//随机下移动1-5个单位
					pointsFirstArr[currentColum] += random.nextInt(5);
					//如果第一个字母超出了屏幕大小,则重新产生一个随机数,
					if(pointsFirstArr[currentColum] * grid > height) {  
						pointsFirstArr[currentColum] = random.nextInt(rows);
					}
					currentColum ++;
				}
			}
		}
	
	
	//为了使代码灵活性更高,我们全部写到digital_study 这个类中
	public static void main(String[] args) {
		new digital_study();
     }

	
}


class windows extends JFrame{
	public int width;
	public int height;
	private JFrame jf;
	public windows(){
		jf = new JFrame("黑客数字雨"); // 实例化一个JFrame对象
		Container contentPane = jf.getContentPane();
		jf.setVisible(true); // 使窗体可视
		jf.setBounds(200,120,1500, 900); // 设置窗体大小
		setLocationRelativeTo(null);   //设置窗口剧中
		jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//点击时关闭程序
		
		//窗体返回大小
		width = (int)jf.getSize().getWidth();
		height = (int)jf.getSize().getHeight();
		
	}
	public JFrame jf() {
		return this.jf;  //返回JP实例
	}
	
}

以上代码是可执行代码,效果图如下:

JAVA--简单实现黑客帝国字符雨(图4)


这个呢,比较简陋,大家要是能继续发挥,加上一些年份我想效果会更好