当前位置:首页>python>代码的诗意:用Python重现《黑客帝国》数字雨,再送你一场爱心流星雨

代码的诗意:用Python重现《黑客帝国》数字雨,再送你一场爱心流星雨

  • 2026-09-02 19:07:02
代码的诗意:用Python重现《黑客帝国》数字雨,再送你一场爱心流星雨

"代码不仅是工具,更是艺术。"


一、为什么《黑客帝国》的数字雨如此经典?

1999年,电影《黑客帝国》(The Matrix)上映,那个绿色数字从天而降的画面,成为了影史最经典的视觉符号之一。

1.1 超越时代的视觉美学

导演沃卓斯基姐妹创造的这个数字雨效果,不仅仅是一个简单的动画,它代表了:

  • • 虚拟与现实的边界:数字世界正在"渗透"现实
  • • 信息的洪流:我们生活在一个被数据包围的时代
  • • 赛博朋克的极致美学:高科技、低生活的视觉表达

1.2 为什么它如此迷人?

心理学家分析,数字雨效果之所以令人着迷,是因为它触发了人类的几种本能反应:

心理效应
解释
流动感
人类大脑对运动物体有天生的注意力偏好
神秘感
无法立即理解的符号激发好奇心
秩序中的混乱
有规律的下落,随机的字符,形成独特的美感
绿色的心理暗示
绿色与科技、未来、生命力相关联

1.3 数字雨的技术构成

从技术角度看,数字雨效果包含几个核心要素:

┌─────────────────────────────────────────┐│           数字雨效果构成要素              │├─────────────────────────────────────────┤│  1. 字符集:日文片假名、数字、字母        ││  2. 颜色:荧光绿渐变(亮→暗)            ││  3. 运动:垂直下落 + 随机速度            ││  4. 层次:多条独立的"雨滴轨迹"           ││  5. 透明度:尾迹渐隐效果                 │└─────────────────────────────────────────┘

二、用Python创造你的数字雨

现在,让我们用Python重现这个经典效果!不需要复杂的图形库,只需要一个终端就能运行。

2.1 基础版数字雨(终端版)

这是最简单的实现,直接在终端中运行:

"""《黑客帝国》数字雨效果 - 终端版作者:鹏哥数个数运行环境:Python 3.x"""import randomimport osimport time# 清屏函数def clear_screen():    os.system('cls' if os.name == 'nt' else 'clear')# 字符集:数字、字母、日文片假名CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \        "アイウエオカキクケコサシスセソタチツテト" \        "ナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"def matrix_rain_terminal(width=80, height=24, speed=0.05):    """    终端版数字雨    width: 终端宽度    height: 终端高度    speed: 刷新速度(秒)    """    # 初始化每列的位置    drops = [random.randint(-20, 0) for _ in range(width)]    try:        while True:            clear_screen()            # 生成每一行            for row in range(height):                line = ""                for col in range(width):                    if row == drops[col]:                        # 雨滴头部(最亮的字符)                        line += f"\033[1;32m{random.choice(CHARS)}\033[0m"                    elif drops[col] - 5 <= row < drops[col]:                        # 雨滴尾迹(较暗的字符)                        line += f"\033[0;32m{random.choice(CHARS)}\033[0m"                    else:                        line += " "                print(line)            # 更新雨滴位置            for i in range(width):                drops[i] += 1                if drops[i] > height + random.randint(0, 10):                    drops[i] = random.randint(-10, 0)            time.sleep(speed)    except KeyboardInterrupt:        clear_screen()        print("数字雨已停止")if __name__ == "__main__":    print("《黑客帝国》数字雨效果")    print("按 Ctrl+C 停止")    time.sleep(2)    matrix_rain_terminal()

运行效果预览:

    1          キ          5          A          9    0          ク          2          B          8    A          エ          1          C          7    2          オ          0          D          6    B          カ          A          E          5

2.2 进阶版数字雨(图形界面版)

如果你想要更炫酷的效果,可以使用 pygame 库:

