Python烟花爆炸程序实例学习

2022-02-21  本文已影响0人  大龙10

摘自:哈哈老师的日记

https://www.toutiao.com/a7054756551550140965

  哈哈老师设计的烟花程序,学习实践一下。

一、烟花爆炸设计

  给定一个点,生成粒子,爆炸效果是该粒子的半径逐渐加大,颜色随机变化,方向360度速度随机变化。


烟花爆炸

二、烟花爆炸主程序

  主程序 firework.py

# firework.py

from particle import Particle
from base import *
import time

W,H = 1920,1080

g= 0.1      # 重力
balls = []  # 存放烟花粒子

def Bang(n=100,pos = (W/2,H/4)):
    '''烟花爆炸'''
    for i in range(n):
        ball = Particle(pos,(4,4),(255,255,255),(0,0),(0,0),5)
        ball.color = ctx.hsv_to_rgb(random.randint(0,360),100,100)
        r = random.randint(2,12)
        ball.size = (r,r)
        ball.r = r
        speed = Vector2(random.random()*15,0).rotate(random.randint(0,360))
        ball.vel = speed
        balls.append(ball)

def setup():
    size(W,H)

last_time = 0   # 上次爆炸时间

def draw():
    global last_time
    for event in ctx.events:
        if event.type == KEYDOWN:
            if event.key == K_SPACE:
                pos = random.randint(50,W-100),random.randint(100,H/2)
                Bang(200,pos)
        if event.type == MOUSEBUTTONDOWN:
            Bang(200,event.pos)

    if time.time() - last_time > random.randint(30,100)/10:     # 每隔一段时间爆炸一次(3 - 10秒)
        pos = random.randint(50,W-100),random.randint(100,H/2)
        Bang(random.randint(50,300),pos)
        last_time = time.time()

    ctx.screen.fill((0,0,0,100))    # 先清屏,alpha = 100 留残影

    for ball in balls[:]:       # 有删除操作,所以用 balls 的副本遍历
        if not ball.alive:
            balls.remove(ball)
        else:
            ball.applyForce(Vector2(0,g))
            ball.draw(ctx.screen)

run()

三、 粒子程序的实现

粒子程序particle.py

import pygame
from pygame.math import Vector2
import random,time

class Particle():

    def __init__(self,pos,size,color=(255,255,255),vel=(0,0),acc = (0,0),mass = 1):
        self.pos = Vector2(pos)
        self.size = size
        self.color = color
        self.vel = Vector2(vel)
        self.acc = Vector2(acc)
        self.r = size[0]/2
        self.mass = mass

        self.borth_time = time.time()
        self.life = random.random()*10
        self.alive = True

    def applyForce(self,force):
        f = force / self.mass
        self.acc += f

    def is_OutOfEdges(self,canvas):
        rect = canvas.get_rect()
        w,h = self.size
        if self.pos.x - w/2 >= rect.width:
            return True
        elif self.pos.x +w/2<= 0:
            return True
        if self.pos.y-h/2 >= rect.height:
            return True
        elif self.pos.y +h/2<= 0:
            return True

    def checkLife(self):
        if self.life <= time.time() - self.borth_time:
            self.alive = False

    def update(self):
        self.vel += self.acc
        self.pos += self.vel
        self.acc *= 0

        self.checkLife()

    def draw(self,canvas):
        self.update()
        if not self.is_OutOfEdges(canvas):
            pygame.draw.circle(canvas,self.color,self.pos,self.r)
        else:
            self.alive = False

四、封装 pygame

用来简单封装 pygame的程序base.py

# base.py

import pygame
from pygame.locals import *
from pygame.math import Vector2
import sys,random,math,os

width,height = 1920,1080
pygame.init()
window = None
pygame.display.set_caption('测试')

clock = pygame.time.Clock()
running = True

class real_contex():
    def __init__(self):
        self.screen = None
        x,y = pygame.mouse.get_pos()
        self.mouseX = x
        self.mouseY = y
        self.fps = 60

    def fill(self,color):
        self.window.fill(0)
        if self.screen is not None:
            self.screen.fill(color)

    def hsv_to_rgb(self,h,s,v,a=100):
        '''颜色转换'''
        c = pygame.Color(0,0,0,a)
        c.hsva = (h,s,v,a)
        return c

    def setup(self):
        pass

    def draw(self):
        pass

ctx = real_contex()

def size(w,h):
    global width,height,window
    width,height = w,h
    if w == 1920 and h == 1080:
        window = pygame.display.set_mode((width,height),FULLSCREEN)
    else:
        window = pygame.display.set_mode((width,height))

    ctx.window = window    
    # ctx.screen = window.convert_alpha() # 支持透明度
    ctx.screen = pygame.Surface((w,h), pygame.SRCALPHA)
    ctx.width = width
    ctx.height = height
    ctx.rect = window.get_rect()
    ctx.center = ctx.rect.center

def run():
    global running,window

    # 获取调用 run 函数的文件名
    m_name = sys._getframe(1).f_code.co_filename
    f_name = os.path.basename(m_name)
    module_name = os.path.splitext(f_name)[0]
    # print(f_name,module_name)
    # 通过文件名加载为模块,并动态获取 setup 和 draw 方法
    app_module = __import__(module_name)
    m_dir = dir(app_module)
    if 'setup' in m_dir:
        ctx.setup = app_module.setup
    if 'draw' in m_dir:
        ctx.draw = app_module.draw
    del m_dir

    ctx.setup()
    if window is None:
        size(800,600)
    while running:
        ctx.events = pygame.event.get()
        ctx.mouseX,ctx.mouseY = pygame.mouse.get_pos()
        for evt in ctx.events:
            if evt.type == QUIT:
                pygame.quit()
                sys.exit()
            if evt.type == KEYDOWN:
                if evt.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit()

        ctx.draw()
        window.blit(ctx.screen,(0,0))
        pygame.display.update()
        clock.tick(ctx.fps)
上一篇下一篇

猜你喜欢

热点阅读