PythonPygame制作雪夜烟花景

Valora ·
更新时间:2024-11-10
· 948 次阅读

目录

运行截图

实现过程

核心代码

基础架子

下雪的过程

雪落到地上堆起来的过程

实现烟花的过程

完整代码

运行截图

运行效果:

什么?你说你看不清烟花?那我换一种颜色,请点开看。

实现过程

准备工作

使用语言和框架:python、pygame。

安装pygame:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn pygame

你需要知道的基础知识

首先,pygame渲染是同步的,所以同屏渲染的点过多之后,就会造成卡顿的情况。

其次,pygame的代码逻辑是,周期性渲染一系列的屏,从而产生连续的动画。

你需要掌握的框架基础知识:

初始化过程

import pygame pygame.init() pygame.mixer.init() pygame.font.init()

获取字体

myfont = pygame.font.SysFont('simHei', 30) textsurface = myfont.render(a[i], False, random_color(150, 255)) screen.blit(textsurface, (80, 30))

画圈

pygame.draw.circle(screen, (snow_list[i][4], snow_list[i][5], snow_list[i][6]), snow_list[i][:2], snow_list[i][3] - 3)

加载背景音乐

screen = pygame.display.set_mode(bg_size) pygame.display.set_caption("新年快乐") bg = pygame.image.load(bg_img) pygame.mixer.music.load('D:\\CloudMusic\\小时姑娘 - 霞光-《精灵世纪》片尾曲.mp3') 核心代码 基础架子

首先,需要实现一个基础的事件循环的架子,如下:

def main():     global show_n     global fk_list     bg_size = (WIN_W, WIN_H)     screen = pygame.display.set_mode(bg_size)     pygame.display.set_caption("新年快乐")     pygame.mixer.music.load('D:\\CloudMusic\\小时姑娘 - 霞光-《精灵世纪》片尾曲.mp3')     font_values = ['新年快乐']     grand_has = set()     clock = pygame.time.Clock()     while True:         if not pygame.mixer.music.get_busy():             pygame.mixer.music.play()         for event in pygame.event.get():             if event.type == pygame.QUIT:                 exit()         screen.fill((0, 0, 0))         ... ...         pygame.display.update()         time_passed = clock.tick(50) if __name__ == '__main__':     main() 下雪的过程

现在,需要实现下雪的过程,首先,考虑定义定义一堆初始化的下雪点

def init_xue(bg_size): snow_list = [] for i in range(200): x_site = random.randrange(0, bg_size[0]) # 雪花圆心位置 y_site = random.randrange(0, bg_size[1]) # 雪花圆心位置 X_shift = random.randint(-1, 1) # x 轴偏移量 radius = random.randint(4, 6) # 半径和 y 周下降量 xxxxx = random_color(150, 255) snow_list.append([x_site, y_site, X_shift, radius, 255, 255, 255]) return snow_list

然后实现渲染雪的过程

def draw_xue(snow_list: [], screen, bg_size: [], grand_has: set, grand_list: []): # 雪花列表循环 # todo 空中的雪 for i in range(len(snow_list)): # 绘制雪花,颜色、位置、大小 pygame.draw.circle(screen, (snow_list[i][4], snow_list[i][5], snow_list[i][6]), snow_list[i][:2], snow_list[i][3] - 3) # 移动雪花位置(下一次循环起效) snow_list[i][0] += snow_list[i][2] snow_list[i][1] += snow_list[i][3] # 如果雪花落出屏幕,重设位置 if snow_list[i][1] > bg_size[1]: # tmp = [] snow_list[i][1] = random.randrange(-50, -10) snow_list[i][0] = random.randrange(0, bg_size[0]) x = snow_list[i][0] y = bg_size[1] while (grand_has.__contains__(x * 10000 + y)): y = y - snow_list[i][3] grand_has.add(x * 10000 + y) grand_list.append( [x, y, snow_list[i][2], snow_list[i][3], snow_list[i][4], snow_list[i][5], snow_list[i][6]])

集成到上面的架子中,效果如下:

不过目前的下雪没有质感,可以考虑在底部堆一些雪,只需要在雪落到地上做特判即可。

