Files
card/card_game/effects.py
2026-05-24 08:10:22 +08:00

117 lines
3.8 KiB
Python

"""Visual effects: floating damage numbers, attack lines, ink splash."""
import math
import random
import pygame
from card_game.config import INK_BLACK, ZHU_HONG, TENG_HUANG
class FloatingText:
def __init__(self, x, y, text, color=ZHU_HONG, duration=60):
self.x = x
self.y = y
self.text = text
self.color = color
self.timer = duration
self.max_timer = duration
def update(self):
self.y -= 0.5
self.timer -= 1
return self.timer > 0
def draw(self, surface, font):
alpha = min(255, int(255 * self.timer / self.max_timer))
text_surf = font.render(self.text, True, self.color)
alpha_surf = pygame.Surface(text_surf.get_size(), pygame.SRCALPHA)
alpha_surf.fill((255, 255, 255, alpha))
text_surf.blit(alpha_surf, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
surface.blit(text_surf, (self.x - text_surf.get_width() // 2, int(self.y)))
class AttackLine:
def __init__(self, x1, y1, x2, y2, duration=20):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
self.timer = duration
self.max_timer = duration
def update(self):
self.timer -= 1
return self.timer > 0
def draw(self, surface):
progress = 1 - self.timer / self.max_timer
cx = self.x1 + (self.x2 - self.x1) * min(progress * 2, 1)
cy = self.y1 + (self.y2 - self.y1) * min(progress * 2, 1)
from card_game.ink_style import draw_brush_stroke
draw_brush_stroke(surface, (int(self.x1), int(self.y1)),
(int(cx), int(cy)), 3, TENG_HUANG, alpha=200)
class InkSplash:
def __init__(self, x, y, duration=30):
self.x = x
self.y = y
self.timer = duration
self.max_timer = duration
rng = random.Random(int(x * 100 + y))
self.particles = []
for _ in range(8):
angle = rng.uniform(0, 2 * math.pi)
speed = rng.uniform(1, 4)
size = rng.randint(3, 8)
self.particles.append((angle, speed, size))
def update(self):
self.timer -= 1
return self.timer > 0
def draw(self, surface):
progress = 1 - self.timer / self.max_timer
alpha = max(0, int(200 * (1 - progress)))
for angle, speed, size in self.particles:
dist = speed * progress * 30
px = int(self.x + dist * math.cos(angle))
py = int(self.y + dist * math.sin(angle))
current_size = max(1, int(size * (1 - progress * 0.5)))
s = pygame.Surface((current_size * 2, current_size * 2), pygame.SRCALPHA)
pygame.draw.circle(s, (*INK_BLACK[:3], alpha),
(current_size, current_size), current_size)
surface.blit(s, (px - current_size, py - current_size))
class EffectManager:
def __init__(self):
self.texts = []
self.lines = []
self.splashes = []
def add_damage(self, x, y, amount):
self.texts.append(FloatingText(x, y, f"-{amount}", ZHU_HONG))
def add_heal(self, x, y, amount):
self.texts.append(FloatingText(x, y, f"+{amount}", (70, 140, 80)))
def add_attack_line(self, x1, y1, x2, y2):
self.lines.append(AttackLine(x1, y1, x2, y2))
def add_ink_splash(self, x, y):
self.splashes.append(InkSplash(x, y))
def update(self):
self.texts = [t for t in self.texts if t.update()]
self.lines = [l for l in self.lines if l.update()]
self.splashes = [s for s in self.splashes if s.update()]
def draw(self, surface, font):
for line in self.lines:
line.draw(surface)
for splash in self.splashes:
splash.draw(surface)
for text in self.texts:
text.draw(surface, font)