Python turtle打造一个浪漫流星雨表白程序

 更新时间:2026年06月03日 08:42:24   作者:WL_Aurora  
本教程详细介绍使用Python标准库turtle和tkinter实现浪漫表白程序,用户点击好哦后88颗随机流星划划过夜空;点击不要弹出提示框;代码简洁易无需第三方包,适合作为Python教学示例,需要的朋友可以参考下

大家好!今天分享一个用 Python 标准库(turtle + tkinter)实现的浪漫表白程序。点击"好哦"后,80颗流星划过夜空,每一颗都是独一无二的随机生成;点击"不要"或关闭窗口?不存在的!这是一个"霸道总裁式"的表白神器

效果预览

程序启动后弹出一个居中窗口,上面写着"亲爱的,做我女朋友好吗?"。两个按钮:“好哦"和"不要”。

  • 点击 “好哦” → 窗口关闭,全屏进入流星雨动画
  • 点击 “不要” → 弹出警告框"再给你一次机会!"
  • 点击 关闭按钮 → 弹出警告框"逃避是没有用的哦"

流星雨效果:黑色夜空中,80颗蓝白色流星从左上向右下划过,每颗流星形状、大小、速度、颜色各不相同,循环往复……

技术栈

技术说明
turtlePython 内置图形库,绘制流星形状
tkinterPython 内置 GUI 库,弹窗表白界面
random随机生成流星参数
math三角函数计算流星弧度

纯标准库,无需 pip 安装任何第三方包,开箱即用!

项目结构

流星雨表白/
├── 流星雨.py          # 主程序(完整单文件)
└── README.md

核心功能拆解

tkinter 弹窗 —— "霸道总裁"式表白

import tkinter as tk

def love():
    root = tk.Tk()
    root.title('❤')
    root.resizable(0, 0)  # 禁止调整窗口大小
    root.wm_attributes("-toolwindow", 1)  # 隐藏任务栏按钮

    # 计算居中位置
    screenwidth = root.winfo_screenwidth()
    screenheight = root.winfo_screenheight()
    widths, heights = 300, 100
    x = (screenwidth - widths) / 2
    y = (screenheight - heights) / 2
    root.geometry('%dx%d+%d+%d' % (widths, heights, x, y))

    # 表白文字
    tk.Label(root, text='亲爱的,做我女朋友好吗?', 
             width=37, font=('宋体', 12)).place(x=0, y=10)

    # 按钮
    tk.Button(root, text='好哦', width=5, height=1, command=OK).place(x=80, y=50)
    tk.Button(root, text='不要', width=5, height=1, command=NO).place(x=160, y=50)

    # 绑定关闭事件
    root.protocol('WM_DELETE_WINDOW', closeWindow)
    root.mainloop()

关键技巧:

技巧代码效果
窗口居中geometry('%dx%d+%d+%d')弹窗出现在屏幕正中央
禁止关闭protocol('WM_DELETE_WINDOW', closeWindow)拦截右上角关闭按钮
隐藏任务栏wm_attributes("-toolwindow", 1)窗口不显示在任务栏
禁止调整resizable(0, 0)窗口大小固定

按钮逻辑:

def OK():
    root.destroy()      # 销毁弹窗
    Meteors()           # 启动流星雨

def NO():
    tk.messagebox.showwarning('❤', '再给你一次机会!')

def closeWindow():
    tk.messagebox.showwarning('❤', '逃避是没有用的哦')

流星形状 —— 数学之美

每颗流星由两段直线 + 一段圆弧组成,形成一个"水滴"或"彗星"形状:

def star(self):
    t.pensize(self.outline)
    t.penup()
    t.goto(self.x, self.y)
    t.pendown()
    t.color(self.color)
    t.begin_fill()
    t.fillcolor(self.color)

    t.setheading(-30)           # 初始朝向:右下 30°
    t.right(self.t)             # 偏转随机角度 t
    t.forward(self.r)           # 前进 r(流星长度)
    t.left(self.t)              # 回正

    # 画圆弧:半径 = r * sin(t°),角度 = 180°
    t.circle(self.r * math.sin(math.radians(self.t)), 180)

    t.left(self.t)
    t.forward(self.r)           # 返回起点
    t.end_fill()

几何分析:

          起点
            \   圆弧(180°)
             \ /
              * —— 顶点
             / \
            /   \
           /     \
          终点   中点

    整体形状:"水滴"或"柳叶"
    偏转角 t 越大,流星越"胖"
    长度 r 越大,流星越长

关键公式:

圆弧半径=r×sin⁡(t°)
其中 t∈[1°,3°],r∈[50,100] 

t 很小时,sin⁡(t°)≈t°×π/180,圆弧接近半圆,流星呈细长水滴状。

流星运动 —— 循环重生