"""《黑客帝国》数字雨效果 - Pygame图形版需要安装:pip install pygame"""import pygameimport random# 初始化pygamepygame.init()# 屏幕设置WIDTH, HEIGHT = 1200, 800screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption("Matrix Digital Rain - 黑客帝国数字雨")# 颜色定义BLACK = (0, 0, 0)GREEN_BRIGHT = (180, 255, 180)  # 亮绿色(头部)GREEN_NORMAL = (0, 255, 70)     # 正常绿色GREEN_DARK = (0, 100, 30)       # 暗绿色(尾迹)# 字体设置FONT_SIZE = 16font = pygame.font.SysFont("msmincho", FONT_SIZE, bold=True)# 字符集CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \        "アイウエオカキクケコサシスセソタチツテト" \        "ナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"class Drop:    """雨滴类"""    def __init__(self, x):        self.x = x        self.y = random.randint(-HEIGHT, 0)        self.speed = random.randint(3, 8)        self.length = random.randint(5, 20)        self.chars = [random.choice(CHARS) for _ in range(self.length)]        self.char_change = 0    def fall(self):        """下落"""        self.y += self.speed        # 随机更换字符        self.char_change += 1        if self.char_change % 3 == 0:            for i in range(len(self.chars)):                if random.random() < 0.3:  # 30%概率更换                    self.chars[i] = random.choice(CHARS)        # 重置位置        if self.y - self.length * FONT_SIZE > HEIGHT:            self.y = random.randint(-200, -50)            self.speed = random.randint(3, 8)            self.length = random.randint(5, 20)            self.chars = [random.choice(CHARS) for _ in range(self.length)]    def draw(self, screen):        """绘制"""        for i, char in enumerate(self.chars):            y_pos = self.y - i * FONT_SIZE            if 0 <= y_pos < HEIGHT:                # 头部最亮,尾迹渐暗                if i == 0:                    color = GREEN_BRIGHT                elif i < 3:                    color = GREEN_NORMAL                else:                    # 渐变暗                    darkness = min(255, i * 15)                    color = (0, max(100, 255 - darkness), max(30, 100 - darkness // 3))                text = font.render(char, True, color)                screen.blit(text, (self.x, y_pos))def main():    """主函数"""    # 创建雨滴列    columns = WIDTH // FONT_SIZE    drops = [Drop(x * FONT_SIZE) for x in range(columns)]    clock = pygame.time.Clock()    running = True    print("按 ESC 或关闭窗口退出")    while running:        for event in pygame.event.get():            if event.type == pygame.QUIT:                running = False            if event.type == pygame.KEYDOWN:                if event.key == pygame.K_ESCAPE:                    running = False        # 黑色背景(带轻微拖尾效果)        fade = pygame.Surface((WIDTH, HEIGHT))        fade.fill(BLACK)        fade.set_alpha(50)  # 透明度        screen.blit(fade, (0, 0))        # 更新和绘制雨滴        for drop in drops:            drop.fall()            drop.draw(screen)        pygame.display.flip()        clock.tick(30)  # 30帧/秒    pygame.quit()if __name__ == "__main__":    main()

安装依赖:

pip install pygame

2.3 代码解析

让我们拆解一下数字雨的核心原理:

┌─────────────────────────────────────────────────────────────┐│                    数字雨原理图解                             │├─────────────────────────────────────────────────────────────┤│                                                             ││   列1    列2    列3    列4    列5    列6                    ││    ↓      ↓      ↓      ↓      ↓      ↓                    ││    A      キ     5      B      9      オ  ← 雨滴头部(最亮) ││    2      ク     2      C      8      カ                    ││    B      エ     1      D      7      キ  ← 雨滴中部        ││    0      オ     0      E      6      ク                    ││           カ            F      5                            ││                  ↑                                          ││            雨滴尾迹(渐暗)                                  ││                                                             ││   每一列是一个独立的"雨滴"对象                               ││   - 有自己的下落速度                                        ││   - 有自己的字符序列                                        ││   - 到达底部后从顶部重新出现                                 │└─────────────────────────────────────────────────────────────┘

三、浪漫升级:下一场红色爱心雨

数字雨很酷,但如果是下爱心呢?让我们改造代码,创造一场浪漫的爱心流星雨!(有心的小伙伴,可以复现出来给自己女朋友惊喜!)

3.1 爱心雨代码

