基于pygame的烟花代码

除了利用HTML、CSS外,Python也可以实现相同的烟花效果。

首先通过以下命令下载依赖:

pip install pygame

接着创建一个Firework.py文件,可自己命名。

导入项目需要的依赖

import pygame as pg
import random as ra
import math

对pygame进行初始化,设置展示窗口的相关信息

# 初始化pygame
pg.init()
# 设置窗口标题
pg.display.set_caption("🎇")
# 获取窗口信息
winScreen = pg.display.Info()
# 获取屏幕宽度
screenWidth = winScreen.current_w
# 获取屏幕高度
screenHeight = winScreen.current_h
# 创建向量
vector = pg.math.Vector2
# 创建颜色列表
trail_colors = [(45, 45, 45), (60, 60, 60), (75, 75, 75), (125, 125, 125), (150, 150, 150)]

1. pg.init():初始化pygame库,这是使用pygame库的第一步。

2. pg.display.set_caption("🎇"):设置窗口标题为"🎇"。

3. winScreen = pg.display.Info():获取窗口信息,并将其存储在`winScreen`变量中。

4. screenWidth = winScreen.current_w:获取屏幕宽度,并将其存储在`screenWidth`变量中。

5. screenHeight = winScreen.current_h:获取屏幕高度,并将其存储在`screenHeight`变量中。

6. vector = pg.math.Vector2:创建一个向量类,用于处理二维向量。

7. trail_colors = [(45, 45, 45), (60, 60, 60), (75, 75, 75), (125, 125, 125), (150, 150, 150)]:创建一个颜色列表,用于存储不同颜色的RGB值。

编写烟花类Firework,对烟花信息进行配置。

 