雪落到地上堆起来的过程

在前面的下雪过程的代码中,我们维护了一个Grand_list的数组,目的就是维护堆雪的效果

min_height = 100000 # todo 地上的积雪 for i in range(len(grand_list)): if grand_list[i][0] < 375: min_height = min(min_height, grand_list[i][1])

然后进入维护程序:

draw_xue(snow_list, screen, bg_size, grand_has, grand_list)

最后再将雪画出来

for i in range(len(grand_list)): pygame.draw.circle(screen, (grand_list[i][4], grand_list[i][5], grand_list[i][6]), grand_list[i][:2], grand_list[i][3] - 3)

效果图如上。

实现烟花的过程

首先定义出烟花类:

class Fireworks():     is_show = False     x, y = 0, 0     vy = 0     p_list = []     color = [0, 0, 0]     v = 0     def __init__(self, x, y, vy, n=300, color=[0, 255, 0], v=10):         self.x = x         self.y = y         self.vy = vy         self.color = color         self.v = v         for i in range(n):             self.p_list.append([random.random() * 2 * math.pi, 0, v * math.pow(random.random(), 1 / 3)])     def run(self):         global show_n         for p in self.p_list:             p[1] = p[1] + (random.random() * 0.6 + 0.7) * p[2]             p[2] = p[2] * 0.97             if p[2] < 1.2:                 self.color[0] *= 0.9999                 self.color[1] *= 0.9999                 self.color[2] *= 0.9999             if max(self.color) < 10 or self.y > WIN_H + p[1]:                 show_n -= 1                 self.is_show = False                 break         self.vy += 10 * t1         self.y += self.vy * t1

然后,我们需要画出烟花释放前上升的过程点,这部分与下雪的初始化差不多。

def init_yanhua(bg_size): yanhua_list = [] for i in range(5): x_site = random.randrange(0, WIN_W) # 雪花圆心位置 y_site = WIN_H # 雪花圆心位置 X_shift = 0 # x 轴偏移量 radius = random.randint(6, 10) # 半径和 y 周上升降量 xxxxx = random_color(150, 255) red = xxxxx[0] green = xxxxx[1] blue = xxxxx[2] yanhua_list.append([x_site, y_site, X_shift, radius, red, green, blue]) return yanhua_list

然后是画上升过程

def draw_yanhua(yanhua_list: [], screen, bg_size: []):     global fk_list     for i in range(len(yanhua_list)):         # 绘制雪花,颜色、位置、大小         pygame.draw.circle(screen, (yanhua_list[i][4], yanhua_list[i][5], yanhua_list[i][6]), yanhua_list[i][:2],                            yanhua_list[i][3] - 3)         yanhua_list[i][0] += yanhua_list[i][2]         yanhua_list[i][1] -= yanhua_list[i][3]         if yanhua_list[i][1] <= 0:             # tmp = []             yanhua_list[i][1] = WIN_H             yanhua_list[i][0] = random.randrange(0, bg_size[0])         if yanhua_list[i][1] <= random.randint(200, 400):             # todo 放烟花             fk = Fireworks(yanhua_list[i][0], yanhua_list[i][1], -20, n=300, color=red_random(1, 150), v=10)             fk_list.append(fk)             yanhua_list[i][1] = WIN_H             yanhua_list[i][0] = random.randrange(0, bg_size[0])

效果图如下:

圈出来的就是上升过程的烟花。

最后就是绽放部分,其实在上升过程的代码中有维护,如果超过某个随机高度,就会生成一个烟花,只是没有渲染,现在我们把渲染加上。

for fk in fk_list: fk.run() for p in fk.p_list: x, y = fk.x + p[1] * math.cos(p[0]), fk.y + p[1] * math.sin(p[0]) if random.random() < 0.055: screen.set_at((int(x), int(y)), (255, 255, 255)) else: screen.set_at((int(x), int(y)), (int(fk.color[0]), int(fk.color[1]), int(fk.color[2]))) tmp = [] for fk in fk_list: for p in fk.p_list: x, y = fk.x + p[1] * math.cos(p[0]), fk.y + p[1] * math.sin(p[0]) if y < WIN_H - 1000: tmp.append(fk) break fk_list = tmp

