import pygame
import numpy as np
import sys
import random
from math import sin, cos, pi, sqrt
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
pygame.display.set_caption("师徒契约动态仪式")
# 状态定义
STAGE_QUESTION = 0
STAGE_HEART_FORMATION = 1
STAGE_FIREWORKS = 2
STAGE_CHRISTMAS_TREE = 3
STAGE_BLESSINGS = 4
# 全局状态
current_stage = STAGE_QUESTION
particles = []
selected = None
scale = 0.0
tree_height = 0
click_ready = True
last_click_time = 0
# 验证函数
def verify_resolution():
assert screen.get_size() == (800, 600), "分辨率必须800x600"
def verify_particle_count():
assert len(particles) == 3000, f"粒子数量必须3000个(当前{len(particles)}个)"
def verify_heart_shape():
t = pi/2
x = 16*(sin(t)**3)
y = -(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t))
assert abs(x-16) < 0.01 and abs(y+8) < 0.01, "心形参数方程错误"
def verify_dual_text():
assert "桃李满天下" in blessings and "祝你平安顺遂" in blessings, "缺失关键祝福语"
# 初始化粒子
def init_particles():
global particles
particles = []
for i in range(3000):
if current_stage == STAGE_QUESTION:
# 初始随机分布
particles.append([
random.randint(50, 750),
random.randint(50, 550),
0, 0, # 速度
random.randint(100, 255), # R
random.randint(0, 50), # G
random.randint(0, 50) # B
])
elif current_stage == STAGE_HEART_FORMATION:
# 为爱心形成准备
t = i * 0.002 * pi
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
particles.append([
random.randint(50, 750), # 初始随机位置
random.randint(50, 550),
(x*15+400 - random.randint(50, 750))*0.05, # 目标速度X
(y*15+250 - random.randint(50, 550))*0.05, # 目标速度Y
255, 20, 20 # 红色渐变
])
init_particles()
# 圣诞树绘制参数
tree_params = [
(400, 500, 100, 20), # 树干
(400, 350, 150, 30), # 最底层
(400, 280, 120, 25),
(400, 220, 90, 20),
(400, 170, 60, 15),
(400, 130, 30, 10) # 顶层
]
# 烟花效果
fireworks = []
star_colors = [(255,215,0), (173,216,230), (255,182,193)]
def create_firework(x, y):
for _ in range(200):
angle = random.uniform(0, 2*pi)
speed = random.uniform(2, 5)
life = random.randint(30, 60)
fireworks.append([
x, y,
cos(angle)*speed, sin(angle)*speed,
random.choice(star_colors),
life
])
# 初始化
blessings = ["桃李满天下", "祝你平安顺遂", "春风化雨润桃李", "师恩如海永铭记"]
current_blessing = 0
heart_complete = False
while True:
current_time = pygame.time.get_ticks()
# 清屏
screen.fill((0, 0, 0))
# 阶段处理
if current_stage == STAGE_QUESTION:
# 显示问题和按钮
font = pygame.font.SysFont(None, 48)
screen.blit(font.render("你是我永远的老师吗?", True, (255, 215, 0)), (200, 150))
# 是按钮(固定位置)
yes_btn = pygame.draw.rect(screen, (0, 180, 0), (250, 300, 120, 60), border_radius=15)
screen.blit(font.render("是", True, (255, 255, 255)), (295, 315))
# 否按钮(随机移动)
no_x = 450 + 150 * sin(current_time * 0.003)
no_btn = pygame.draw.rect(screen, (180, 0, 0), (no_x, 300, 120, 60), border_radius=15)
screen.blit(font.render("否", True, (255, 255, 255)), (no_x+40, 315))
# 粒子行为
for p in particles:
if selected == "否":
# 随机运动并缩小
p[2] += (random.random() - 0.5) * 0.8
p[3] += (random.random() - 0.5) * 0.8
p[0] += p[2]
p[1] += p[3]
size = max(0.2, 3 - (current_time - last_click_time) * 0.002)
if size > 0.5:
pygame.draw.circle(screen, (p[3], p[4], p[5]), (int(p[0]), int(p[1])), int(size))
else:
# 正常显示
pygame.draw.circle(screen, (p[3], p[4], p[5]), (int(p[0]), int(p[1])), 2)
elif current_stage == STAGE_HEART_FORMATION:
# 粒子汇聚成爱心
all_at_target = True
for i, p in enumerate(particles):
# 心形目标位置
t = i * 0.002 * pi
target_x = 16 * (sin(t) ** 3) * 15 + 400
target_y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)) * 15 + 250
# 平滑移动到目标
dx = target_x - p[0]
dy = target_y - p[1]
dist = sqrt(dx*dx + dy*dy)
if dist > 1:
all_at_target = False
p[0] += dx * 0.05
p[1] += dy * 0.05
# 绘制粒子(随汇聚过程变大)
size = 1.5 + min(3.0, (1 - dist/300) * 3)
pygame.draw.circle(screen, (255, 50, 50), (int(p[0]), int(p[1])), int(size))
# 完全形成后自动进入下一阶段
if all_at_target and not heart_complete:
heart_complete = True
last_click_time = current_time
elif current_stage == STAGE_FIREWORKS:
# 显示爱心作为烟花中心
for p in particles:
pygame.draw.circle(screen, (255, 50, 50), (int(p[0]), int(p[1])), 2)
# 烟花效果
if current_time - last_click_time < 2000:
if random.random() < 0.2:
create_firework(random.randint(300, 500), random.randint(200, 300))
# 更新烟花
for fw in fireworks[:]:
fw[0] += fw[2]
fw[1] += fw[3]
fw[5] -= 1
if fw[5] > 0:
pygame.draw.circle(screen, fw[4], (int(fw[0]), int(fw[1])), max(1, fw[5]//10))
else:
fireworks.remove(fw)
elif current_stage == STAGE_CHRISTMAS_TREE:
# 绘制圣诞树(从上到下生长)
for i, (x, y, width, stem) in enumerate(tree_params):
if i == 0: # 树干
if tree_height > y:
pygame.draw.rect(screen, (101, 67, 33), (x-10, y, 20, 500-y))
else:
target_y = y - (i-1)*30
if tree_height > target_y:
pygame.draw.polygon(screen, (34, 139, 34), [
(x - width//2, target_y),
(x, target_y - stem),
(x + width//2, target_y)
])
# 添加装饰球
if current_time % 1000 < 500:
pygame.draw.circle(screen, (255, 215, 0), (x, target_y-10), 5)
# 树生长动画
if tree_height < 500:
tree_height += 3
else:
# 树完成后显示文字提示
font = pygame.font.SysFont(None, 36)
screen.blit(font.render("点击继续", True, (255, 255, 255)), (350, 520))
elif current_stage == STAGE_BLESSINGS:
# 显示祝福语
font = pygame.font.SysFont(None, 64)
text = font.render(blessings[current_blessing], True, (255, 215, 0))
screen.blit(text, (400 - text.get_width()//2, 250))
# 添加闪烁星星
for _ in range(50):
x = random.randint(0, 800)
y = random.randint(0, 600)
size = random.choice([1, 2])
alpha = 128 + abs(int(sin(current_time*0.005)*127))
pygame.draw.circle(screen, (alpha, alpha, alpha), (x, y), size)
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and click_ready:
if current_stage == STAGE_QUESTION:
# 检查按钮点击
if yes_btn.collidepoint(event.pos):
selected = "是"
current_stage = STAGE_HEART_FORMATION
init_particles()
click_ready = False
elif no_btn.collidepoint(event.pos):
selected = "否"
last_click_time = current_time
elif current_stage == STAGE_HEART_FORMATION and heart_complete:
if current_time - last_click_time > 1000:
current_stage = STAGE_FIREWORKS
last_click_time = current_time
elif current_stage == STAGE_FIREWORKS and current_time - last_click_time > 2000:
current_stage = STAGE_CHRISTMAS_TREE
tree_height = 0
elif current_stage == STAGE_CHRISTMAS_TREE and tree_height >= 500:
current_stage = STAGE_BLESSINGS
elif current_stage == STAGE_BLESSINGS:
current_blessing = (current_blessing + 1) % len(blessings)
click_ready = False
# 点击冷却
if not click_ready and current_time - last_click_time > 300:
click_ready = True
# 验证关键要求
verify_resolution()
if current_stage >= STAGE_HEART_FORMATION:
verify_particle_count()
verify_heart_shape()
if current_stage >= STAGE_BLESSINGS:
verify_dual_text()
pygame.display.flip()
clock.tick(60)