def move(self):
    if self.y >= -500:           # 还在画布内
        self.y -= self.speed     # 向下移动
        self.x += 2 * self.speed # 向右移动(斜率 2:1)
    else:
        # 超出画布,重置参数,从上方重新出现
        self.r = ra.randint(50, 100)
        self.t = ra.randint(1, 3)
        self.x = ra.randint(-2000, 1000)
        self.y = 444
        self.speed = ra.randint(5, 10)
        self.color = ra.choice(colors)

运动轨迹:

屏幕坐标系(turtle):
    y ↑
      │
  999 ├────────── 流星生成区
      │    \    \    \
  444 ├─────\────\────\───
      │      \    \    \
      │       \    \    \
      │        \    \    \
   -500├─────────\────\────\── 消失边界
      │           \    \    \
      └────────────────────────→ x
    -2000                    1000

参数范围:

参数范围作用
r50-100流星长度
t1-3偏转角度(影响胖瘦)
x-2000 ~ 1000初始水平位置
y444 ~ 999初始垂直位置
speed5-10下落速度
colorskyblue/white/cyan/aqua颜色

双缓冲动画 —— 消除闪烁

tu.tracer(0)      # 关闭自动刷新
# ... 绘制所有流星 ...
tu.update()       # 手动刷新一次

原理: tracer(0) 关闭 turtle 的自动渲染,所有绘制操作先在内存中完成,最后调用 update() 一次性显示到屏幕,避免逐帧绘制导致的闪烁。

对比:

模式代码效果
默认无 tracer每步都刷新,严重闪烁
双缓冲tracer(0) + update()批量刷新,流畅无闪烁

颜色主题切换

# 蓝色主题(默认)
colors = ['skyblue', 'white', 'cyan', 'aqua']

# 粉色主题(注释掉的浪漫选项)
# colors = ['pink', 'lightpink', 'deeppink']

只需注释/取消注释即可切换整体色调!

快速开始

步骤 1:直接运行

python 流星雨.py

无需安装任何依赖,Python 内置库即可运行!

步骤 2:自定义表白文字

tk.Label(root, text='这里写你的表白语', width=37, font=('宋体', 12))

步骤 3:调整流星数量

for i in range(100):    # 默认 100 颗,改小更流畅,改大更壮观
    Stars.append(Star())

while True:
    for i in range(100):    # 与上面保持一致
        Stars[i].move()
        Stars[i].star()

步骤 4:调整画布边界

# 流星重生边界
if self.y >= -500:        # 下边界,改小流星飞得更远

# 初始位置范围
self.x = ra.randint(-2000, 1000)   # 水平范围
self.y = ra.randint(444, 999)       # 垂直范围(生成高度)

自定义改造指南

改造 1:添加背景音乐

import pygame

pygame.mixer.init()
pygame.mixer.music.load("romantic.mp3")
pygame.mixer.music.play(-1)  # 循环播放

改造 2:流星拖尾效果

def move(self):
    # 保存历史位置
    self.trail.append((self.x, self.y))
    if len(self.trail) > 5:
        self.trail.pop(0)

    # 绘制拖尾
    for i, (tx, ty) in enumerate(self.trail):
        alpha = i / len(self.trail)
        t.pensize(self.outline * alpha)
        t.goto(tx, ty)

改造 3:添加星星背景

def draw_background():
    t.penup()
    for _ in range(200):
        x = ra.randint(-1000, 1000)
        y = ra.randint(-500, 500)
        t.goto(x, y)
        t.dot(2, 'white')  # 画小星星

改造 4:表白成功后的文字

def OK():
    root.destroy()
    # 显示成功文字
    success = tk.Tk()
    tk.Label(success, text='❤️ 余生请多指教 ❤️', 
             font=('华文行楷', 24), fg='red').pack()
    success.after(2000, Meteors)  # 2秒后进入流星雨
    success.mainloop()

改造 5:多行表白语

messages = [
    '遇见你,是我最美的意外',
    '愿余生与你,星河滚烫',
    '做我女朋友好吗?'
]

for i, msg in enumerate(messages):
    tk.Label(root, text=msg, font=('宋体', 12)).place(x=0, y=10 + i*20)

完整源码

import turtle as tu
import random as ra
import tkinter as tk
import math

def Meteors():
    tu.setup(1.0, 1.0)
    tu.screensize(1.0, 1.0)
    tu.bgcolor('black')
    tu.title("流星雨")
    t = tu.Pen()
    t.hideturtle()
    colors = ['skyblue', 'white', 'cyan', 'aqua']

    class Star():
        def __init__(self):
            self.r = ra.randint(50,100)
            self.t = ra.randint(1,3)
            self.x = ra.randint(-2000,1000)
            self.y = ra.randint(444, 999)
            self.speed = ra.randint(5,10)
            self.color = ra.choice(colors)
            self.outline = 1

        def star(self):
            t.pensize(self.outline)
            t.penup()
            t.goto(self.x,self.y)
            t.pendown()
            t.color(self.color)
            t.begin_fill()
            t.fillcolor(self.color)
            t.setheading(-30)
            t.right(self.t)
            t.forward(self.r)
            t.left(self.t)
            t.circle(self.r*math.sin(math.radians(self.t)),180)
            t.left(self.t)
            t.forward(self.r)
            t.end_fill()

        def move(self):
            if self.y >= -500:
                self.y -= self.speed
                self.x += 2*self.speed
            else:
                self.r = ra.randint(50,100)
                self.t = ra.randint(1,3)
                self.x = ra.randint(-2000,1000)
                self.y = 444
                self.speed = ra.randint(5,10)
                self.color = ra.choice(colors)
                self.outline = 1

    Stars = []
    for i in range(100):
        Stars.append(Star())
    while True:
        tu.tracer(0)
        t.clear()
        for i in range(100):
            Stars[i].move()
            Stars[i].star()
        tu.update()
    tu.mainloop()

