預覽
代碼結構概述
這段代碼使用了 pygame
庫來創建一個動態的圖形窗口,繪制一個心形圖案,并在其中顯示閃爍的文本。代碼主要分為以下幾個部分:
- 初始化和設置
- 心形曲線的計算
- 粒子類的定義
- 生成粒子
- 文本設置
- 主循環
1. 初始化和設置
import pygame
import random
import math
import os# 初始化pygame
pygame.init()# 屏幕尺寸
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Dynamic Particle Heart")
- 導入庫:首先導入所需的庫,
pygame
用于圖形處理,random
用于生成隨機數,math
用于數學計算。 - 初始化pygame:調用
pygame.init()
來初始化所有的 pygame 模塊。 - 設置屏幕尺寸:定義窗口的寬度和高度,并創建一個窗口。
- 設置窗口標題:使用
set_caption
設置窗口的標題。
2. 顏色定義
# 顏色定義
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128) # 紫色的RGB值
- 定義顏色:使用 RGB 顏色模式定義了白色、黑色和紫色。
3. 心形曲線的計算
# 心形方程
def heart_curve(t):x = 16 * math.sin(t) ** 3y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)return x, y
- 心形方程:定義了一個函數
heart_curve
,接受一個參數t
(角度),并計算心形曲線的 x 和 y 坐標。這個公式通過三角函數生成心形的坐標。
4. 計算心形的最大寬度和高度
def get_heart_dimensions():max_x, min_x, max_y, min_y = -float('inf'), float('inf'), -float('inf'), float('inf')for i in range(0, 360, 1):angle_rad = math.radians(i)x, y = heart_curve(angle_rad)if x > max_x: max_x = xif x < min_x: min_x = xif -y > max_y: max_y = -y # 注意:這里取負是因為pygame坐標系y軸向下if -y < min_y: min_y = -ywidth = max_x - min_xheight = max_y - min_yreturn width, height
- 計算心形的尺寸:這個函數遍歷從 0 到 360 度的每個角度,計算心形的坐標,并找到心形的最大和最小 x、y 值,以便計算出心形的寬度和高度。
5. 粒子類的定義
class Particle:def __init__(self, x, y):self.x = xself.y = yself.size = random.randint(2, 5)self.color = PURPLEself.angle = random.uniform(0, math.pi * 2)self.speed = random.uniform(1, 3)self.lifetime = random.randint(50, 100)def move(self):self.x += math.sin(self.angle) * self.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.lifetime -= 1if self.size <= 0 or self.lifetime <= 0:self.reset()def reset(self):angle_rad = random.uniform(0, math.pi * 2)x, y = heart_curve(angle_rad)self.x = x * scale_factor + WIDTH // 2self.y = -y * scale_factor + HEIGHT // 2self.size = random.randint(2, 5)self.angle = random.uniform(0, math.pi * 2)self.speed = random.uniform(1, 3)self.lifetime = random.randint(50, 100)def draw(self, screen):s = pygame.Surface((self.size * 2, self.size * 2), pygame.SRCALPHA)pygame.draw.circle(s, (*self.color[:3], self.lifetime * 2.55), (self.size, self.size), self.size)screen.blit(s, (self.x - self.size, self.y - self.size))
- 粒子類:定義了一個
Particle
類,表示一個粒子。- 初始化方法:設置粒子的初始位置、大小、顏色、角度、速度和生命周期。
- 移動方法:更新粒子的位置,減少大小和生命周期。如果粒子的大小或生命周期小于等于0,則重置粒子。
- 重置方法:隨機生成新的位置、大小、角度和速度。
- 繪制方法:在屏幕上繪制粒子。
6. 生成粒子
# 生成初始粒子
particles = [Particle(random.uniform(-width/2, width/2) * scale_factor + WIDTH // 2,random.uniform(-height/2, height/2) * scale_factor + HEIGHT // 2) for _ in range(10000)]
- 創建粒子:生成 10,000 個粒子,并將它們存儲在
particles
列表中。每個粒子的位置是隨機的,基于心形的尺寸和縮放因子。
7. 文本設置
# 字體設置
font_size = 48 # 字體大小
font_path = "./test.ttf" # 確保字體文件在當前目錄下
font = pygame.font.Font(font_path, font_size) # 使用指定字體
text = "多想再見你 哪怕一眼匆匆就別離"
text_surface = font.render(text, True, WHITE) # 渲染文本
text_rect = text_surface.get_rect(center=(WIDTH // 2, HEIGHT // 2)) # 文本居中
- 設置字體:定義字體大小和路徑,渲染文本并計算文本的矩形區域,以便后續居中顯示。
8. 主循環
# 主循環
running = True
clock = pygame.time.Clock()
blink_counter = 0
blink_rate = 10 # 每10幀閃爍一次while running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falsescreen.fill(BLACK)# 繪制心形曲線points = []for i in range(0, 360, 1):angle_rad = math.radians(i)x, y = heart_curve(angle_rad)x = x * scale_factor + WIDTH // 2y = -y * scale_factor + HEIGHT // 2points.append((x, y))pygame.draw.lines(screen, PURPLE, False, points, 2) # 使用lines代替polygon# 更新和繪制粒子for particle in particles:particle.move()particle.draw(screen)# 繪制閃爍的文本if blink_counter % blink_rate < blink_rate / 2: # 每隔一段時間閃爍# 隨機生成顏色random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))text_surface = font.render(text, True, random_color) # 渲染文本screen.blit(text_surface, text_rect) # 繪制文本blink_counter += 1pygame.display.flip()clock.tick(60)pygame.quit()
- 主循環:程序的核心部分。
- 事件處理:檢查是否有退出事件。
- 清屏:用黑色填充屏幕。
- 繪制心形曲線:計算心形的每個點并繪制。
- 更新和繪制粒子:讓每個粒子移動并繪制在屏幕上。
- 繪制閃爍的文本:每隔一定的幀數,隨機生成文本顏色并繪制文本。
- 更新顯示:調用
pygame.display.flip()
更新屏幕,clock.tick(60)
控制幀率為 60 幀每秒。
9. 退出
pygame.quit()
- 退出程序:當主循環結束后,調用
pygame.quit()
關閉窗口并清理資源。
總結
這段代碼結合了圖形繪制、動畫效果和文本渲染,展示了如何使用 pygame
創建一個動態的視覺效果。通過理解每個部分的功能,你可以更好地掌握 pygame
的使用,并進行更復雜的項目開發。
完整代碼
import pygame
import random
import math
import os# 初始化pygame
pygame.init()# 屏幕尺寸
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Dynamic Particle Heart")# 顏色定義
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128) # 紫色的RGB值# 心形方程
def heart_curve(t):x = 16 * math.sin(t) ** 3y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)return x, y# 計算心形的最大寬度和高度
def get_heart_dimensions():max_x, min_x, max_y, min_y = -float('inf'), float('inf'), -float('inf'), float('inf')for i in range(0, 360, 1):angle_rad = math.radians(i)x, y = heart_curve(angle_rad)if x > max_x: max_x = xif x < min_x: min_x = xif -y > max_y: max_y = -y # 注意:這里取負是因為pygame坐標系y軸向下if -y < min_y: min_y = -ywidth = max_x - min_xheight = max_y - min_yreturn width, heightwidth, height = get_heart_dimensions()
scale_factor = min(WIDTH / (width * 1.2), HEIGHT / (height * 1.2)) # 增加一點額外的空間# 粒子類
class Particle:def __init__(self, x, y):self.x = xself.y = yself.size = random.randint(2, 5)self.color = PURPLEself.angle = random.uniform(0, math.pi * 2)self.speed = random.uniform(1, 3)self.lifetime = random.randint(50, 100)def move(self):self.x += math.sin(self.angle) * self.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.lifetime -= 1if self.size <= 0 or self.lifetime <= 0:self.reset()def reset(self):angle_rad = random.uniform(0, math.pi * 2)x, y = heart_curve(angle_rad)self.x = x * scale_factor + WIDTH // 2self.y = -y * scale_factor + HEIGHT // 2self.size = random.randint(2, 5)self.angle = random.uniform(0, math.pi * 2)self.speed = random.uniform(1, 3)self.lifetime = random.randint(50, 100)def draw(self, screen):s = pygame.Surface((self.size * 2, self.size * 2), pygame.SRCALPHA)pygame.draw.circle(s, (*self.color[:3], self.lifetime * 2.55), (self.size, self.size), self.size)screen.blit(s, (self.x - self.size, self.y - self.size))# 生成初始粒子
particles = [Particle(random.uniform(-width/2, width/2) * scale_factor + WIDTH // 2,random.uniform(-height/2, height/2) * scale_factor + HEIGHT // 2) for _ in range(10000)]# 字體設置
font_size = 48 # 字體大小
font_path = "./test.ttf" # 確保字體文件在當前目錄下
font = pygame.font.Font(font_path, font_size) # 使用指定字體
text = "多想再見你 哪怕一眼匆匆就別離"
text_surface = font.render(text, True, WHITE) # 渲染文本
text_rect = text_surface.get_rect(center=(WIDTH // 2, HEIGHT // 2)) # 文本居中# 主循環
running = True
clock = pygame.time.Clock()
blink_counter = 0
blink_rate = 10 # 每10幀閃爍一次while running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falsescreen.fill(BLACK)# 繪制心形曲線points = []for i in range(0, 360, 1):angle_rad = math.radians(i)x, y = heart_curve(angle_rad)x = x * scale_factor + WIDTH // 2y = -y * scale_factor + HEIGHT // 2points.append((x, y))pygame.draw.lines(screen, PURPLE, False, points, 2) # 使用lines代替polygon# 更新和繪制粒子for particle in particles:particle.move()particle.draw(screen)# 繪制閃爍的文本if blink_counter % blink_rate < blink_rate / 2: # 每隔一段時間閃爍# 隨機生成顏色random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))text_surface = font.render(text, True, random_color) # 渲染文本screen.blit(text_surface, text_rect) # 繪制文本blink_counter += 1pygame.display.flip()clock.tick(60)pygame.quit()
補充解說
讓我詳細解釋這個代碼的運行邏輯:
- 初始化階段:
# 初始化基本設置
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))# 心形方程定義
def heart_curve(t):x = 16 * math.sin(t) ** 3y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)return x, y
- 粒子系統:
class Particle:def __init__(self, x, y):# 初始化粒子位置、大小、速度等屬性self.x = xself.y = yself.size = random.randint(2, 5)self.angle = random.uniform(0, math.pi * 2)self.speed = random.uniform(1, 3)self.lifetime = random.randint(50, 100)
- 粒子移動和重置邏輯:
def move(self):# 移動粒子self.x += math.sin(self.angle) * self.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.lifetime -= 1# 當粒子生命周期結束時重置if self.size <= 0 or self.lifetime <= 0:self.reset()def reset(self):# 重置粒子到心形曲線上的隨機位置angle_rad = random.uniform(0, math.pi * 2)x, y = heart_curve(angle_rad)self.x = x * scale_factor + WIDTH // 2self.y = -y * scale_factor + HEIGHT // 2# 重置其他屬性
運行流程:
-
初始化:
- 創建10000個隨機分布的粒子
- 每個粒子有隨機的位置、大小、速度和生命周期
-
主循環:
while running:screen.fill(BLACK) # 清空屏幕# 繪制心形輪廓# 更新和繪制所有粒子for particle in particles:particle.move()particle.draw(screen)
- 粒子運動機制:
- 每個粒子按照自己的角度和速度移動
- 當粒子生命周期結束時,通過
reset()
函數重生在心形曲線上 - 這創造了粒子似乎在"靠近"心形的視覺效果
關于"靠近"效果的實現:
- 這個效果是通過粒子的生命周期系統實現的
- 當粒子消失時,它們會在心形曲線上重生(
reset()
函數) - 隨著時間推移,越來越多的粒子會重生在心形曲線上
- 這創造了粒子群似乎在向心形聚集的視覺效果
核心實現在reset()
函數:
def reset(self):angle_rad = random.uniform(0, math.pi * 2)x, y = heart_curve(angle_rad) # 在心形曲線上選擇新位置
這不是真正的"靠近"運動,而是通過粒子的死亡和重生機制,逐漸在心形輪廓上形成粒子群,創造出視覺上的聚集效果。