Загрузка данных
import pygame
import math
import random
import sys
pygame.init()
WIDTH, HEIGHT = 900, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("I love you Karina ❤")
clock = pygame.time.Clock()
# Цвета
BLACK = (8, 0, 15)
PINK = (255, 105, 180)
HOT_PINK = (255, 20, 100)
DEEP = (140, 0, 60)
WHITE = (255, 255, 255)
GOLD = (255, 220, 150)
# Шрифты
try:
font_name = pygame.font.SysFont("georgia", 56, bold=True, italic=True)
font_sign = pygame.font.SysFont("georgia", 22, italic=True)
except Exception:
font_name = pygame.font.Font(None, 56)
font_sign = pygame.font.Font(None, 22)
LINE1 = "I love you"
LINE2 = "Karina"
# ---------- Форма сердца (параметрическая) ----------
def heart_point(t, scale):
"""t от 0 до tau. Возвращает (x, y) для контура сердца."""
x = 16 * math.sin(t) ** 3
y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
return x * scale, -y * scale
def build_heart_points(scale, steps=200):
return [heart_point(2 * math.pi * i / steps, scale) for i in range(steps + 1)]
# ---------- Частицы-искры вокруг сердца ----------
class Spark:
def __init__(self, cx, cy):
self.cx, self.cy = cx, cy
self.reset()
def reset(self):
angle = random.uniform(0, math.tau)
radius = random.uniform(220, 340)
self.x = self.cx + math.cos(angle) * radius
self.y = self.cy + math.sin(angle) * radius
self.size = random.uniform(1, 3)
self.alpha = random.randint(60, 200)
self.angle = angle
self.speed = random.uniform(0.003, 0.01)
def update(self):
self.angle += self.speed
radius = math.hypot(self.x - self.cx, self.y - self.cy)
self.x = self.cx + math.cos(self.angle) * radius
self.y = self.cy + math.sin(self.angle) * radius
self.alpha -= 0.3
if self.alpha <= 0:
self.reset()
sparks = [Spark(WIDTH // 2, HEIGHT // 2 - 40) for _ in range(80)]
def draw_glow_text(target, text, font, center, color, glow_color, glow_radius=3):
"""Текст с неоновым свечением."""
for dx in range(-glow_radius, glow_radius + 1):
for dy in range(-glow_radius, glow_radius + 1):
if dx == 0 and dy == 0:
continue
s = font.render(text, True, glow_color)
s.set_alpha(120)
target.blit(s, (center[0] - s.get_width() // 2 + dx,
center[1] - s.get_height() // 2 + dy))
s = font.render(text, True, color)
target.blit(s, (center[0] - s.get_width() // 2,
center[1] - s.get_height() // 2))
# ---------- Главный цикл ----------
t = 0
running = True
# Фазы анимации:
# 0..180 — рисуется контур сердца
# 180..300 — сердце заполняется и пульсирует
# 300+ — внутри появляется текст
DRAW_END = 180
FILL_END = 300
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
# Лёгкий след вместо полной очистки — красивое размытие
trail = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
trail.fill((8, 0, 15, 60))
screen.blit(trail, (0, 0))
cx, cy = WIDTH // 2, HEIGHT // 2 - 40
# --- Искры на фоне ---
for s in sparks:
s.update()
surf = pygame.Surface((6, 6), pygame.SRCALPHA)
pygame.draw.circle(surf, (*PINK, int(s.alpha)), (3, 3), int(s.size))
screen.blit(surf, (s.x - 3, s.y - 3))
# --- Пульсация ---
if t < FILL_END:
scale = 11
else:
beat = (t - FILL_END) / 60
# двойной "удар" как у настоящего сердца
pulse = math.sin(beat * 6) * 0.5 + math.sin(beat * 12) * 0.5
scale = 11 + pulse * 0.25
points = build_heart_points(scale)
heart_surf = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
heart_points_screen = [(cx + x, cy + y) for x, y in points]
# --- Фаза 1: прорисовка контура ---
if t < DRAW_END:
progress = t / DRAW_END
visible = int(progress * (len(points) - 1))
if visible > 1:
# Свечение контура
for w, a in [(10, 30), (6, 60), (3, 120)]:
s = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
pygame.draw.lines(s, (*HOT_PINK, a), False,
heart_points_screen[:visible], w)
screen.blit(s, (0, 0))
# Яркая линия
pygame.draw.lines(screen, WHITE, False, heart_points_screen[:visible], 2)
# --- Фаза 2: заполнение ---
elif t < FILL_END:
fill_progress = (t - DRAW_END) / (FILL_END - DRAW_END)
# Пульсирующее свечение вокруг
glow_color = (
int(200 + 55 * math.sin(t * 0.15)),
int(20 + 40 * math.sin(t * 0.15)),
int(80 + 40 * math.sin(t * 0.15)),
)
for w, a in [(40, 25), (25, 45), (15, 80), (8, 130)]:
s = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
pygame.draw.polygon(s, (*glow_color, a), heart_points_screen)
s = pygame.transform.smoothscale(s, (WIDTH, HEIGHT))
screen.blit(s, (0, 0))
# Само сердце — плавно появляется
body = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
pygame.draw.polygon(body, (*HOT_PINK, int(255 * fill_progress)),
heart_points_screen)
screen.blit(body, (0, 0))
# Контур ярко
pygame.draw.lines(screen, WHITE, False, heart_points_screen, 3)
# --- Фаза 3: всё + текст ---
else:
glow_color = (
int(200 + 55 * math.sin(t * 0.15)),
int(20 + 40 * math.sin(t * 0.15)),
int(80 + 40 * math.sin(t * 0.15)),
)
for w, a in [(40, 25), (25, 45), (15, 80), (8, 130)]:
s = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
pygame.draw.polygon(s, (*glow_color, a), heart_points_screen)
screen.blit(s, (0, 0))
body = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
pygame.draw.polygon(body, HOT_PINK, heart_points_screen)
screen.blit(body, (0, 0))
pygame.draw.lines(screen, WHITE, False, heart_points_screen, 3)
# --- Текст внутри ---
text_progress = min((t - FILL_END) / 90, 1.0) # 1.5 сек на текст
line1_chars = int(len(LINE1) * text_progress)
line2_chars = int(len(LINE2) * max(0, text_progress - 0.4) / 0.6)
shown1 = LINE1[:line1_chars]
shown2 = LINE2[:line2_chars]
# мягкое мерцание оттенка
shimmer = 0.5 + 0.5 * math.sin(t * 0.1)
text_color = (
255,
int(200 + 40 * shimmer),
int(220 + 30 * shimmer),
)
if shown1:
draw_glow_text(screen, shown1, font_name,
(cx, cy - 30), text_color, (255, 100, 180), 4)
if shown2:
draw_glow_text(screen, shown2, font_name,
(cx, cy + 45), text_color, (255, 100, 180), 4)
# Подпись снизу
if text_progress >= 1.0:
sign_progress = min((t - FILL_END - 90) / 60, 1.0)
if sign_progress > 0:
s = font_sign.render("— навсегда твой ❤", True, GOLD)
s.set_alpha(int(255 * sign_progress))
screen.blit(s, (WIDTH // 2 - s.get_width() // 2, HEIGHT - 60))
pygame.display.flip()
t += 1
clock.tick(60)
pygame.quit()
sys.exit()