class Firework:
    def __init__(self):
        # 随机生成颜色
        self.colour = (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
        # 随机生成三种颜色
        self.colours = (
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
        )
        # 生成一个表示发射出的火花的粒子对象
        self.firework = Particle(ra.randint(0, screenWidth), screenHeight, True, self.colour)
        # 初始化爆炸状态为 False
        self.exploded = False
        self.particles = []
        # 爆炸产生的粒子数量范围
        self.min_max_particles = vector(666, 999)

    def update(self, win):
        g = vector(0, ra.uniform(0.15, 0.4))
        if not self.exploded:
            # 给发射出的火花施加重力
            self.firework.apply_force(g)
            self.firework.move()
            for tf in self.firework.trails:
                tf.show(win)
            self.show(win)
            if self.firework.vel.y >= 0:
                self.exploded = True
                self.explode()
        else:
            for particle in self.particles:
                # 给爆炸产生的粒子施加随机力
                particle.apply_force(vector(g.x + ra.uniform(-1, 1) / 20, g.y / 2 + (ra.randint(1, 8) / 100)))
                particle.move()
                for t in particle.trails:
                    t.show(win)
                particle.show(win)

    def explode(self):
        amount = ra.randint(int(self.min_max_particles.x), int(self.min_max_particles.y))
        for i in range(amount):
            # 在爆炸位置生成粒子对象并添加到粒子列表中
            self.particles.append(Particle(self.firework.pos.x, self.firework.pos.y, False, self.colours))

    def show(self, win):
        # 绘制发射出的火花
        pg.draw.circle(win, self.colour, (int(self.firework.pos.x), int(self.firework.pos.y)), self.firework.size)

    def remove(self):
        if self.exploded:
            for p in self.particles:
                if p.remove is True:
                    self.particles.remove(p)
            if len(self.particles) == 0:
                return True
            else:
                return False

        Firework类中包含了初始化方法__init__,更新方法update,爆炸方法explode,显示方法show以及移除方法remove。

        __init__()方法用于初始化烟花对象的基本属性,如颜色、爆炸状态等。同时,它还生成了一个表示发射出的火花的粒子对象self.firework,并将其添加到烟花对象的粒子列表self.particles中。

        update()方法用于更新烟花对象的状态。如果烟花尚未爆炸,它会给发射出的火花施加重力,并移动火花的位置。如果烟花已经爆炸,它会更新爆炸产生的粒子的状态,并移动粒子的位置。

        explode()方法用于模拟烟花爆炸的过程。它会随机生成一定数量的粒子对象,并将其添加到烟花对象的粒子列表self.particles中。

        show()方法用于在屏幕上绘制烟花对象。如果烟花尚未爆炸,它会绘制发射出的火花;如果烟花已经爆炸,它会绘制爆炸产生的粒子。

        remove()方法用于判断烟花对象是否需要被移除。如果烟花已经爆炸,并且所有粒子都被移除了,那么烟花对象就可以被移除了。

        由于使用了随机数生成,每次运行结果可能会有所不同。

烟花爆炸效果类Particle

class Particle:
    # 初始化函数,传入参数x,y,firework,colour
    def __init__(self, x, y, firework, colour):
        # 初始化firework属性
        self.firework = firework
        # 初始化位置属性
        self.pos = vector(x, y)
        # 初始化原点属性
        self.origin = vector(x, y)
        # 初始化半径属性
        self.radius = 25
        # 初始化remove属性
        self.remove = False
        # 初始化爆炸半径属性
        self.explosion_radius = ra.randint(15, 25)
        # 初始化生命属性
        self.life = 0
        # 初始化加速度属性
        self.acc = vector(0, 0)
        # 初始化 trails 属性
        self.trails = []
        # 初始化prev_posx属性
        self.prev_posx = [-10] * 10
        # 初始化prev_posy属性
        self.prev_posy = [-10] * 10
        # 如果firework属性为真
        if self.firework:
            # 初始化速度属性
            self.vel = vector(0, -ra.randint(17, 20))
            # 初始化大小属性
            self.size = 5
            # 初始化颜色属性
            self.colour = colour
            # 遍历5次
            for i in range(5):
                # 将Trail实例添加到trails属性中
                self.trails.append(Trail(i, self.size, True))
        # 如果firework属性为假
        else:
            # 初始化速度属性
            self.vel = vector(ra.uniform(-1, 1), ra.uniform(-1, 1))
            # 乘以随机数
            self.vel.x *= ra.randint(7, self.explosion_radius + 2)
            self.vel.y *= ra.randint(7, self.explosion_radius + 2)
            # 初始化大小属性
            self.size = ra.randint(2, 4)
            # 从colour属性中随机选择颜色
            self.colour = ra.choice(colour)
            # 遍历5次
            for i in range(5):
                # 将Trail实例添加到trails属性中
                self.trails.append(Trail(i, self.size, False))

    def apply_force(self, force):
        # 施加力
        self.acc += force

    def move(self):
        if not self.firework:
            # 爆炸产生的粒子减速
            self.vel.x *= 0.8
            self.vel.y *= 0.8
        self.vel += self.acc
        self.pos += self.vel
        self.acc *= 0
        if self.life == 0 and not self.firework:
            # 判断是否超出爆炸半径
            distance = math.sqrt((self.pos.x - self.origin.x) ** 2 + (self.pos.y - self.origin.y) ** 2)
            if distance > self.explosion_radius:
                self.remove = True
        self.decay()
        self.trail_update()
        self.life += 1

    def show(self, win):
        # 绘制粒子
        pg.draw.circle(win, (self.colour[0], self.colour[1], self.colour[2], 0), (int(self.pos.x), int(self.pos.y)),
                       self.size)

    def decay(self):
        if 50 > self.life > 10:
            ran = ra.randint(0, 30)
            if ran == 0:
                self.remove = True
        elif self.life > 50:
            ran = ra.randint(0, 5)
            if ran == 0:
                self.remove = True

        # 定义一个函数trail_update,用于更新轨迹

    def trail_update(self):
        # 将当前位置的x坐标从列表中弹出,并插入到列表的第一个位置
        self.prev_posx.pop()
        self.prev_posx.insert(0, int(self.pos.x))
        # 将当前位置的y坐标从列表中弹出,并插入到列表的第一个位置
        self.prev_posy.pop()
        self.prev_posy.insert(0, int(self.pos.y))
        # 遍历轨迹列表
        for n, t in enumerate(self.trails):
            # 如果轨迹是动态的,则获取下一个位置的坐标
            if t.dynamic:
                t.get_pos(self.prev_posx[n + 1], self.prev_posy[n + 1])
            # 如果轨迹是静态的,则获取下一个位置的坐标
            else:
                t.get_pos(self.prev_posx[n + 5], self.prev_posy[n + 5])

 

        这段代码定义了一个名为Particle的类,用于表示烟花模拟中的粒子。粒子可以分为两种类型:一种是烟花爆炸产生的粒子,另一种是烟花爆炸后产生的粒子。

        Particle类的__init__方法用于初始化粒子的属性,包括firework、pos、origin、radius、remove、explosion_radius、life、acc、trails、prev_posx和prev_posy。其中,firework表示粒子是否属于烟花爆炸产生的粒子,pos表示粒子的当前位置,origin表示粒子的原点位置,radius表示粒子的半径,remove表示粒子是否应该被移除,explosion_radius表示烟花爆炸的半径,life表示粒子的生命周期,acc表示粒子的加速度,trails表示粒子的轨迹列表,prev_posx和prev_posy分别表示粒子的前10个位置的x和y坐标。

        Particle类还定义了apply_force、move、show和decay方法,用于施加力、移动粒子、绘制粒子和衰变粒子。其中,apply_force方法用于施加力,move方法用于移动粒子,show方法用于绘制粒子,decay方法用于衰变粒子。

        trail_update方法用于更新粒子的轨迹。如果轨迹是动态的,则获取下一个位置的坐标;如果轨迹是静态的,则获取下一个位置的坐标。

痕迹类Trail :

class Trail:
    # 初始化函数,参数n表示第n个元素,size表示元素的大小,dynamic表示元素是否动态
    def __init__(self, n, size, dynamic):
        # 记录元素在行中的位置
        self.pos_in_line = n
        # 记录元素的坐标
        self.pos = vector(-10, -10)
        # 记录元素是否动态
        self.dynamic = dynamic
        # 如果元素是动态的
        if self.dynamic:
            # 记录元素的颜色
            self.colour = trail_colors[n]
            # 记录元素的大小
            self.size = int(size - n / 2)
        # 如果元素是静态的
        else:
            # 记录元素的默认颜色
            self.colour = (255, 255, 200)
            # 记录元素的大小
            self.size = size - 2
            # 如果元素的大小小于0,则设置元素的大小为0
            if self.size < 0:
                self.size = 0

    def get_pos(self, x, y):
        self.pos = vector(x, y)

    def show(self, win):
        # 绘制痕迹
        pg.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)

        这段代码定义了一个名为`Trail`的类,用于表示游戏中的痕迹。痕迹可以是动态的(如子弹的轨迹),也可以是静态的(如玩家移动的脚印)。

