Efekty nad fontem
Minule jsme si ze znaků připravili svg. Teď to svg vezmeme, a tam, kde jsou čáry, si uděláme kuličky, a s nimi pak něco provedeme.
Paricles
Mám dilema, jak důkladně popisovat mechaniky pygame
. Zůstanu asi jen u principu
spritů a skupin. Sprite je něco, co má obdélník (rect
), obrázek (image
),
a metodu update
. Skupina obsahuje sprity, a umí na nich volat update
,
a vykreslit je.
Zkusme něco jednoduchého:
class Particle(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.start = (x, y)
self.x = x
self.y = y
self.r = 0
self.speed = random.randint(1, 5)
self.image = pygame.Surface((self.r * 2, self.r * 2), pygame.SRCALPHA)
self.rect = self.image.get_rect(center=(self.x, self.y))
def update(self, dt):
self.r += self.speed * dt / 400
self.image = pygame.Surface((self.r * 2, self.r * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, (192, 255, 255), (self.r, self.r), self.r, width=0)
pygame.draw.circle(self.image, (0, 128, 128), (self.r, self.r), self.r, width=2)
self.rect = self.image.get_rect(center=(self.x, self.y))
Tento particle vznikne, a pak se zvětšuje náhodnou rychlostí. To je vše. Pár jich naaranžujeme to kolečka, a necháme to běžět:
self.particles = pygame.sprite.Group()
for i in range(100):
angle = random.random() * math.pi * 2
self.particles.add(Particle(x + math.sin(angle) * r, y + math.cos(angle) * r))
dt = 1
clock = pygame.time.Clock()
while do_run:
self.screen.fill((0, 0, 0))
self.particles.update(dt=dt)
self.particles.draw(self.screen)
pygame.display.flip()
dt = clock.tick(60)
Na tenhle styl to pak bude všechno ostatní. Chcete, aby částice padaly? Letěly na
stranu? Měnily barvu? Jenom přepište update
. Co třeba:
Jak tušíte, tady používáme 2 typy spritů, nebo mohu-li to tak říct, particlů. Máme hvězdu, která vznikne v konstantní vzdálenosti od středu, a pak se pohybuje ven, a zároveň rotuje oproti středu. Když vypadne z obrazu, tak se zresetuje:
class Star(pygame.sprite.Sprite):
def __init__(self, center, r, angle):
super().__init__()
self.center = center
self.angle = angle
self.dist0 = self.dist = r
self.r = random.randrange(2, 6)
self.speed = random.randint(1, 5)
self.image = pygame.Surface((self.r * 2, self.r * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, (192, 255, 255), (self.r, self.r), self.r, width=0)
pygame.draw.circle(self.image, (0, 128, 128), (self.r, self.r), self.r, width=2)
def update(self, dt):
self.dist += self.speed * dt / 40
self.angle += self.speed * dt / 40000
self.speed *= 1.1
x = self.center[0] + math.sin(self.angle) * self.dist
y = self.center[1] + math.cos(self.angle) * self.dist
self.rect = self.image.get_rect(center=(x, y))
if x < 0 or x > PGMTest.WIDTH or y < 0 or y > PGMTest.HEIGHT:
self.reset()
def reset(self):
self.dist = self.dist0
self.angle = random.random() * math.pi * 2
self.speed = random.randint(1, 5)
Pak máme tu žhavou kružnici, ve které zůstávají particly ve stejné vzdálenosti od středu, jen rotují.
class Glow(pygame.sprite.Sprite):
def __init__(self, center, r, angle):
super().__init__()
self.center = center
self.angle = angle
self.dist0 = self.dist = r
self.r = random.randrange(6, 12)
self.speed = random.randint(15, 25)
self.image = pygame.Surface((self.r * 2, self.r * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, (255, random.randrange(78, 220), 1), (self.r, self.r), self.r, width=0)
pygame.draw.circle(self.image, (255, 78, 1), (self.r, self.r), self.r, width=1)
def update(self, dt):
self.angle += self.speed * dt / 40000
x = self.center[0] + math.sin(self.angle) * self.dist
y = self.center[1] + math.cos(self.angle) * self.dist
self.rect = self.image.get_rect(center=(x, y))
Zpět k fontu
Kružnice je jednoduchá. Teď ale musíme získat seznam bodů, na kterých vytvoříme
ty particly, které pak necháme animovat. Vzpomínáte si z minula na náš self.bg_img
a self.fg_img
? Paradoxně, self.bg_img
je ta kontura a self.fg_img
je
černě vyplněná plocha. Takže když si z self.bg_img
vezmeme body, na ně
umístíme particly, a pak to necháme běžet, měli bychom dostat to, co chceme.
Tato funkce vezme obrázek, rozčtverečkuje jej na čtverce o velikosti modulo
,
a pokud je v nějakém čtverci nějaká barva, tak vrátí souřadnice toho bodu:
def extract_points(self, image: pygame.Surface, modulo: int = 2) -> list[tuple[int, int]]:
points = []
for x in range(0, image.get_width() // modulo * modulo, modulo):
for y in range(0, image.get_height() // modulo * modulo, modulo):
v = 0
out = False
for i in range(modulo):
for j in range(modulo):
if sum(image.get_at((x + i, y + j))[0:3]):
points.append((x + i, y + j))
out = True
break
if out:
break
return points
Začneme prostě s těma zvětšujícíma se kuličkama:
def create_particles(self):
self.points = self.extract_points(self.bg_img, 20)
random.shuffle(self.points)
self.particles = pygame.sprite.Group()
for i in self.points:
self.particles.add(Particle(*i))
Jak Particle
jsme použili náš první Particle
, a obrázek je
starý známý self.fg_img
.
Celý kód naleznete zde.
O dalších efektech se nechci dál rozepisovat, vidíte asi sami, že na tom nic těžkého není. Dovolte mi jen zmínit, že pro efekt hoření jsem použil tento kód.
Cesta je prach a štěrk
Příště zkusíme, zda bychom dokázali jít po té cestě, která tvoří obrys písmena.
Komentáře byly zrušeny
V EU teď máme složitou situaci s Cookies. Na komentáře jsem používal jistou službu třetí strany. Ta však používá Cookies poměrně, ehm, benevolentně. Tak jsem se rozhodl komentáře zrušit. Pokud chcete, můžete mi napsat přímo