当在 Pygame 中使用 colorkey 透明度位块分割精灵时,应该透明的区域是黑色的

发布于 2024-09-19 00:48:49 字数 3149 浏览 6 评论 0原文

我有一个简单的程序,它将背景图像传输到显示区域,然后将精灵放在左上角。精灵使用 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'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()

我找到的所有教程都让我相信这段代码是正确的。有人看到我做错了什么吗?


编辑:搜索相关问题,我发现 image.convert() 不保留 alpha 像素,因此按照另一个问题中的建议,我将其更改为 image.convert_alpha()。然而现在,我只得到了色键的颜色,而不是黑色区域。我已经三次检查了颜色值,并且确信它是正确的。还有什么我可能会错过的吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

围归者 2024-09-26 00:50:38

这是我在 pygame 示例中找到的一段图像加载代码。您可以将其插入到您的主 python 文件中,以处理与脚本相同的工作,而无需导入它:

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 时会发生这种情况,但我不知道加载其他扩展格式时会发生什么。

该块用途极其广泛;您可以将其复制粘贴到任何脚本中,它就会起作用。当您想要加载图像时,请调用 load_image('image.bmp', -1)。 -1 的 colorkey 将告诉函数将像素定位在精灵的 0,0 处,然后将其用作 colorkey。

Here's a block of image loading code I found within the pygame examples. You can plug this into your main python file to handle the same job as your script, without having to import it:

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

Some notes:

Loading a circular object whose diameter touches the rect's dimensions will cause issues. You can fix that by making the image size larger than the circle. This happened when loading PNGs, but I don't know what happens when loading other extension formats.

This block is extremely versatile; you can copy-paste this in any script and it will work. When you want to load an image, call load_image('image.bmp', -1). a colorkey of -1 will tell the function to locate the pixel at 0,0 of the sprite, then use that as the colorkey.

心欲静而疯不止 2024-09-26 00:50:22

对 loadImage 的调用(隐式)传递 None 作为 colorkey 参数。当 colorkey 为 None 时,您的 loadImage 函数不会设置任何 colorkey。

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

莫言歌 2024-09-26 00:50:03

现在问题中发布的代码的问题可能是您正在混合convert_alpha(),这会导致带有alpha通道的精灵与alpha 255的颜色。SDL中的colorkey检查只是一个整数比较,因此,即使您没有指定 alpha 通道,您也只会匹配 0x007888FF,而不是 0x007888FE 或 0x00788800。

如果您首先有一个带有 Alpha 通道的精灵,则没有理由使用颜色键。只需使用精灵的 Alpha 通道即可使您想要的部分变得透明。

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.

谎言月老 2024-09-26 00:49:40

好吧,我解决了我的问题。它涉及更改 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

它使我的代码变得更加混乱,并且可能会慢一些,但它确实有效。如果有人能告诉我为什么它必须以这种方式工作,以及如何让它不那么难看,那就太好了。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文