`__init__`函数是类的初始化函数,用于初始化痕迹的属性。它接受三个参数:`n`表示第n个元素,`size`表示元素的大小,`dynamic`表示元素是否动态。根据这些参数,它可以设置痕迹的颜色、大小和位置。

        `get_pos`函数用于更新痕迹的坐标。它接受两个参数`x`和`y`,表示新的坐标。

        `show`函数用于在游戏窗口中绘制痕迹。它接受一个参数`win`,表示游戏窗口。绘制痕迹时,会使用`pg.draw.circle`函数绘制一个圆形,圆形的位置和颜色由`self.pos`和`self.colour`决定,半径由`self.size`决定。

展示函数fire:

def fire():
    # 设置屏幕大小
    screen = pg.display.set_mode((screenWidth, screenHeight - 66))
    # 设置时钟
    clock = pg.time.Clock()
    # 创建烟花列表
    fireworks = [Firework() for _ in range(2)]
    # 设置运行状态
    running = True
    # 加载字体
    font = pg.font.SysFont("comicsansms", 99)
    # 渲染文本
    # 展示文本
    text = ""
    text_color = (255, 190, 200)  # 字体颜色
    rendered_text = font.render(text, True, text_color)
    # 循环
    while running:
        # 设置帧数
        clock.tick(99)
        # 获取事件
        for event in pg.event.get():
            if event.type == pg.QUIT:
                running = False
        # 计算文本位置
        text_width = rendered_text.get_width()
        text_height = rendered_text.get_height()
        text_x = (screenWidth - text_width) // 2
        text_y = (screenHeight - text_height) // 2 - 99
        # 设置背景色
        screen.fill((20, 20, 30))
        # 绘制文本
        screen.blit(rendered_text, (text_x, text_y))
        # 随机添加烟花
        if ra.randint(0, 10) == 1:
            fireworks.append(Firework())
        # 更新烟花
        update(screen, fireworks)
    # 退出
    pg.quit()
    quit()

 完整代码如下:

import pygame as pg
import random as ra
import math

# 初始化pygame
pg.init()
# 设置窗口标题
pg.display.set_caption("🎇")
# 获取窗口信息
winScreen = pg.display.Info()
# 获取屏幕宽度
screenWidth = winScreen.current_w
# 获取屏幕高度
screenHeight = winScreen.current_h
# 创建向量
vector = pg.math.Vector2
# 创建颜色列表
trail_colors = [(45, 45, 45), (60, 60, 60), (75, 75, 75), (125, 125, 125), (150, 150, 150)]


