При перетаскивании спрайта с прозрачностью с помощью цветовой клавиши в Pygame области, которые должны быть прозрачными, будут черными

1

У меня есть простая программа, которая сбрасывает фоновое изображение на область отображения, а затем помещает спрайт в верхний левый угол. Спрайт использует прозрачность colorkey, но когда я заливаю спрайт, области, которые должны быть прозрачными, являются черными. Цвет, используемый для colorkey, является зеленоватым цветом, поэтому colorkey делает что-то, по крайней мере.

Здесь мой основной модуль, который имеет большую часть отображаемого кода:

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()

Мой другой модуль, sprites.py, имеет дело с загрузкой изображений и конструированием объектов спрайтов:

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 in charge of finding character 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()

Все обучающие материалы, которые я нашел, заставляют меня считать, что этот код верен. Кто-нибудь видит, что я делаю неправильно?


EDIT: поиск по связанным вопросам, я обнаружил, что image.convert() не сохраняет альфа-пиксели, так как в другом вопросе я изменил его на image.convert_alpha(). Теперь, однако, вместо черных областей, я просто получаю цвет colorkey. Я проверил трехзначное значение цвета, и я уверен, что это правильно. Что-нибудь еще, что мне не хватало?

Теги:
pygame
transparency

4 ответа

1
Лучший ответ

Хорошо, я решил свою проблему. Это связано с изменением кишок SpriteDict, чтобы он не вызывал loadImage(), а вместо этого обрабатывал загрузку изображения и применял прозрачность в самом конструкторе, например:

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

Это делает мой код намного более грязным и, вероятно, немного медленнее, но он работает. Если кто-то может сказать мне, почему он должен работать таким образом, и, возможно, как сделать его не таким уродливым, это было бы здорово.

1

Проблема с кодом, опубликованным в вопросе сейчас, вероятно, заключается в том, что вы смешиваете convert_alpha(), что приводит к спрайту с альфа-каналом, с цветом с альфа-255. Проверка colorkey в SDL - это просто целочисленное сравнение, поэтому, хотя вы не указали альфа-канал, вы будете только соответствовать 0x007888FF, а не, например, 0x007888FE или 0x00788800.

Если у вас есть спрайт с альфа-каналом в первую очередь, нет причин использовать colorkey. Просто используйте альфа-канал спрайта, чтобы сделать части, которые вы хотите прозрачными.

  • 0
    Спрайт не имеет альфа-канала. У меня была convert_alpha (), чтобы посмотреть, решит ли это проблему. Первоначально у меня там была обычная функция convert ().
0

Вот блок кода загрузки изображения, который я нашел в примерах pygame. Вы можете подключить его к основному файлу python для обработки того же задания, что и ваш script, без необходимости его импорта:

import os, sys #required to use this block
...
-snip-
...
def load_image(name, colorkey=None):
    fullname = os.path.join('name for images folder here', name)
    try:
        image = pygame.image.load(fullname)
    except pygame.error, message:
        print 'Cannot load image:', name
        raise SystemExit, message
    image = image.convert()
    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()

Некоторые примечания:

Загрузка кругового объекта, диаметр которого касается прямоугольных размеров, вызовет проблемы. Вы можете исправить это, сделав размер изображения больше круга. Это произошло при загрузке PNG, но я не знаю, что происходит при загрузке других форматов расширений.

Этот блок чрезвычайно универсален; вы можете скопировать-вставить это в любой script, и он будет работать. Когда вы хотите загрузить изображение, вызовите load_image('image.bmp', -1). colorkey из -1 скажет функции найти пиксель в 0,0 спрайта, а затем использовать его как colorkey.

0

Ваш вызов loadImage пропускает (неявно) None как параметр colorkey. Функция loadImage, когда colorkey равна None, не устанавливает никаких colorkey.

  • 0
    В конструкторе SpriteDict меня был вызов loadImage, который я забыл показать. Он определяет цветовой ключ как «# 007888». Прости за это.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню