views:

63

answers:

3

I have a simple program that blits a background image onto the display area, and then puts a sprite in the upper left corner. The sprite uses colorkey transparency, but when I blit the sprite, the areas that should be transparent are black, instead. The color used for the colorkey is a greenish color, so the colorkey is doing something, at least.

Here's my main module, which has most of the display code:

import pygame
from pygame.locals import *

import sprites

try: 
    import psyco
    psyco.full()
except:
    print "psyco failed to import"

class PatchCon(object): # main game class
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((832, 768))
        pygame.display.set_caption('PatchCon')
        self.setBackground()
        self.sprites = pygame.sprite.RenderPlain((sprites.Actor("Reimu")))

    def refresh(self):
        self.sprites.update()
        self.screen.blit(self.background, (0,0))
        self.sprites.draw(self.screen)
        pygame.display.update()

    def setBackground(self):
        self.background = pygame.Surface(self.screen.get_size())
        backgrounds = sprites.loadImage('patchconbackgrounds.png')
        self.background.blit(backgrounds[0], (0,0), sprites.bgcoords[3])
        self.background = self.background.convert()

    def mainLoop(self):
        while True:
            for event in pygame.event.get():
                if event.type == QUIT: return
            self.refresh()



if __name__ == '__main__':
    game = PatchCon()
    game.mainLoop()

My other module, 'sprites.py', deals with loading images and constructing sprite objects:

import os
import pygame
from pygame.locals import *


# there are four different backgrounds compiled into one big image.
bgcoords = ((0,0,832,768),
            (0,769,832,1537),
            (833,0,1664,768),
            (833,769,1664,1537))

# the top left pixels of characters' sprites in the sprite sheet
charCoords = { "Reimu" : (1, 10), 
               "Marisa" : (334, 10)} 


def loadImage(name, colorkey=None):
    fullname = os.path.join('images', name)
    try:
        image = pygame.image.load(fullname)
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    image = image.convert_alpha()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()



class SpriteDict(object):
    """SpriteDict has a list that holds all of the different images
    the sprites have.  It's in charge of finding character's sprites on a big
    sprite sheet and loading them into that list."""
    def __init__(self):
        self.spritesheet = loadImage("patchconsprites.png", pygame.Color('#007888'))[0]
        # more code here

    def choose(self, dir, step, color):
        """This function returns an image from the sprite list."""



class Actor(pygame.sprite.Sprite):
    def __init__(self, name):
        pygame.sprite.Sprite.__init__(self)
        self.sprites = SpriteDict(name)
        self.image = self.sprites.choose('N', 0, 1)
        self.rect = self.image.get_rect()

All the tutorials I've found lead me to believe this code is correct. Anyone see what I'm doing wrong?


EDIT: searching around the related questions, I found that image.convert() doesn't preserve alpha pixels, so as suggested in another question, I changed it to image.convert_alpha(). Now, however, instead of black areas, I just get the color of the colorkey. I've triple-checked the color value, and I'm certain its correct. Anything else I could be missing?

A: 

Your call to loadImage passes (implicitly) None as the colorkey parameter. Your loadImage function, when the colorkey is None, does not set any colorkey.

Joe
In the constructor of `SpriteDict`, I had a call to loadImage I forgot to show. It specifies the colorkey as '#007888'. Sorry about that.
Max
A: 

Well, I solved my problem. It involved changing the guts of SpriteDict so that it didn't call loadImage(), but instead handled loading the image and applying the transparency in the constructor itself, like so:

class SpriteDict(object):
    def __init__(self, name):
        self.spriteSize = (35, 35)
        # change this old line:
        #self.spritesheet = loadImage("patchconsprites.png", (0,120,136,0))[0]
        # to this:
        self.spritesheet = pygame.image.load("./images/patchconsprites.png")
        self.sprites = []
        start = charCoords[name]
        char = list(start)
        image = pygame.Surface((35,35))
        for y in range(5):
            char[0] = start[0]
            for x in range(9):
                rect = (char[0], char[1], char[0]+self.spriteSize[0], char[1]+self.spriteSize[1])
                image.blit(self.spritesheet, (0,0), rect)
                # and put the transparency code here:
                image = image.convert()
                colorkey = image.get_at((0,0))
                image.set_colorkey(colorkey, RLEACCEL)
                # end new code
                self.sprites.append(image)
                char[0] += self.spriteSize[0]+2
            char[1] += self.spriteSize[1]+2

It makes my code a lot messier, and probably a good bit slower, but it works. If someone could tell me why it has to work this way, and possibly how to make it not so ugly, that'd be great.

Max
A: 

The problem with the code that is posted in the question now is probably that you are mixing convert_alpha(), which results in a sprite with an alpha channel, with a color with alpha 255. A colorkey check in SDL is just an integer comparison, so even though you did not specify an alpha channel, you are only going to match 0x007888FF, not e.g. 0x007888FE or 0x00788800.

If you have a sprite with an alpha channel in the first place, there is no reason to use a colorkey. Simply use the sprite's alpha channel to make the parts you want transparent.

Joe
The sprite does not have an alpha channel. I had convert_alpha() there in an attempt to see if it would fix the problem. Originally I had regular convert() there.
Max