# 烟花类
class Firework:
    def __init__(self):
        # 随机生成颜色
        self.colour = (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
        # 随机生成三种颜色
        self.colours = (
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255)),
            (ra.randint(0, 255), ra.randint(0, 255), ra.randint(0, 255))
        )
        # 生成一个表示发射出的火花的粒子对象
        self.firework = Particle(ra.randint(0, screenWidth), screenHeight, True, self.colour)
        # 初始化爆炸状态为 False
        self.exploded = False
        self.particles = []
        # 爆炸产生的粒子数量范围
        self.min_max_particles = vector(666, 999)

    def update(self, win):
        g = vector(0, ra.uniform(0.15, 0.4))
        if not self.exploded:
            # 给发射出的火花施加重力
            self.firework.apply_force(g)
            self.firework.move()
            for tf in self.firework.trails:
                tf.show(win)
            self.show(win)
            if self.firework.vel.y >= 0:
                self.exploded = True
                self.explode()
        else:
            for particle in self.particles:
                # 给爆炸产生的粒子施加随机力
                particle.apply_force(vector(g.x + ra.uniform(-1, 1) / 20, g.y / 2 + (ra.randint(1, 8) / 100)))
                particle.move()
                for t in particle.trails:
                    t.show(win)
                particle.show(win)

    def explode(self):
        amount = ra.randint(int(self.min_max_particles.x), int(self.min_max_particles.y))
        for i in range(amount):
            # 在爆炸位置生成粒子对象并添加到粒子列表中
            self.particles.append(Particle(self.firework.pos.x, self.firework.pos.y, False, self.colours))

    def show(self, win):
        # 绘制发射出的火花
        pg.draw.circle(win, self.colour, (int(self.firework.pos.x), int(self.firework.pos.y)), self.firework.size)

    def remove(self):
        if self.exploded:
            for p in self.particles:
                if p.remove is True:
                    self.particles.remove(p)
            if len(self.particles) == 0:
                return True
            else:
                return False


# 粒子类
class Particle:
    # 初始化函数,传入参数x,y,firework,colour
    def __init__(self, x, y, firework, colour):
        # 初始化firework属性
        self.firework = firework
        # 初始化位置属性
        self.pos = vector(x, y)
        # 初始化原点属性
        self.origin = vector(x, y)
        # 初始化半径属性
        self.radius = 25
        # 初始化remove属性
        self.remove = False
        # 初始化爆炸半径属性
        self.explosion_radius = ra.randint(15, 25)
        # 初始化生命属性
        self.life = 0
        # 初始化加速度属性
        self.acc = vector(0, 0)
        # 初始化 trails 属性
        self.trails = []
        # 初始化prev_posx属性
        self.prev_posx = [-10] * 10
        # 初始化prev_posy属性
        self.prev_posy = [-10] * 10
        # 如果firework属性为真
        if self.firework:
            # 初始化速度属性
            self.vel = vector(0, -ra.randint(17, 20))
            # 初始化大小属性
            self.size = 5
            # 初始化颜色属性
            self.colour = colour
            # 遍历5次
            for i in range(5):
                # 将Trail实例添加到trails属性中
                self.trails.append(Trail(i, self.size, True))
        # 如果firework属性为假
        else:
            # 初始化速度属性
            self.vel = vector(ra.uniform(-1, 1), ra.uniform(-1, 1))
            # 乘以随机数
            self.vel.x *= ra.randint(7, self.explosion_radius + 2)
            self.vel.y *= ra.randint(7, self.explosion_radius + 2)
            # 初始化大小属性
            self.size = ra.randint(2, 4)
            # 从colour属性中随机选择颜色
            self.colour = ra.choice(colour)
            # 遍历5次
            for i in range(5):
                # 将Trail实例添加到trails属性中
                self.trails.append(Trail(i, self.size, False))

    def apply_force(self, force):
        # 施加力
        self.acc += force

    def move(self):
        if not self.firework:
            # 爆炸产生的粒子减速
            self.vel.x *= 0.8
            self.vel.y *= 0.8
        self.vel += self.acc
        self.pos += self.vel
        self.acc *= 0
        if self.life == 0 and not self.firework:
            # 判断是否超出爆炸半径
            distance = math.sqrt((self.pos.x - self.origin.x) ** 2 + (self.pos.y - self.origin.y) ** 2)
            if distance > self.explosion_radius:
                self.remove = True
        self.decay()
        self.trail_update()
        self.life += 1

    def show(self, win):
        # 绘制粒子
        pg.draw.circle(win, (self.colour[0], self.colour[1], self.colour[2], 0), (int(self.pos.x), int(self.pos.y)),
                       self.size)

    def decay(self):
        if 50 > self.life > 10:
            ran = ra.randint(0, 30)
            if ran == 0:
                self.remove = True
        elif self.life > 50:
            ran = ra.randint(0, 5)
            if ran == 0:
                self.remove = True

        # 定义一个函数trail_update,用于更新轨迹

    def trail_update(self):
        # 将当前位置的x坐标从列表中弹出,并插入到列表的第一个位置
        self.prev_posx.pop()
        self.prev_posx.insert(0, int(self.pos.x))
        # 将当前位置的y坐标从列表中弹出,并插入到列表的第一个位置
        self.prev_posy.pop()
        self.prev_posy.insert(0, int(self.pos.y))
        # 遍历轨迹列表
        for n, t in enumerate(self.trails):
            # 如果轨迹是动态的,则获取下一个位置的坐标
            if t.dynamic:
                t.get_pos(self.prev_posx[n + 1], self.prev_posy[n + 1])
            # 如果轨迹是静态的,则获取下一个位置的坐标
            else:
                t.get_pos(self.prev_posx[n + 5], self.prev_posy[n + 5])