def love():
    root = tk.Tk()
    root.title('❤')
    root.resizable(0, 0)
    root.wm_attributes("-toolwindow", 1)
    screenwidth = root.winfo_screenwidth()
    screenheight = root.winfo_screenheight()
    widths = 300
    heights = 100
    x = (screenwidth - widths) / 2
    y = (screenheight - heights) / 2
    root.geometry('%dx%d+%d+%d' % (widths, heights, x, y))
    tk.Label(root, text='亲爱的,做我女朋友好吗?', width=37, font=('宋体', 12)).place(x=0, y=10)

    def OK():
        root.destroy()
        Meteors()
    def NO():
        tk.messagebox.showwarning('❤', '再给你一次机会!')
    def closeWindow():
        tk.messagebox.showwarning('❤', '逃避是没有用的哦')

    tk.Button(root, text='好哦', width=5, height=1, command=OK).place(x=80, y=50)
    tk.Button(root, text='不要', width=5, height=1, command=NO).place(x=160, y=50)
    root.protocol('WM_DELETE_WINDOW', closeWindow)
    root.mainloop()

if __name__ == "__main__":
    love()

总结

本项目展示了 Python 标准库的强大表现力:

  • tkinter:零依赖 GUI,弹窗交互
  • turtle:简单绘图,适合教学与演示
  • 对象封装Star 类管理每颗流星状态
  • 双缓冲tracer(0) + update() 流畅动画
  • 事件绑定:拦截关闭按钮,"强制"表白

以上就是Python turtle打造一个浪漫流星雨表白程序的详细内容,更多关于Python turtle流星雨表白程序的资料请关注脚本之家其它相关文章!

相关文章

  • python 实现从高分辨图像上抠取图像块

    python 实现从高分辨图像上抠取图像块

    今天小编就为大家分享一篇python 实现从高分辨图像上抠取图像块,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • Python中创建相关系数矩阵的方法小结

    Python中创建相关系数矩阵的方法小结

    相关系数矩阵是一种用于衡量变量之间关系的重要工具,本文将介绍在 Python 中创建相关系数矩阵的不同方法,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • 使用Python将图片转正方形的两种方法实例代码详解

    使用Python将图片转正方形的两种方法实例代码详解

    这篇文章主要介绍了使用Python将图片转正方形的两种方法,本文通过实例代码给大家给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Python边遍历边删除列表元素的几种方法

    Python边遍历边删除列表元素的几种方法

    在 Python 中,边遍历边删除列表元素通常是一个不推荐的操作,因为它会改变列表的大小,可能会导致一些意料之外的行为,例如,元素被删除后,列表的索引会发生变化,可能导致漏掉某些元素或者遍历到错误的位置,所以本文介绍了Python边遍历边删除列表元素的几种方法
    2024-12-12
  • Python深度学习pytorch神经网络汇聚层理解

    Python深度学习pytorch神经网络汇聚层理解

    通常当我们处理图像时,我们希望逐渐降低隐藏表示的空间分辨率,聚集信息,这样随着我们在神经网络层叠的上升,每个神经元对其敏感的感受野(输入)就越大
    2021-10-10
  • python实现文件的分割与合并

    python实现文件的分割与合并

    这篇文章主要为大家详细介绍了python实现文件的分割与合并,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • python如何设置静态变量

    python如何设置静态变量

    在本篇内容里小编给大家整理的是一篇关于python如何设置静态变量的相关文章,有兴趣的朋友们可以参考下。
    2020-09-09
  • 使用OpenCV校准鱼眼镜头的方法

    使用OpenCV校准鱼眼镜头的方法

    这篇文章主要介绍了使用OpenCV校准鱼眼镜头的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Python可视化神器pyecharts绘制饼状图

    Python可视化神器pyecharts绘制饼状图

    这篇文章主要介绍了Python可视化神器pyecharts绘制饼状图,饼图是用圆形及圆内扇形的角度来表示数值大小的图形,它主要用于表示一个样本中各组成部分的数据占全部数据的比例
    2022-07-07
  • pytorch获取vgg16-feature层输出的例子

    pytorch获取vgg16-feature层输出的例子

    今天小编就为大家分享一篇pytorch获取vgg16-feature层输出的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08

最新评论