2

While testing my new-found python skills using pygame, I ran into an interesting problem. When I load planet .png images onto the screen, the planets show up with a black halo.

planet_with_halo

This is really strange since the other images(.png and .bmp) that I have loaded into the game work without a problem.

I have imported the images by using a for loop and converting them with convert_alpha(). When I do not convert the images, the black halo is still there. I also tried setting the color key with each iteration of the for loop to no avail:

class Pl_Images(pygame.sprite.Sprite):
    def __init__(self):
        self.pl_images = []
        for num in range(1,5):
            img = pygame.image.load(f"Images/planets/static/planet{num}.png")
            img_rect = img.get_rect()
            img = pygame.transform.scale(img, (int(img_rect.width//10), int(img_rect.height//10)))
            self.pl_images.append(img)

One of the pre-loaded images are then used (when needed) by a Planet object when it is created by the planet generator class "PlanetSurface" and is placed into a sprite group.

import pygame
from planet import Planet
import random
from pygame.sprite import Sprite
from pl_images import Pl_Images

class PlanetSurface(Sprite):
    def __init__(self, settings):
        """
           Creates a planet surface and planets that travel across the screen
         """
        super(PlanetSurface, self). __init__()
        self.settings = settings
        self.surface = pygame.surface.Surface(settings.screen.get_size())
        self.surface.set_colorkey([0,0,0])
        self.images = Pl_Images()
        self.planets = pygame.sprite.Group()
        self.pl_timer = random.randrange(420, 720) # 7 seconds and 12 seconds
        self.max_planets = 3
        self.current_num_planets = 0

    def update(self):
        """ update the planets """
        self.planets.update()
        for planet in self.planets.copy():
            if planet.rect.y > self.settings.screen_height:
                self.planets.remove(planet)
                self.current_num_planets -= 1
        if self.pl_timer == 0:
            if self.current_num_planets >= self.max_planets:
                pass
            else:
                self.new_planet = Planet(self.settings, self.images)
                self.rect = self.new_planet.rect
                self.planets.add(self.new_planet)
                self.pl_timer = random.randrange(2100, 3600)
        # Redraw planet for a smooth effect
        self.surface.fill((0,0,0))
        self.planets.draw(self.surface)
        self.pl_timer -= 1

Here is the Planet class:

class Planet(Sprite):
    def __init__(self, settings, images):
        super(Planet, self). __init__()
        self.images = images
        self.planets = self.images.pl_images
        self.settings = settings
        self.num_planets = len(self.planets)
        self.image_index = random.randrange(self.num_planets - 1)
        self.image = self.planets[self.image_index]
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(
                      0,
                      self.settings.screen_width - self.rect.width
                      )
        self.rect.y = -self.rect.height
        self.vel_x = 0
        self.vel_y = random.randrange(1, 2)

    def update(self):
        self.rect.x += self.vel_x
        self.rect.y += self.vel_y

The image is then drawn to the planet's surface when the update method is called. The surface that I am drawing the images to is a simple surface that uses a transparent colorkey:

This custom surface is being drawn by the main function on top of the main background but below the gaming surface:

self.screen.blit(self.background.bgimage, (self.background.bgX2,
    self.background.bgY2))
self.screen.blit(self.planet_surface.surface, (0,0))
self.screen.blit(self.game_surface.surface, (0,0))

I am quite baffled by this problem since the planets are .png images with transparent backgrounds. Does anyone have any idea where this black halo might be coming from?
Is there something that I am doing wrong or is this a glitch in pygame?

I have uploaded a sample planet for analysis. planet45.png

Thanks in advance!

ti7
  • 16,375
  • 6
  • 40
  • 68
python_noob
  • 107
  • 7
  • What's happening is that it's a transparency issue. PyGame is just rendering fully transparent regions as transparent, and everything else as opaque. As for why, I don't know how transparency works in PyGame unfortunately so someone else might need to help with that part. – Random Davis Jan 05 '21 at 23:28
  • I found [this question](https://stackoverflow.com/questions/13059092/transparent-sprites-in-pygame) which seems related, does that help? – Random Davis Jan 05 '21 at 23:30
  • That makes sense. Thanks for the feedback! Hopefully someone has a solution. – python_noob Jan 05 '21 at 23:31
  • Why do you set a color key `img.set_colorkey([0,0,0])`. You have PNGs. They should be transparent automatically. Remove `img.set_colorkey([0,0,0])` at least for the planet image. – Rabbid76 Jan 06 '21 at 08:48
  • You are correct. I had activated a transparent color key to see if it would help, but unfortunately it did not. I will update the code and remove this line. – python_noob Jan 06 '21 at 14:42
  • 2
    If the rest of your images work and only this one does not, then there is something obviously different about this image. It's been a while, but I used to work with image manipulation a lot. It was common to have to manipulate the alpha channel of an image and/or the compositing mode to get the right effect, and there were times where an image was just plain "wrong" and there was nothing you could do. If I recall correctly, "wrong" usually meant a background color being pre-assumed when it shouldn't have been. I suspect that here...a black background being incorrectly assumed. – CryptoFool Jan 06 '21 at 21:33
  • @Steve -unfortunately you and Rabbid76 are correct. I will have to find a new image that has alpha per pixel. Thanks for taking the time to answer. – python_noob Jan 07 '21 at 19:34
  • @Rabbid76 I meant that that was happening in this case, not that pygame doesn't support it. Obviously the issue turned out to be the image, not pygame, but I was just explaining what was happening, not saying that it was pygame's fault. – Random Davis Jan 08 '21 at 05:15
  • @RandomDavis I see. I apologize, I misunderstood you. – Rabbid76 Jan 08 '21 at 05:31

1 Answers1

2

I examined the example planet you provided in your question. - planet45.png

The alpha channel of the entire image is 255. The image has an opaque white background and a pale blue halo around the planet. You can set a white color (set_colorkey()) to make the background transparent, but the halo will remain opaque. The problem is not with your application, but with the image resource. You need to use another planet image that provides alpha per pixel.

See also How can I make an Image with a transparent Backround in Pygame? or How to convert the background color of image to match the color of Pygame window? respectively How do I blit a PNG with some transparency onto a surface in Pygame?.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174