更新於 2024/10/11閱讀時間約 12 分鐘

The Nature of Code閱讀心得與Python實作:4.5 A System of Systems

集合許多個別的粒子可以形成一個粒子系統,那集合許多粒子系統,是不是也能形成一個系統呢?

當然可以!

既然集合許多粒子系統可以形成一個系統,那集合許多由粒子系統形成的系統,可不可以又形成一個系統呢?

當然也可以!

接下來,我們會以同樣的思路來處理含有許多粒子系統的系統。

在上一節中,我們讓許多粒子形成一個發射器系統;在這一節中,我們會來處理由許多發射器所構成的系統。

在Example 4.3中,我們處理的是單一的粒子系統:畫面上就只有一個不斷冒出粒子的發射器粒子系統。程式的寫法,是把那個系統指定給一個變數emitter,然後不斷把新的粒子加進emitter中,並呼叫emitterrun()方法:

現在,如果我們希望一開始的時候畫面上沒有任何發射器粒子系統,然後每當按下滑鼠左鍵時,就會在滑鼠游標所在的地方放置一個發射器粒子系統,那程式要怎麼寫呢?在設計Emitter這個類別時,我們是把系統所含的粒子放在一個list中。現在的做法也一樣,就把粒子系統放在一個叫做emitterslist中來處理;當按下滑鼠左鍵時,就新增一個發射器粒子系統到list中,然後針對所有在list中的發射器粒子系統,逐一新增粒子,並呼叫run()方法。

Example 4.4: A System of Systems

# python version 3.10.9
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 4.4: A System of Systems")

WHITE = (255, 255, 255)

screen_size = 640, 360
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

gravity = pygame.Vector2(0, 0.05)

# 一開始的時候,畫面上沒有任何粒子系統
emitters = []

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

screen.fill(WHITE)

# 當按下滑鼠左鍵時,就把粒子系統新增到list中
if pygame.mouse.get_pressed()[0]:
x, y = pygame.mouse.get_pos()
emitters.append(Emitter(x, y, 1))

# 針對所有在list中的粒子系統,逐一新增粒子,並呼叫run()方法
for emitter in emitters:
emitter.add_particle()
emitter.run()

pygame.display.update()
frame_rate.tick(FPS)

Exercise 4.5

Emitter類別的__init__()加入紀錄粒子庫存數量的變數:

self.inventory = 100

修改add_particle()

def add_particle(self):
if self.inventory > 0:
self.particles.append(Particle(self.origin.x, self.origin.y, self.mass))
self.inventory -= 1

主程式如下:

# python version 3.10.9
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Exercise 4.5")

WHITE = (255, 255, 255)

screen_size = 640, 360
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

gravity = pygame.Vector2(0, 0.05)

emitters = []

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

screen.fill(WHITE)

if pygame.mouse.get_pressed()[0]:
x, y = pygame.mouse.get_pos()
emitters.append(Emitter(x, y, 1))

for emitter in emitters:
emitter.add_particle()
emitter.run()

# 移除已經沒有粒子的粒子系統
emitters = list(filter(lambda emitter: bool(emitter.particles), emitters))

pygame.display.update()
frame_rate.tick(FPS)

Exercise 4.6

一開始的時候,讓粒子系統的粒子聚在一起,形成一個大的團塊。這時候,僅在畫面上顯示粒子,而不更新其狀態,等偵測到滑鼠點擊團塊時,才開始更新粒子的狀態。

修改Emitter類別。

修改__init__()方法,讓粒子系統的粒子在一開始的時候,就在畫面上結成團塊,同時加入用來紀錄粒子系統狀態的變數,以便判斷粒子系統是否正碎裂四散。

def __init__(self, x, y, mass):
self.mass = mass
self.size = 16*self.mass

# 一開始的粒子團塊
self.particles = [Particle(x+3*i, y+3*j, mass)
for i in range(10) for j in range(10)]

# 發射器位置
self.origin = pygame.Vector2(x, y)

# 粒子系統是否正碎裂四散?
self.shattering = False

修改run()方法,加入判斷粒子系統是否正碎裂四散的功能

def run(self):
if not self.shattering:
for particle in self.particles:
particle.show()
else:
for particle in self.particles:
particle.apply_force(gravity)
particle.update()

# 移除壽命已到的粒子
self.particles = list(filter(lambda particle: not particle.is_dead(), self.particles))

for particle in self.particles:
particle.show()

新增check_click()方法,用來偵測滑鼠是否點擊粒子團塊。當滑鼠點擊任何團塊中的粒子時,即表示滑鼠正點擊該粒子團塊。

def check_click(self, x, y):
for particle in self.particles:
d = pygame.Vector2(x, y).distance_to(particle.position)
if d <= particle.radius:
self.shattering = True
break

主程式如下:

# python version 3.10.9
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Exercise 4.6")

WHITE = (255, 255, 255)

screen_size = 640, 360
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

gravity = pygame.Vector2(0, 0.05)

emitters = [Emitter(100*i, 130, 1) for i in range(1, 6)]

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

screen.fill(WHITE)

for emitter in emitters:
if pygame.mouse.get_pressed()[0]:
x, y = pygame.mouse.get_pos()
emitter.check_click(x, y)

emitter.run()

pygame.display.update()
frame_rate.tick(FPS)


分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.