首先,需要的外置庫:pygame,pymunk
導入
import pygame
from pygame.locals import *
import pymunk
from pymunk import pygame_util
import sys
import random as rd
import time
import math
然后寫一個主程序類,對pygame進行初始化,設置屏幕寬高,設置標題,創建pymunk空間,然后設置空間的重力為(0,300),然后設置collision_persistence參數為0,表示沒有碰撞,畢竟倆煙花也不會撞一起......然后設置煙花半徑(可以自行修改),創建兩個列表,用于存放煙花爆炸形成的火球和發射到天空中還沒爆炸的煙花,創建一個colors列表,存放煙花的顏色
class Firework:
def init (self):
pygame.init()
self.W,self.H=800,1000
self.screen=pygame.display.set_mode((self.W,self.H))
self.draw_options=pygame_util.DrawOptions(self.screen)
pygame.display.set_caption("2023元旦煙花")
self.space=pymunk.Space()
self.space.gravity=(0,300)
self.space.collision_persistence=0
self.fireball_radius=2
self.fire_radius=2
self.fireballs=[]
self.colors=[
(255,0,0),(255,127,80),(255,140,0),(255,160,122),(240,128,128),(255,99,71),(255,69,0),
(255,105,180),(255,20,147),(208,32,144),(176,48,96),(153,50,204),(255,48,48),
(238,44,44),(205,38,38),(255,255,0),(255,215,0),(255,185,15),(238,201,0),
(34,139,34),(46,139,87),(60,179,113),(0,255,127)
]
self.fires=[]
接下來,進行事件監聽,按下鼠標就可以創建火球
def listen(self):
for event in pygame.event.get():
if event.type==QUIT:
sys.exit()
if event.type==MOUSEBUTTONDOWN:
self.create_firework(x=pygame.mouse.get_pos()[0])
然后寫個創建煙花的方法,首先要有個body,設置body_type為DYNAMIC,因為煙花是動態的。然后設置body的位置,x坐標為傳參的x坐標,y坐標為屏幕最底部,接下來創建一個shape,形狀為circle,body對應的fireball_body傳進去就好了,然后設置radius(半徑),設置shape的彈性(這個不設置也可以,沒多大影響),將body和shape添加到空間中,用add添加,然后將煙花對應的shape對象、顏色、創建時間、爆炸前持續時間這四個參數歸在一個列表,將這個列表添加到fireballs中,最后就是要賦予body沖擊力了,使用apply_impulse_at_local_point方法
def create_firework(self,x):
fireball_body=pymunk.Body(mass=1,moment=100,body_type=pymunk.Body.DYNAMIC)
fireball_body.position=x,self.H
fireball_shape=pymunk.Circle(fireball_body,self.fireball_radius)
fireball_shape.elasticity=0.5
self.space.add(fireball_body,fireball_shape)
self.fireballs.append([fireball_shape,rd.choice(self.colors),time.time(),rd.uniform(1,2.2)]) # shape,color,startTime,lastTime
fireball_body.apply_impulse_at_local_point((0,rd.randint(-730,-500)),(0,0))
然后是draw的代碼(比較多),先是填充背景為黑色,然后使用while循環遍歷fireballs,將煙花繪制出來,檢查是否到達了爆炸時間,如果已經到達爆炸時間,那么將這個火球從煙花的列表中刪掉。接下來就要創建炸開來的火花,火花是向不同方向散開的,所以用for循環遍歷一圈的度數,每隔10°就有一個,length是斜邊長度,然后定義bias偏移量,因為火花散發力量和距離并不是固定的,所以每一次length都會浮動一點,但始終控制在25~100之間(maximum和minimum),因為apply_impulse_at_local_point發射出去時傳參是x軸的力量和y軸的力量,所以要使用三角函數計算臨邊和對邊的長度從而得到apply_impulse_at_local_point傳參的數值,又因為我們遍歷的是度數(degree),sin和cos計算的是弧度(radians),所以要先把度數通過math.radians轉化為弧度,再傳參到sin和cos中。計算出來之后,還是創建body和shape并設置一些基本的參數,添加到空間中,并添加到fires列表中,最后刪除已爆炸的煙花,別忘了變量i需要減1。
上面是對未爆炸的煙花進行遍歷,下面我們還需要對爆炸后形成的火花進行遍歷,如果超出范圍或已到達刪除時間就進行刪除的操作,邏輯差不多
draw的代碼如下
def draw(self):
self.screen.fill((0,0,0))
i=0
while i<len(self.fireballs):
fireball,color,startTime,lastTime=self.fireballs[i]
pygame.draw.circle(self.screen,color,fireball.body.position,self.fireball_radius)
nowTime=time.time()
boomTime=startTime+lastTime
if nowTime>boomTime:
popball=self.fireballs.pop(i)
length=50
for degree in range(90,450,10):
bias=1
length+=rd.randint(-bias,bias)
maximum,minimum=100,25
if length>maximum:
length=maximum
elif lengthmath.radians(degree)
x_force=math.sin(radians)*length
y_force=math.cos(radians)*length
body=pymunk.Body(mass=1,moment=100,body_type=pymunk.Body.DYNAMIC)
body.position=popball[0].body.position
shape=pymunk.Circle(body,self.fire_radius)
self.space.add(body,shape)
self.fires.append([shape,popball[1],time.time(),rd.uniform(0.5,1.5)]) # shape,color,startTime,lastTime
body.apply_impulse_at_local_point((x_force,y_force),(0,0))
self.space.remove(popball[0])
i-=1
i+=1
i=0
while i<len(self.fires):
fire,color,startTime,lastTime=self.fires[i]
pos=fire.body.position
pygame.draw.circle(self.screen,color,pos,self.fire_radius)
nowTime=time.time()
deleteTime=startTime+lastTime
if nowTime>deleteTime:
self.fires.pop(i)
self.space.remove(fire)
i-=1
elif pos[0]<0 or pos[0]>self.W or pos[1]>self.H:
self.fires.pop(i)
self.space.remove(fire)
i-=1
i+=1
寫到這兒,我們的煙花就差不多完成了,最后寫個run
def run(self):
clock=pygame.time.Clock()
FPS=60
while True:
clock.tick(FPS)
self.listen()
self.draw()
self.space.step(1/FPS)
pygame.display.update()
運行
if name ==" main ":
firework=Firework()
firework.run()
這樣就好啦!
最終代碼:
import pygame
from pygame.locals import *
import pymunk
from pymunk import pygame_util
import sys
import random as rd
import time
import math
class Firework:
def init (self):
pygame.init()
self.W,self.H=800,1000
self.screen=pygame.display.set_mode((self.W,self.H))
self.draw_options=pygame_util.DrawOptions(self.screen)
pygame.display.set_caption("2023元旦煙花")
self.space=pymunk.Space()
self.space.gravity=(0,300)
self.space.collision_persistence=0
self.fireball_radius=2
self.fire_radius=2
self.fireballs=[]
self.colors=[
(255,0,0),(255,127,80),(255,140,0),(255,160,122),(240,128,128),(255,99,71),(255,69,0),
(255,105,180),(255,20,147),(208,32,144),(176,48,96),(153,50,204),(255,48,48),
(238,44,44),(205,38,38),(255,255,0),(255,215,0),(255,185,15),(238,201,0),
(34,139,34),(46,139,87),(60,179,113),(0,255,127)
]
self.fires=[]
def listen(self):
for event in pygame.event.get():
if event.type==QUIT:
sys.exit()
if event.type==MOUSEBUTTONDOWN:
self.create_firework(x=pygame.mouse.get_pos()[0])
def create_firework(self,x):
fireball_body=pymunk.Body(mass=1,moment=100,body_type=pymunk.Body.DYNAMIC)
fireball_body.position=x,self.H
fireball_shape=pymunk.Circle(fireball_body,self.fireball_radius)
fireball_shape.elasticity=0.5
self.space.add(fireball_body,fireball_shape)
self.fireballs.append([fireball_shape,rd.choice(self.colors),time.time(),rd.uniform(1,2.2)]) # shape,color,startTime,lastTime
fireball_body.apply_impulse_at_local_point((0,rd.randint(-730,-500)),(0,0))
def draw(self):
self.screen.fill((0,0,0))
i=0
while i fireball,color,startTime,lastTime=self.fireballs[i] pygame.draw.circle(self.screen,color,fireball.body.position,self.fireball_radius) nowTime=time.time() boomTime=startTime+lastTime if nowTime>boomTime: popball=self.fireballs.pop(i) length=50 for degree in range(90,450,10): bias=1 length+=rd.randint(-bias,bias) maximum,minimum=100,25 if length>maximum: length=maximum elif length length=minimum radians=math.radians(degree) x_force=math.sin(radians)*length y_force=math.cos(radians)*length body=pymunk.Body(mass=1,moment=100,body_type=pymunk.Body.DYNAMIC) body.position=popball[0].body.position shape=pymunk.Circle(body,self.fire_radius) self.space.add(body,shape) self.fires.append([shape,popball[1],time.time(),rd.uniform(0.5,1.5)]) # shape,color,startTime,lastTime body.apply_impulse_at_local_point((x_force,y_force),(0,0)) self.space.remove(popball[0]) i-=1 i+=1 i=0 while i fire,color,startTime,lastTime=self.fires[i] pos=fire.body.position pygame.draw.circle(self.screen,color,pos,self.fire_radius) nowTime=time.time() deleteTime=startTime+lastTime if nowTime>deleteTime: self.fires.pop(i) self.space.remove(fire) i-=1 elif pos[0]<0 or pos[0]>self.W or pos[1]>self.H: self.fires.pop(i) self.space.remove(fire) i-=1 i+=1 def run(self): clock=pygame.time.Clock() FPS=60 while True: clock.tick(FPS) self.listen() self.draw() self.space.step(1/FPS) pygame.display.update() if name ==" main ": firework=Firework() firework.run() 此時我仿佛聽見你說:一直按鼠標手好酸啊! 那沒事,我們改成自動就好啦! 只需要修改一部分內容就好 首先需要一個自定義事件(全局變量) CREATE_FIREBALL=USEREVENT+1 run中while循環前添加這一行,用來啟動事件循環,第二個參數是間隔時間,單位是毫秒,可以自己修改 pygame.time.set_timer(CREATE_FIREBALL,120) 將listen改成這樣 def listen(self): for event in pygame.event.get(): if event.type==QUIT: sys.exit() if event.type==CREATE_FIREBALL: self.create_firework(x=rd.randint(0,self.W)) 這樣就大功告成啦! 原文鏈接:https://blog.csdn.net/leleprogrammer/article/details/128510460 編輯:何安
-
開發
+關注
關注
0文章
370瀏覽量
40836 -
python
+關注
關注
56文章
4792瀏覽量
84628
發布評論請先 登錄
相關推薦
評論