最终的运行效果就如最顶上的效果一样。

完整代码

将上述过程进行组合,结果如下,感兴趣的朋友可以按自己的需求进行优化。

import pygame import random import math pygame.init() pygame.mixer.init() pygame.font.init() WIN_W = 2200 WIN_H = 1300 t1 = 0.18  # 时间流速 show_n = 0 show_frequency = 0.0015  # 烟花绽放频率,数值越大频率越高 color_list = [     [255, 0, 0] ] yanhua_map = {} fk_list = [] class Fireworks():     is_show = False     x, y = 0, 0     vy = 0     p_list = []     color = [0, 0, 0]     v = 0     def __init__(self, x, y, vy, n=300, color=[0, 255, 0], v=10):         self.x = x         self.y = y         self.vy = vy         self.color = color         self.v = v         for i in range(n):             self.p_list.append([random.random() * 2 * math.pi, 0, v * math.pow(random.random(), 1 / 3)])     def run(self):         global show_n         for p in self.p_list:             p[1] = p[1] + (random.random() * 0.6 + 0.7) * p[2]             p[2] = p[2] * 0.97             if p[2] < 1.2:                 self.color[0] *= 0.9999                 self.color[1] *= 0.9999                 self.color[2] *= 0.9999             if max(self.color) < 10 or self.y > WIN_H + p[1]:                 show_n -= 1                 self.is_show = False                 break         self.vy += 10 * t1         self.y += self.vy * t1 def random_color(l, r):     return [random.randint(l, r), random.randint(l, r), random.randint(l, r)] def red_random(l, r):     return [255, random.randint(l, r), random.randint(l, r)] def init_yanhua(bg_size):     yanhua_list = []     for i in range(5):         x_site = random.randrange(0, WIN_W)  # 雪花圆心位置         y_site = WIN_H  # 雪花圆心位置         X_shift = 0  # x 轴偏移量         radius = random.randint(6, 10)  # 半径和 y 周上升降量         xxxxx = random_color(150, 255)         red = xxxxx[0]         green = xxxxx[1]         blue = xxxxx[2]         yanhua_list.append([x_site, y_site, X_shift, radius, red, green, blue])     return yanhua_list def init_xue(bg_size):     snow_list = []     for i in range(200):         x_site = random.randrange(0, bg_size[0])  # 雪花圆心位置         y_site = random.randrange(0, bg_size[1])  # 雪花圆心位置         X_shift = random.randint(-1, 1)  # x 轴偏移量         radius = random.randint(4, 6)  # 半径和 y 周下降量         xxxxx = random_color(150, 255)         # red = xxxxx[0]         # green = xxxxx[1]         # blue = xxxxx[2]         snow_list.append([x_site, y_site, X_shift, radius, 255, 255, 255])     return snow_list def draw_xue(snow_list: [], screen, bg_size: [], grand_has: set, grand_list: []):     # 雪花列表循环     # todo 空中的雪     for i in range(len(snow_list)):         # 绘制雪花,颜色、位置、大小         pygame.draw.circle(screen, (snow_list[i][4], snow_list[i][5], snow_list[i][6]), snow_list[i][:2],                            snow_list[i][3] - 3)         # 移动雪花位置(下一次循环起效)         snow_list[i][0] += snow_list[i][2]         snow_list[i][1] += snow_list[i][3]         # 如果雪花落出屏幕,重设位置         if snow_list[i][1] > bg_size[1]:             # tmp = []             snow_list[i][1] = random.randrange(-50, -10)             snow_list[i][0] = random.randrange(0, bg_size[0])             x = snow_list[i][0]             y = bg_size[1]             while (grand_has.__contains__(x * 10000 + y)):                 y = y - snow_list[i][3]             grand_has.add(x * 10000 + y)             grand_list.append(                 [x, y, snow_list[i][2], snow_list[i][3], snow_list[i][4], snow_list[i][5],                  snow_list[i][6]]) def draw_yanhua(yanhua_list: [], screen, bg_size: []):     global fk_list     for i in range(len(yanhua_list)):         # 绘制雪花,颜色、位置、大小         pygame.draw.circle(screen, (yanhua_list[i][4], yanhua_list[i][5], yanhua_list[i][6]), yanhua_list[i][:2],                            yanhua_list[i][3] - 3)         # 移动雪花位置(下一次循环起效)         yanhua_list[i][0] += yanhua_list[i][2]         yanhua_list[i][1] -= yanhua_list[i][3]         # 如果雪花落出屏幕,重设位置         if yanhua_list[i][1] <= 0:             # tmp = []             yanhua_list[i][1] = WIN_H             yanhua_list[i][0] = random.randrange(0, bg_size[0])         if yanhua_list[i][1] <= random.randint(200, 400):             # todo 放烟花             fk = Fireworks(yanhua_list[i][0], yanhua_list[i][1], -20, n=300, color=red_random(1, 150), v=10)             fk_list.append(fk)             yanhua_list[i][1] = WIN_H             yanhua_list[i][0] = random.randrange(0, bg_size[0]) def show_shi(a: list, n, screen):     i = 2 * n - 1     j = 2 * n     if i >= len(a):         i = len(a) - 2         j = len(a) - 1     if i >= 0:         myfont = pygame.font.SysFont('simHei', 30)         textsurface = myfont.render(a[i], False, random_color(150, 255))         screen.blit(textsurface, (WIN_W / 2, 30))     if j >= 0:         myfont = pygame.font.SysFont('simHei', 100)         textsurface = myfont.render(a[j], False, red_random(1, 1))         screen.blit(textsurface, (WIN_W / 2 - 200, 50)) def main():     global show_n     global fk_list     bg_size = (WIN_W, WIN_H)     screen = pygame.display.set_mode(bg_size)     # bg_img = "./1.png"     pygame.display.set_caption("新年快乐")     # bg = pygame.image.load(bg_img)     pygame.mixer.music.load('D:\\CloudMusic\\小时姑娘 - 霞光-《精灵世纪》片尾曲.mp3')     grand_list = []     font_values = ['新年快乐']     grand_has = set()     clock = pygame.time.Clock()     yanhua_list = init_yanhua(bg_size)     snow_list = init_xue(bg_size)     # 游戏主循环     while True:         if not pygame.mixer.music.get_busy():             pygame.mixer.music.play()         for event in pygame.event.get():             if event.type == pygame.QUIT:                 exit()         screen.fill((0, 0, 0))         draw_yanhua(yanhua_list, screen, bg_size)         if len(fk_list) != 0:             print(len(fk_list))         # # 放烟花         show_shi(font_values, 0, screen)         for fk in fk_list:             fk.run()             for p in fk.p_list:                 x, y = fk.x + p[1] * math.cos(p[0]), fk.y + p[1] * math.sin(p[0])                 if random.random() < 0.055:                     screen.set_at((int(x), int(y)), (255, 255, 255))                 else:                     screen.set_at((int(x), int(y)), (int(fk.color[0]), int(fk.color[1]), int(fk.color[2])))         tmp = []         for fk in fk_list:             for p in fk.p_list:                 x, y = fk.x + p[1] * math.cos(p[0]), fk.y + p[1] * math.sin(p[0])                 if y < WIN_H - 1000:                     tmp.append(fk)                     break         fk_list = tmp         min_height = 100000         # todo 地上的积雪         for i in range(len(grand_list)):             if grand_list[i][0] < 375:                 min_height = min(min_height, grand_list[i][1])         draw_xue(snow_list, screen, bg_size, grand_has, grand_list)         for i in range(len(grand_list)):             pygame.draw.circle(screen, (grand_list[i][4], grand_list[i][5], grand_list[i][6]), grand_list[i][:2],                                grand_list[i][3] - 3)         pygame.display.update()         time_passed = clock.tick(50) if __name__ == '__main__':     main()

以上就是Python Pygame制作雪夜烟花景的详细内容,更多关于Python Pygame的资料请关注软件开发网其它相关文章!



烟花

需要 登录 后方可回复, 如果你还没有账号请 注册新账号