I'm making a 2D game in python using the module pygame. I would like to create a red vignette/bleed effect whenever the player takes damage in my game. This is seen in many games today, where the edges of the screen will flash red for a second and quickly disappear.
I have tried blitting an image I made in photoshop and scaling it accordingly during an animation cycle, but this was a really performance heavy operation, subsequently causing a lot of lag. I'm looking for alternatives to this method.
Code declaring a few variables:
bgX = 0
bgY = 0
damage = pygame.image.load("defensiveGameHUD.png").convert_alpha()
dimensions = [1920,1080]
Then I have this in the main loop of my game:
win.blit(background,(0,0))
if dimensions[0] != 4020:
dimensions[0] += 30
bgX -= 15
if dimensions[1] != 4600:
dimensions[1] += 40
bgY -= 20
if dimensions[1] != 4600:
screenDamage = pygame.transform.scale(damage, dimensions)
win.blit(screenDamage, (bgX, bgY))
else:
screenDamage = None
That is simply an animation that will scale the image in, however, the scaling is improper and this is very costly on performance.
def smmothstep(edge0, edge1, x):
t = min(1, max(0, (x - edge0) / (edge1 - edge0)))
return t * t * (3.0 - 2.0 * t)
def gen_damage_image(scale, source):
dest = source.copy()
img_size = dest.get_size()
for i in range(img_size[0]):
for j in range(img_size[1]):
fx = smmothstep(0, img_size[0]/2*scale, min(i, img_size[0]-i))
fy = smmothstep(0, img_size[1]/2*scale, min(j, img_size[1]-j))
color = dest.get_at((i, j))
fade_color = [int(255 - (1-fx*fy)*(255 - c)) for c in color]
dest.set_at((i, j), fade_color)
return dest
def tintDamage(surface, scale):
i = min(len(dmg_list)-1, max(0, int(scale*(len(dmg_list)-0.5))))
c.blit(dmg_list[i], (0, 0), special_flags = pygame.BLEND_MULT)
damage = pygame.image.load("defensiveGameHUD.png").convert_alpha()
max_dmg_img = 10
dmg_list = [gen_damage_image((i+1)/max_dmg_img, damage) for i in range(max_dmg_img)]
start_time = 0
tint = 0
damage_effect = False