How to Change Sprite Colours in Pygame

Is it possible to change sprite colours in Pygame?

If the image is a "mask" image, with a transparent background and a white (255, 255, 255) mask, then you can "tint" the image with ease.

Load the image:

image = pygame.image.load(imageName)

Generate a uniform colored image with an alpha channel and the same size:

colorImage = pygame.Surface(image.get_size()).convert_alpha()
colorImage.fill(color)

Blend the image with maskImage, by using the filter BLEND_RGBA_MULT:

image.blit(colorImage, (0,0), special_flags = pygame.BLEND_RGBA_MULT)

A sprite class may look like this:

class MySprite(pygame.sprite.Sprite):

def __init__(self, imageName, color):
super().__init__()

self.image = pygame.image.load(imageName)
self.rect = self.image.get_rect()

colorImage = pygame.Surface(self.image.get_size()).convert_alpha()
colorImage.fill(color)
self.image.blit(colorImage, (0,0), special_flags = pygame.BLEND_RGBA_MULT)

Minimal example: Sample Image repl.it/@Rabbid76/PyGame-ChangeColorOfSurfaceArea-4

Sample Image

import pygame

def changColor(image, color):
colouredImage = pygame.Surface(image.get_size())
colouredImage.fill(color)

finalImage = image.copy()
finalImage.blit(colouredImage, (0, 0), special_flags = pygame.BLEND_MULT)
return finalImage

pygame.init()
window = pygame.display.set_mode((300, 160))

image = pygame.image.load('CarWhiteDragon256.png').convert_alpha()
hue = 0

clock = pygame.time.Clock()
nextColorTime = 0
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

color = pygame.Color(0)
color.hsla = (hue, 100, 50, 100)
hue = hue + 1 if hue < 360 else 0

color_image = changColor(image, color)

window.fill((96, 96, 64))
window.blit(color_image, color_image.get_rect(center = window.get_rect().center))
pygame.display.flip()

pygame.quit()
exit()

Sprite: Sample Image

Trying to make sections of sprite change colour, but whole sprite changes instead

self.image is the loaded image, where you want to change specific regions by a certain color and self.mask is a mask which defines the regions.

And you create an image masked, which contains the regions which are specified in mask tinted in a specific color.

So all you've to do is to .blit the tinted mask (masked) on the image without any special_flags set:

self.image.blit(self.masked, (0, 0))

See the example, where the red rectangle is changed to a blue rectangle:

Sample Image repl.it/@Rabbid76/PyGame-ChangeColorOfSurfaceArea

Sample Image


Minimal example: Sample Image repl.it/@Rabbid76/PyGame-ChangeColorOfSurfaceArea-3

Sprite: Sample Image

Mask: Sample Image

Sample Image

import pygame

def changColor(image, maskImage, newColor):
colouredImage = pygame.Surface(image.get_size())
colouredImage.fill(newColor)

masked = maskImage.copy()
masked.set_colorkey((0, 0, 0))
masked.blit(colouredImage, (0, 0), None, pygame.BLEND_RGBA_MULT)

finalImage = image.copy()
finalImage.blit(masked, (0, 0), None)

return finalImage

pygame.init()
window = pygame.display.set_mode((404, 84))

image = pygame.image.load('avatar64.png').convert_alpha()
maskImage = pygame.image.load('avatar64mask.png').convert_alpha()

colors = []
for hue in range (0, 360, 60):
colors.append(pygame.Color(0))
colors[-1].hsla = (hue, 100, 50, 100)

images = [changColor(image, maskImage, c) for c in colors]

clock = pygame.time.Clock()
nextColorTime = 0
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

window.fill((255, 255, 255))
for i, image in enumerate(images):
window.blit(image, (10 + i * 64, 10))
pygame.display.flip()

pygame.quit()
exit()

How can I change an image's color in Pygame?

If you want to fill the entire image with a single color but preserve the transparency, you can utilize two nested for loops and the pygame.Surface.set_at method to change every pixel of the surface.

import pygame as pg

pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
img = pg.Surface((150, 150), pg.SRCALPHA)
pg.draw.polygon(img, (0, 100, 200), ((75, 0), (150, 75), (75, 150), (0, 75)))

def set_color(img, color):
for x in range(img.get_width()):
for y in range(img.get_height()):
color.a = img.get_at((x, y)).a # Preserve the alpha value.
img.set_at((x, y), color) # Set the color of the pixel.

done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_j:
set_color(img, pg.Color(255, 0, 0))
elif event.key == pg.K_h:
set_color(img, pg.Color(0, 100, 200))

screen.fill(BG_COLOR)
screen.blit(img, (200, 200))
pg.display.flip()
clock.tick(60)

If you want to tint a surface, take a look at this post: https://stackoverflow.com/a/49017847/6220679

Change color of Pygame Surface

Your problem is that you keep creating new sprites every frame, so when you change the color of one Rectangle to green, it will be covered by a white one.

You do this by calling the fill function (which creates new Rectangle instances) inside the drawGrid function.

Pygame Ellipse change color to collide

Your .draw() function is only drawing the ball with a different colour while it's outside of the bounds of the display, which is never. What you instead want, is within your .check_collisions(), if a collision is detected, set a property on self determining which colour to use.

Then, in .draw(), instead of draw.ellipse(self.display, self.color_default, self.rect), you'd have draw.ellipse(self.display, self.current_colour, self.rect), or something similar.



Related Topics



Leave a reply



Submit