"""爱心流星雨效果用Python创造浪漫"""import pygameimport randomimport mathpygame.init()# 屏幕设置WIDTH, HEIGHT = 1000, 700screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption("❤️ 爱心流星雨 ❤️")# 颜色BLACK = (10, 10, 20)RED_BRIGHT = (255, 100, 150)RED_NORMAL = (255, 50, 100)RED_DARK = (150, 30, 60)PINK = (255, 182, 193)# 字体FONT_SIZE = 20font = pygame.font.SysFont("simhei", FONT_SIZE, bold=True)# 爱心符号集合HEARTS = ["❤", "♥", "💕", "💖", "💗", "💓", "💝", "♡"]class HeartDrop:    """爱心雨滴"""    def __init__(self, x):        self.x = x        self.y = random.randint(-HEIGHT, -50)        self.speed = random.uniform(2, 6)        self.size = random.randint(14, 24)        self.heart = random.choice(HEARTS)        self.sway = random.uniform(0, 2 * math.pi)  # 摆动相位        self.sway_speed = random.uniform(0.02, 0.05)        self.sway_amount = random.uniform(0, 30)        self.original_x = x        self.rotation = 0        self.rotation_speed = random.uniform(-2, 2)        self.opacity = 255        self.fade_speed = random.uniform(0.5, 2)    def fall(self):        """下落并摆动"""        self.y += self.speed        self.sway += self.sway_speed        self.rotation += self.rotation_speed        # 左右摆动效果        self.x = self.original_x + math.sin(self.sway) * self.sway_amount        # 到达底部后重置        if self.y > HEIGHT + 50:            self.y = random.randint(-100, -50)            self.original_x = random.randint(50, WIDTH - 50)            self.x = self.original_x            self.speed = random.uniform(2, 6)            self.heart = random.choice(HEARTS)            self.opacity = 255    def draw(self, screen):        """绘制爱心"""        if 0 <= self.y < HEIGHT + 50:            # 根据位置调整颜色(上面亮,下面暗)            progress = self.y / HEIGHT            if progress < 0.3:                color = RED_BRIGHT            elif progress < 0.7:                color = RED_NORMAL            else:                # 渐隐效果                fade = max(0, 1 - (progress - 0.7) * 3)                color = (                    int(RED_DARK[0] + (RED_NORMAL[0] - RED_DARK[0]) * fade),                    int(RED_DARK[1] + (RED_NORMAL[1] - RED_DARK[1]) * fade),                    int(RED_DARK[2] + (RED_NORMAL[2] - RED_DARK[2]) * fade)                )            # 使用系统字体渲染爱心            heart_font = pygame.font.SysFont("simhei", self.size, bold=True)            text = heart_font.render(self.heart, True, color)            # 绘制            screen.blit(text, (int(self.x), int(self.y)))class Particle:    """粒子效果(闪烁的小星星)"""    def __init__(self):        self.x = random.randint(0, WIDTH)        self.y = random.randint(0, HEIGHT)        self.size = random.randint(1, 3)        self.life = random.randint(30, 100)        self.max_life = self.life        self.color = random.choice([PINK, (255, 255, 200), (200, 200, 255)])    def update(self):        self.life -= 1        if self.life <= 0:            self.__init__()    def draw(self, screen):        alpha = self.life / self.max_life        color = tuple(int(c * alpha) for c in self.color)        pygame.draw.circle(screen, color, (self.x, self.y), self.size)def draw_background_gradient():    """绘制渐变背景"""    for y in range(HEIGHT):        # 从深蓝到黑色的渐变        color_val = int(20 + (y / HEIGHT) * 10)        pygame.draw.line(screen, (color_val // 2, color_val // 3, color_val),                         (0, y), (WIDTH, y))def main():    """主函数"""    # 创建爱心雨滴    hearts = [HeartDrop(random.randint(50, WIDTH - 50)) for _ in range(60)]    # 创建背景粒子    particles = [Particle() for _ in range(50)]    clock = pygame.time.Clock()    running = True    # 标题文字    title_font = pygame.font.SysFont("simhei", 48, bold=True)    subtitle_font = pygame.font.SysFont("simhei", 24)    print("爱心流星雨运行中...")    print("按 ESC 或关闭窗口退出")    while running:        for event in pygame.event.get():            if event.type == pygame.QUIT:                running = False            if event.type == pygame.KEYDOWN:                if event.key == pygame.K_ESCAPE:                    running = False        # 绘制渐变背景        draw_background_gradient()        # 更新和绘制粒子        for particle in particles:            particle.update()            particle.draw(screen)        # 更新和绘制爱心        for heart in hearts:            heart.fall()            heart.draw(screen)        # 绘制标题        title = title_font.render("❤️ 爱心流星雨 ❤️", True, RED_BRIGHT)        title_rect = title.get_rect(center=(WIDTH // 2, 50))        # 标题阴影        title_shadow = title_font.render("❤️ 爱心流星雨 ❤️", True, (50, 20, 30))        screen.blit(title_shadow, (title_rect.x + 2, title_rect.y + 2))        screen.blit(title, title_rect)        # 绘制副标题        subtitle = subtitle_font.render("用Python创造的浪漫", True, PINK)        subtitle_rect = subtitle.get_rect(center=(WIDTH // 2, 100))        screen.blit(subtitle, subtitle_rect)        pygame.display.flip()        clock.tick(60)  # 60帧/秒    pygame.quit()if __name__ == "__main__":    main()

3.2 爱心雨效果特点

