I want to create an tranparent button and text on the screen, i search for the way to do this, the fourth RGB parameter and set_alpha can transparent the color
So i use self.button_color=(0,100,100,128) to set the button and self.text.set_alpha(128) to change the color on text
But nothing change when i run the scripts
Here's the code:
#!/usr/bin/python
import sys,os
import pygame
class Setting():
def __init__(self,width,height):
self.w=width
self.h=height
self.flag=pygame.RESIZABLE
self.screen=pygame.display.set_mode((self.w,self.h),self.flag)
self.screen_rect=self.screen.get_rect()
pygame.display.set_caption("Test")
class Button():
def __init__(self,setting,text):
self.width,self.height = 400,100
self.button_color=(0,100,100,128)
self.text_color=(255,0,0)
self.text = pygame.font.Font(None,100).render(text,True,self.text_color)
self.text.set_alpha(128)
self.rect = pygame.Rect(0,0,self.width,self.height)
self.rect.center = setting.screen_rect.center
self.text_rect = self.text.get_rect()
self.text_rect.center = self.rect.center
def draw_button(self,setting):
setting.screen.fill(self.button_color,self.rect)
setting.screen.blit(self.text,self.text_rect)
def game():
pygame.init()
setting=Setting(1200,800)
button=Button(setting,'PLAY')
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
setting.screen.fill((0,0,0))
button.draw_button(setting)
pygame.display.flip()
game()
Read the documentation of pygame.font.Font.render:
[...] Depending on the type of background and antialiasing used, this returns different types of Surfaces. For performance reasons, it is good to know what type of image will be used. [...] If the background is transparent a colorkey will be set. Antialiased images are rendered to 24-bit RGB images. If the background is transparent a pixel alpha will be included.
That means, if the antialias argument is True, then you have to set a transparent background color to generate a transparent text. e.g:
self.button_color=(0,100,100,128) # transparent alpha=128
self.text_color=(255,0,0)
self.text = pygame.font.Font(None,100).render(text,True,self.text_color, self.button_color)
Read the documentation of pygame.Surface.fill:
[...] The color argument can be either a RGB sequence, a RGBA sequence or a mapped color index. If using RGBA, the Alpha (A part of RGBA) is ignored unless the surface uses per pixel alpha (Surface has the SRCALPHA flag).
You have to create a pygame.Surface object with attribute SCRALPHA to draw a transparent rectangle:
rectsurf = pygame.Surface(self.rect.size,pygame.SRCALPHA)
rectsurf.fill(self.button_color)
setting.screen.blit(rectsurf,self.rect.topleft)
To achieve what you want, you have to blit the text on the rectangle, by using the special flag BLEND_MAX. draw_button just have to blit, the button rectangle, which contains the text, on the screen. e.g:
class Button():
def __init__(self,setting,text):
self.width,self.height = 400,100
self.button_color=(0,100,100,128)
self.text_color=(255,0,0,128)
self.text = pygame.font.Font(None,100).render(text,True,self.text_color, self.button_color)
self.rect = pygame.Rect(0,0,self.width,self.height)
self.text_rect = self.text.get_rect()
self.text_rect.center = self.rect.center
self.btnsurf = pygame.Surface(self.rect.size,pygame.SRCALPHA)
self.btnsurf.fill(self.button_color)
self.btnsurf.blit(self.text, self.text_rect, special_flags=pygame.BLEND_MAX)
self.rect.center = setting.screen_rect.center
def draw_button(self,setting):
setting.screen.blit(self.btnsurf,self.rect)
Related
I have a pygame Sprite which is generated through Font. It's just a 16x16 surface with a letter printed on it and blitted.
The sprite has a timer (it's a powerup) and when it's near the end of it's life I want it to flash a random color on every update. I've been successful doing this with other text but that text isn't a sprite, just a string I blit to the score board. I figured this would be the same, but once the sprite is generated, no matter how much I change the sprite's color, the change doesn't translate to the screen (though if I print(self.color) I can see the updated color tuple in the console).
I've tried putting the random color picker inside the Class as well as trying outside the class in my while loop. I can change the color easily enough, but the sprite on screen doesn't actually change. I am not using an external sprite image, just a Font blitted to a pygame.Surface.
This is my item class.
class Item(pygame.sprite.Sprite):
def __init__(self, name, pos):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.image = pygame.Surface([16, 16])
self.image.set_colorkey(black)
self.font = pygame.font.Font("./fonts/myfont.ttf", 16)
self.pos = pos
if self.name == "health":
self.color = (255, 0, 0)
self.text = self.font.render("H", True, self.color)
self.lifespan = 200
self.lifespan_counter = 0
self.image.blit(self.text, (0, 0))
def update(self):
# Update timer
self.lifespan_counter += 0.1
if self.lifespan_counter >= self.lifespan:
self.kill()
# Update position
self.rect.center = (int(self.pos[0]), int(self.pos[1]))
And then at the bottom of my def main() in the while loop, I have this stuff:
random_color_counter += 1
if random_color_counter > 3:
random_color = get_random_color()
random_color_counter = 0
screen.fill(background)
text_box.fill(blue)
game_box.fill(white)
# Update the sprites positions and then draw them to game_box surface
player_sprites.update()
player_bullet_sprites.update()
enemy_sprites.update()
enemy_bullet_sprites.update()
item_sprites.update()
player_sprites.draw(game_box)
player_bullet_sprites.draw(game_box)
enemy_sprites.draw(game_box)
enemy_bullet_sprites.draw(game_box)
item_sprites.draw(game_box)
...
for i in item_sprites:
game_box.blit(i.image, (int(i.pos[0]), int(i.pos[1])))
# Refresh everything
pygame.display.update()
And this is the function that picks a new color.
def get_random_color():
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
return r, g, b
And then I can use the color random_color for most things, just not sprites apparently.
Like I said, this displays the sprite just fine at the position it is supposed to (where the baddie died), but I cannot seem to have a change to the item sprites color translate to the screen. I'm just not seeing what I'm doing wrong.
When you want to change the color of the text, you have to render the text again and update the text Surface. Write a change_color method:
class Item(pygame.sprite.Sprite):
# [...]
def change_color(self, color):
self.image = pygame.Surface([16, 16])
self.image.set_colorkey(black)
self.color = color
self.text = self.font.render("H", True, self.color)
self.image.blit(self.text, (0, 0))
I'm coding some custom GUI objects for usage in pygame menus, while coding a scrollable box I hit an error.
This box works by moving a surface (which contains the components which are moved when scrolling) within a smaller surface which acts like a window to the confined surface. The surfaces mostly display correctly: the contents of the inner surface which are visible initially (the parts which fit within the window surface) display correctly, but when the inner surface is moved to reveal previously hidden components they are not displayed, the initial visible move correctly and are displayed when they return.
I think the issue is with the outer surface's clipping area thinking that only the already revealed components should be displayed and that the others are still hidden but I don't know.
The custom GUI components always have a Rect (returns the bounding rect for that component) and Draw (blits the component to the screen) functions.
Here is the code for the scroll area (and it's parent class):
class ScrollArea(BaseComponent):
"Implements a section of screen which is operable by scroll wheel"
def __init__(self,surface,rect,colour,components):
"""surface is what this is drawn on
rect is location + size
colour is colour of screen
components is iterable of components to scroll through (they need Draw and Rect functions), this changes the objects location and surface
"""
super().__init__(surface)
self.rect = pygame.Rect(rect)
self.colour = colour
self.components = components
self.Make()
def HandleEvent(self, event):
"Pass events to this; it enables the area to react to them"
if event.type == pygame.MOUSEBUTTONDOWN and self.rect.collidepoint(event.pos) and self._scroll_rect.h > self.rect.h:
if event.button == 4: self.scroll_y = min(self.scroll_y + 15,self._scroll_y_min)
if event.button == 5: self.scroll_y = max(self.scroll_y - 15,self._scroll_y_max)
def Make(self):
"Updates the area, activates any changes made"
_pos = self.rect.topleft
self._sub_surface = pygame.Surface(self.rect.size,pygame.SRCALPHA)
self.rect = pygame.Rect(_pos,self._sub_surface.get_rect().size)
self._sub_surface.unlock()#hopefully fixes issues
self._scroll_surf = pygame.Surface(self.rect.size)
self._scroll_rect = self._scroll_surf.get_rect()
scroll_height = 5
for component in self.components:
component.surface = self._scroll_surf
component.Rect().y = scroll_height
component.Rect().x = 5
component.Draw()
scroll_height += component.Rect().h + 5
self._scroll_rect.h = max(self.rect.h,scroll_height)
self.scroll_y = 0
self._scroll_y_min = 0
self._scroll_y_max = -(self._scroll_rect.h - self.rect.h)
def Draw(self):
"Draw the area and its inner components"
self._sub_surface.fill((255, 255, 255, 0))
self._sub_surface.blit(self._scroll_surf,(0,self.scroll_y))
pygame.draw.rect(self._sub_surface,self.colour,((0,0),self.rect.size),2)
self.surface.blit(self._sub_surface,self.rect.topleft)
def Rect(self):
"Return the rect of this component"
return self.rect
class BaseComponent:
def __init__(self,surface):
"surface is what this is drawn on"
self.surface = surface
def HandleEvent(self,event):
"Pass events into this for the component to react ot them"
raise NotImplementedError()
def Make(self):
"Redo calculations on how component looks"
raise NotImplementedError()
def Draw(self):
"Draw component"
raise NotImplementedError()
def ReDraw(self):
"Call Make then draw functions of component"
self.Make()
self.Draw()
def Rect(self):
"Return the rect of this component"
raise NotImplementedError()
To test this I used this code and a label component:
screen_width = 640
screen_height = 480
font_label = pygame.font.Font("freesansbold.ttf",22)
screen = pygame.display.set_mode((screen_width,screen_height))
grey = (125,125,125)
def LoadLoop():
#objects
scroll_components = []
for i in range(20):
scroll_components.append(Components.Label(screen,(0,0),str(i),font_label,grey))
scroll_area = Components.ScrollArea(screen,Components.CenterRect(screen_width/2,3*screen_height/16 + 120,300,200),grey,scroll_components)
clock = pygame.time.Clock()
running = True
while running:
#events
for event in pygame.event.get():
scroll_area.HandleEvent(event)
if event.type == pygame.QUIT:
running = False
pygame.quit()
exit()
#graphics
screen.fill(black)
scroll_area.Draw(components)
#render
pygame.display.update()
clock.tick(60)
This is the label component's code (it basically just prints text to screen with the location given as it's center):
class Label(BaseComponent):
"Class which implements placing text on a screen"
def __init__(self,surface,center,text,font,text_colour):
"""surface is what this is drawn on
center is the coordinates of where the text is to be located
text is the text of the label
font is the font of the label
text_colour is the text's colour
"""
super().__init__(surface)
self.center = center
self.text = text
self.font = font
self.text_colour = text_colour
self.Make()
def HandleEvent(self,event):
"Labels have no events they react to,\nso this does nothing"
def Make(self):
"(Re)creates the label which is drawn,\nthis must be used if any changes to the label are to be carried out"
self._text_surf = self.font.render(self.text, True, self.text_colour)
self._text_rect = self._text_surf.get_rect()
self._text_rect.center = self.center
def Draw(self):
"Draw the label , will not react to any changes made to the label"
self.surface.blit(self._text_surf,self._text_rect)
def Rect(self):
"Return the rect of this component"
return self._text_rect
This is the window produced by this code:
Before scrolling
After scrolling
I also did it with a different size of ScrollArea, one of the Labels was positioned through the bottom and it was cut in half, when scrolled the cut remained.
Please help.
Sidenote on conventions
First, a sidenote on conventions: class names should start with an uppercase letter, function and method names should be all lowercase.
They are conventions, so you are free to not follow them, but following the conventions will make your code more readable to people used to them.
The quick fix
The error is in the ScrollArea.Make() method. Look carefully at these two lines:
self._sub_surface = pygame.Surface(self.rect.size,pygame.SRCALPHA)
self._scroll_surf = pygame.Surface(self.rect.size)
self._sub_surface is the surface of the window of the scroll area. self._scroll_surf is the scrolling surface. The latter should be higher, but you set them to the same size (same width is fine, same height not).
Obviously when you loop over your component list to blit the Label, the ones which are outside self._sub_surface are also outside self._scroll_surf and hence are not blit at all. You should make self._scroll_surf higher. Try for example:
self._scroll_surf = pygame.Surface((self.rect.width, self.rect.height*10)
Better would be to estimate the proper height to contains all your labels, which should be scroll_height, but you calculate it later in the method, so you should figure how to do properly this part.
A general advice
In general, I think you have a design problem here:
for i in range(20):
scroll_components.append(Label(screen,(0,0),str(i),font_label,grey))
scroll_area = ScrollArea(screen, pygame.Rect(screen_width/2,3*screen_height/16 + 120,300,200),grey,scroll_components)
When you create each label, you pass the screen as the reference surface where the Draw method blits.
But these labels should be blitted on the scroll_surf of your ScrollArea. But you cannot do it because you have not instantiated yet the ScrollArea, and you cannot instantiate before the scroll area because you require the Labels to be passed as an argument.
And in fact in the ScrollArea.Make() method you overwrite each label surface attribute with the _scroll_surf Surface.
I think would be better to pass to ScrollArea a list of strings, and let the ScrollArea.__init__() method to create the labels.
It will look less patched and more coherent.
I seem to have problems with displaying text on the screen
The code draws text on the screen but half 'S' of 'Score' gets cut for reason.
However, if I change screen.blit(text, self.score_rect, self.score_rect) to screen.blit(text, self.score_rect), it works fine. I would like to know why is this happening and how can I fix this.
Thanks.
Here's the code:
class Score(object):
def __init__(self, bg, score=100):
self.score = score
self.score_rect = pygame.Rect((10,0), (200,50))
self.bg = bg
def update(self):
screen = pygame.display.get_surface()
font = pygame.font.Font('data/OpenSans-Light.ttf', 30)
WHITE = (255, 255, 255)
BG = (10, 10, 10)
score = "Score: " + str(self.score)
text = font.render(score, True, WHITE, BG)
text.set_colorkey(BG)
screen.blit(
self.bg,
self.score_rect,
self.score_rect)
screen.blit(text,
self.score_rect,
self.score_rect)
def main():
pygame.init()
#initialize pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption('Score Window')
#initialize background
bg = pygame.Surface((screen.get_size())).convert()
bg.fill((30, 30, 30))
screen.blit(bg, (0, 0))
#initialize scoreboard
score_board = Score(bg)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit(0)
score_board.update()
pygame.display.flip()
Well - it looks like the third parameter on the call do blit, where you repeat the core_rect` parameter is designed exactly to do that: it selects a rectangular area on the
source image (in this case your rendered text) to be pasted in the destination (in this case, the screen).
Text in Pygame is rendered with nice margins, you should not need the source-crop parameter at all - and if you thinbk ou do, you should pass it a suitable set of coordinates, relevant inside the rendered text, not therectangle with the destination coordinates on the screen.
From http://www.pygame.org/docs/ref/surface.html#pygame.Surface.blit:
blit() draw one image onto another blit(source, dest, area=None,
special_flags = 0) -> Rect Draws a source Surface onto this Surface.
The draw can be positioned with the dest argument. Dest can either be
pair of coordinates representing the upper left corner of the source.
A Rect can also be passed as the destination and the topleft corner of
the rectangle will be used as the position for the blit. The size of
the destination rectangle does not effect the blit.
An optional area rectangle can be passed as well. This represents a
smaller portion of the source Surface to draw.
...
I'm in the middle of working on a simple typing tutor using pygame. My problem is that I'm using an image that has a white background, waves1.png. Now's I've specified that I want white to be transparent in the image (self.image.set_colorkey((255, 255, 255))) and it is for everything except the text block. When the waves intersect with the text object, the white background of the waves show on top of the text. You can try running this if you have pygame (with the exception of the waves1.png image).
import pygame
from pygame.locals import *
class TextSprite(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.wordList = ['words yes', 'hello', 'this is a sentence', 'this is another sentence'] # read directly from external file
self.pos = 0
self.wordNum = 0
self.update1()
def update1(self):
# Render the given word
self.image = pygame.font.Font(None, 36).render(self.wordList[self.wordNum], 1, (0, 0, 0))
# Render the correctly guessed letters
self.correct = pygame.font.Font(None, 36).render(self.wordList[self.wordNum][:self.pos], 1, (255, 0, 0))
# Copy correct letters onto given word
self.image.blit(self.correct, (0, 0))
self.rect = self.image.get_rect()
# set the center of the center the given word to the center of the screen
self.rect.center = pygame.display.get_surface().get_rect().center
def keyin(self, key):
word = self.wordList[self.wordNum]
letter = word[self.pos]
if letter == key:
self.pos = self.pos + 1
if self.pos == len(word):
self.reset()
self.update1()
def reset(self):
self.pos = 0
self.wordNum = self.wordNum + 1
self.update1()
class Waves(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, filename):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.image.load(filename).convert()
# makes any white in the image transparent
self.image.set_colorkey((255, 255, 255))
self.rect = self.image.get_rect()
# Decrease the y coordinate so the waves look like they're moving up
def update(self, text):
self.rect.y = self.rect.y - 6
if self.rect.y <= 200:
text.reset()
self.rect.y = 485
def main():
#I - Import and initialize
pygame.init()
#D - Display configuration
# The screen variable is a pygame Surface object
# Note that the set_mode() method creates a Surface object for you automatically
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Typing Game")
#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255, 255, 255))
screen.blit(background, (0,0))
#A - Action (broken into ALTER steps)
#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True
# Collect the sprite in a list
all = pygame.sprite.RenderPlain()
waveList = pygame.sprite.RenderPlain()
text = TextSprite()
all.add(text)
waves = Waves("waves1.png")
waveList.add(waves)
waves.rect.x = 0
waves.rect.y = 485
#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
# Tick is a method in the Clock class that determines the maximum frame rate
clock.tick(30)
#E - Event handling
for event in pygame.event.get():
if event.type == QUIT:
keepGoing = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
keepGoing = False
else:
text.keyin(event.unicode)
# update position of waves
waves.update(text)
# clears screen
all.clear(screen, background)
# update screen
all.draw(screen)
waveList.clear(screen, background)
waveList.draw(screen)
# display.flip is a method that copies everything from the screen object to the actual visual display
pygame.display.flip()
pygame.quit ()
if __name__ == '__main__': main()
I don't know if it's an option for you, but you should get better results with png's native alpha transparency.
If you can edit/recreate the png yourself, then try using a transparent background.
From there, you can use convert_alpha() arfter loading the image. (instead of using a colorkey)
http://pygame.org/docs/ref/surface.html#Surface.convert_alpha
EDIT: one other aspect, is that the image may have an alpha channel interfering with the colorkey. Best to ensure you're not trying to use both.
I'm told that you can detect an image's alpha channel programmatically. Something like ...
if self.image.get_masks()[3]!=0:
print "image has alpha!"
See here http://pygame.org/docs/ref/surface.html#Surface.get_masks
HTH
Well done! You've actually done everything correctly to take advantage of transparency and colorkey (ie, making sure to call convert on the surface, making sure to pass the color into the set_colorkey method, etc).
The problem is with the order of calls to draw and clear on your respective sprite groups, "all" and "waveList". After you've rendered the text blocks by calling all.draw, you then follow it with the call to waveList.clear.
Here's the problem: once you've drawn the text sprites, you don't want to clear the space underneath the wave sprites, or that will wipe out the area that overlaps the already-drawn text blocks.
If you want to do this properly, try doing it in this order:
waves.update()
all.clear(screen,background)
waveList.clear(screen,background)
all.draw(screen)
waveList.draw(screen)
(more simply, just move waveList.clear(screen, background) to the line just below all.clear(screen, background); that should do it)
When I'm working with sprite groups, I usually try to group it so that each sprite group calls the same method in this order: clears, updates, collision checks (if any), draws.
This usually handles things in the right order. Then you still may have to pay attention to whether there is any layering of sprites, but that's another story for another day.
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?
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.
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.
Your call to loadImage passes (implicitly) None as the colorkey parameter. Your loadImage function, when the colorkey is None, does not set any 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.