# 痕迹类
class Trail:
    # 初始化函数,参数n表示第n个元素,size表示元素的大小,dynamic表示元素是否动态
    def __init__(self, n, size, dynamic):
        # 记录元素在行中的位置
        self.pos_in_line = n
        # 记录元素的坐标
        self.pos = vector(-10, -10)
        # 记录元素是否动态
        self.dynamic = dynamic
        # 如果元素是动态的
        if self.dynamic:
            # 记录元素的颜色
            self.colour = trail_colors[n]
            # 记录元素的大小
            self.size = int(size - n / 2)
        # 如果元素是静态的
        else:
            # 记录元素的默认颜色
            self.colour = (255, 255, 200)
            # 记录元素的大小
            self.size = size - 2
            # 如果元素的大小小于0,则设置元素的大小为0
            if self.size < 0:
                self.size = 0

    def get_pos(self, x, y):
        self.pos = vector(x, y)

    def show(self, win):
        # 绘制痕迹
        pg.draw.circle(win, self.colour, (int(self.pos.x), int(self.pos.y)), self.size)


# 定义一个更新函数,参数为窗口和烟花列表
def update(win, fireworks):
    # 遍历烟花列表
    for fw in fireworks:
        # 更新烟花的位置
        fw.update(win)
        # 如果烟花已经移除,从烟花列表中移除
        if fw.remove():
            fireworks.remove(fw)
    # 更新窗口
    pg.display.update()


# 定义fire函数
def fire():
    # 设置屏幕大小
    screen = pg.display.set_mode((screenWidth, screenHeight - 66))
    # 设置时钟
    clock = pg.time.Clock()
    # 创建烟花列表
    fireworks = [Firework() for _ in range(2)]
    # 设置运行状态
    running = True
    # 加载字体
    font = pg.font.SysFont("comicsansms", 99)
    # 渲染文本
    # 展示文本
    text = ""
    text_color = (255, 190, 200)  # 字体颜色
    rendered_text = font.render(text, True, text_color)
    # 循环
    while running:
        # 设置帧数
        clock.tick(99)
        # 获取事件
        for event in pg.event.get():
            if event.type == pg.QUIT:
                running = False
        # 计算文本位置
        text_width = rendered_text.get_width()
        text_height = rendered_text.get_height()
        text_x = (screenWidth - text_width) // 2
        text_y = (screenHeight - text_height) // 2 - 99
        # 设置背景色
        screen.fill((20, 20, 30))
        # 绘制文本
        screen.blit(rendered_text, (text_x, text_y))
        # 随机添加烟花
        if ra.randint(0, 10) == 1:
            fireworks.append(Firework())
        # 更新烟花
        update(screen, fireworks)
    # 退出
    pg.quit()
    quit()


# 调试
if __name__ == "__main__":
    fire()

效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值