特性
说明
摆动下落
爱心不是直线下落,而是左右摇摆
大小变化
不同大小的爱心,增加层次感
颜色渐变
从上到下由亮红变为暗红
背景粒子
闪烁的小星星营造浪漫氛围
多种爱心
使用不同的爱心符号增加多样性

3.3 运行截图示意

        ❤️ 爱心流星雨 ❤️         用Python创造的浪漫         ❤      💕      💖       💗  💓    💝    ♥  ❤          ♡      ❤      💕        💖  💗    💓    💝           ♥      ♡      ❤         💕  💖    💗    💓            💝      ♥      ♡

四、制作绚丽的烟花

4.1 烟花绽放效果

"""烟花绽放效果节日庆典"""import pygameimport randomimport mathpygame.init()WIDTH, HEIGHT = 1000, 700screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption("🎆 烟花绽放 🎆")BLACK = (10, 10, 20)class Particle:    def __init__(self, x, y, color):        self.x = x        self.y = y        self.color = color        angle = random.uniform(0, 2 * math.pi)        speed = random.uniform(2, 8)        self.vx = math.cos(angle) * speed        self.vy = math.sin(angle) * speed        self.life = random.randint(40, 80)        self.max_life = self.life        self.size = random.randint(2, 5)    def update(self):        self.x += self.vx        self.y += self.vy        self.vy += 0.1  # 重力        self.life -= 1        return self.life > 0    def draw(self, screen):        alpha = self.life / self.max_life        color = tuple(int(c * alpha) for c in self.color)        pygame.draw.circle(screen, color, (int(self.x), int(self.y)), self.size)class Firework:    def __init__(self):        self.x = random.randint(100, WIDTH - 100)        self.y = HEIGHT        self.vy = random.uniform(-12, -15)        self.color = random.choice([            (255, 100, 100), (100, 255, 100), (100, 100, 255),            (255, 255, 100), (255, 100, 255), (100, 255, 255)        ])        self.exploded = False        self.particles = []    def update(self):        if not self.exploded:            self.y += self.vy            self.vy += 0.3            if self.vy >= 0:  # 到达顶点                self.explode()        else:            self.particles = [p for p in self.particles if p.update()]        return len(self.particles) > 0 or not self.exploded    def explode(self):        self.exploded = True        for _ in range(100):            self.particles.append(Particle(self.x, self.y, self.color))    def draw(self, screen):        if not self.exploded:            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), 4)        for p in self.particles:            p.draw(screen)def main():    fireworks = []    clock = pygame.time.Clock()    running = True    frame_count = 0    while running:        for event in pygame.event.get():            if event.type == pygame.QUIT:                running = False            if event.type == pygame.KEYDOWN:                if event.key == pygame.K_SPACE:                    fireworks.append(Firework())        # 自动发射烟花        frame_count += 1        if frame_count % 60 == 0:  # 每秒发射一个            fireworks.append(Firework())        screen.fill(BLACK)        fireworks = [f for f in fireworks if f.update()]        for f in fireworks:            f.draw(screen)        pygame.display.flip()        clock.tick(60)    pygame.quit()if __name__ == "__main__":    main()

五、如何分享你的作品

5.1 保存为视频

"""将动画保存为视频文件需要安装:pip install opencv-python"""import cv2import numpy as npimport pygame# ... 你的绘制代码 ...# 设置视频写入器fourcc = cv2.VideoWriter_fourcc(*'mp4v')out = cv2.VideoWriter('matrix_rain.mp4', fourcc, 30.0, (WIDTH, HEIGHT))# 在主循环中while running:    # ... 绘制代码 ...    # 捕获帧    frame = pygame.surfarray.array3d(screen)    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)    frame = np.rot90(frame, 3)  # 旋转    frame = np.flip(frame, 1)   # 翻转    out.write(frame)out.release()

结语

从《黑客帝国》的数字雨到浪漫的爱心流星,代码可以创造出令人惊叹的视觉效果。这不仅仅是编程技术的展示,更是艺术与科技的完美结合。

💡 给初学者的建议:

  1. 1. 先运行代码,看到效果
  2. 2. 修改参数,观察变化
  3. 3. 尝试添加自己的创意
  4. 4. 分享给朋友,获得反馈

代码的世界没有边界,你的想象力就是极限。


完整代码已开源,关注公众号「鹏哥数个数」,回复"数字雨"获取所有源码文件!

作者简介:鹏哥数个数,热爱用代码创造美好事物,相信编程不仅是技术,更是艺术。


本文首发于微信公众号「鹏哥数个数」,转载请注明出处。

特别致谢:《黑客帝国》创作者们。

最新文章

随机文章