python爱好者,业余时间写个模拟烟花小程序。
import pygame,random,math,time,sys
#========================================================
# 设置屏幕大小、背景色
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
BG_COLOR = (0,0,0)
# 设置烟花参数
FIREWORKS_COUNT = 8 #屏幕上同时出现的烟花个数
PARTICLES_COUNT = 50 #每个烟花爆炸的微粒个数
VELOCITY_MIN,VELOCITY_MAX = 5,8
GRAVITY = 0.05 #模拟重力减速度
SIZE_MIN, SIZE_MAX= 1,2 #烟花半径范围
P_size_min,P_size_max = 1,2 #烟花微粒的最大半径
LIGHT_SIZE_MIN,LIGHT_SIZE_MAX = 10,20 #烟花爆炸瞬间光斑半径
PARTICLE_MOVE_LIMITE = 100 #爆炸粒子移动的最远距离(超过距离则删除)
#背景图片定义
background_filename = 'night.jpg'
FRAME = 60 #设置画面刷新率
#========================================================
class Firework:
"""定义烟花类"""
def __init__(self, x, y):
self.x = x
self.y = y
#随机烟花的半径、颜色、水平分速度、竖直分速度
self.size = random.randint(SIZE_MIN,SIZE_MAX)
self.color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
self.velocity_y = random.uniform(VELOCITY_MIN,VELOCITY_MAX)
self.gravity = GRAVITY
#初始化本烟花的微粒和爆炸状态
self.particles = []
self.exploded = False
#随机产生一个爆炸高度,范围是距离顶部50至三分之一屏高
self.Rand_height = random.randint(50,int(SCREEN_HEIGHT/2))
def explode(self,screen):
"""爆炸函数,产生微粒"""
self.exploded = True
#在爆炸处生成一个转瞬即逝的直径为LIGHT_SIZE的闪光
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), random.randint(LIGHT_SIZE_MIN,LIGHT_SIZE_MAX))
for _ in range(PARTICLES_COUNT):
angle = random.uniform(0, 2 * math.pi) # 随机角度
speed = random.uniform(5, 7) # 随机速度
particle_x = self.x + speed * math.cos(angle) # 计算粒子的x坐标
particle_y = self.y + speed * math.sin(angle) # 计算粒子的y坐标
particle = Particle(particle_x, particle_y, screen) # 生成粒子
self.particles.append(particle) # 将粒子添加到烟花的粒子列表中
def draw(self, screen):
"""绘制烟花或者微粒"""
if not self.exploded:
#若未爆炸,则在当前坐标画圆
self.rect = pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.size)
else:
#若已爆炸,则画爆炸微粒
for particle in self.particles:
particle.draw(screen)
particle.update() #此句不用也可以,微粒的速度会慢一点
def update(self,screen):
"""更新烟花位置,或者更新微粒"""
Label = False # 定义一个标签,反映烟花爆炸后,微粒移动距离是否超过100单位
if not self.exploded:
# 烟花如果未爆炸,则竖直上升,上升的速度越来越慢
self.y -= self.velocity_y #velocity_y为上升速度
self.velocity_y -= GRAVITY
self.rect.y = self.y
# 如果上升高度达到随机的爆炸高度,则爆炸
if self.rect.y <= self.Rand_height or \
self.velocity_y <= 0: # 或者烟花到达最高点(上升速度降为0)时,烟花爆炸
self.explode(screen)
elif self.rect.y > SCREEN_HEIGHT: # 如果烟花到达屏幕下沿,则标记Label(删除该烟花)。
Label = True
else:
# 烟花若已爆炸,逐个扫描微粒的移动距离
for particle in self.particles:
particle.update()
if particle.move_distance() >= PARTICLE_MOVE_LIMITE: #若移动距离超过限值,则移除该微粒
self.particles.remove(particle)
Label = True #若微粒移动超过100,返回此标签(为了删除此烟花)
break
return Label
#=============================================================
class Particle:
"""定义粒子类"""
def __init__(self, x, y,screen):
self.x = x
self.y = y
self.x0, self.y0 = x, y #记录初始坐标
self.color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
self.size = random.randint(P_size_min,P_size_max)
self.velocity_y = random.uniform(-1, -0.6) * random.random() # 粒子的竖直速度在-0.6到-1之间随机变化
self.velocity_x = random.uniform(-1, 1) * random.random() # 粒子的水平速度在-1到1之间随机变化
self.rect = pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.size)
def update(self):
"""更新粒子rect位置"""
speed_rate = 1.2 # 定义一个速度系数,微调微粒速度
self.x += self.velocity_x * speed_rate
self.y += self.velocity_y * speed_rate
self.velocity_y += GRAVITY * 0.2 # 微粒的重力加速度要设置得小一点
#更新微粒的rect对象的值,否则显示微粒不动
self.rect.x = self.x
self.rect.y = self.y
def move_distance(self):
"""计算移动的距离"""
return int(math.sqrt((self.x-self.x0)**2+(self.y-self.y0)**2))
def draw(self, screen):
"""绘制粒子"""
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.size)
#==============================================================
def generate_fireworks(fireworks):
"""装载烟花"""
#如果画面烟花数量小于设置上限就补充
if len(fireworks) <= FIREWORKS_COUNT:
#firework = Firework((random.randint(20, SCREEN_WIDTH-20)),(random.randint(int(SCREEN_HEIGHT/2), int(SCREEN_HEIGHT))))
firework = Firework((random.randint(20, SCREEN_WIDTH-20)),(random.randint(SCREEN_HEIGHT-150, SCREEN_HEIGHT-100)))
fireworks.append(firework)
return fireworks
#==============================================================
def update_screen(fireworks,screen):
"""刷新屏幕"""
try:
background = pygame.image.load(background_filename).convert()
except FileNotFoundError:
#print("Sorry, the file " + background_filename + " does not exist.")
#input()
screen.fill(BG_COLOR) #若没有背景图片,则使用纯黑色背景!
else:
screen.blit(background, (0, 0))
#遍历烟花,满足条件即删除
for firework in fireworks:
firework.draw(screen)
Label = firework.update(screen)
# 若烟花的微粒移动距离超过指定数值,则删除该烟花(包括其所有微粒)
if Label == True :
fireworks.remove(firework)
#让最近绘制的屏幕可见
pygame.display.flip()
#===============================================================
def rungame():
"""主函数"""
#初始化
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen.fill(BG_COLOR)
pygame.display.set_caption("Fireworks")
clock = pygame.time.Clock()
fireworks = []
#开始循环
while True :
#设置帧率(如帧率过高,则一闪而过)
clock.tick(FRAME)
#点击窗口X按钮,退出程序
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#生成烟花
generate_fireworks(fireworks)
#刷新屏幕
update_screen(fireworks,screen)
#==============================================================
"""运行主函数"""
if __name__ == '__main__':
rungame()