2011-06-20 8 views
1

Je suis en train de travailler sur un tuteur de frappe simple en utilisant pygame. Mon problème est que j'utilise une image qui a un fond blanc, waves1.png. Maintenant, j'ai spécifié que je veux que le blanc soit transparent dans l'image (self.image.set_colorkey((255, 255, 255))) et il est pour tout sauf le bloc de texte. Lorsque les ondes se croisent avec l'objet text, le fond blanc des vagues apparaît au-dessus du texte. Vous pouvez essayer d'exécuter ceci si vous avez pygame (à l'exception de l'image waves1.png).problème de rendre l'arrière-plan de l'image transparente: pygame

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

Répondre

1

Je ne sais pas si c'est une option pour vous, mais vous devriez obtenir de meilleurs résultats avec la transparence alpha native de png.

Si vous pouvez éditer/recréer vous-même le png, essayez d'utiliser un arrière-plan transparent. À partir de là, vous pouvez utiliser convert_alpha() après le chargement de l'image. (Au lieu d'utiliser un code de couleur)

http://pygame.org/docs/ref/surface.html#Surface.convert_alpha

EDIT: un autre aspect, est que l'image peut avoir un canal alpha interférer avec la couleur de transparence. Le mieux est de vous assurer que vous n'essayez pas d'utiliser les deux.

On me dit que vous pouvez détecter le canal alpha d'une image par programmation. Quelque chose comme ...

if self.image.get_masks()[3]!=0: 
    print "image has alpha!" 

Voir ici http://pygame.org/docs/ref/surface.html#Surface.get_masks

HTH

1

bien fait! Vous avez tout fait correctement pour profiter de la transparence et de la clé de couleur (c'est-à-dire, vous assurer d'appeler convertir sur la surface, en veillant à passer la couleur dans la méthode set_colorkey, etc).

Le problème est avec l'ordre des appels à dessiner et effacer sur vos groupes d'images-objets respectifs, "all" et "waveList". Après avoir rendu les blocs de texte en appelant all.draw, vous le suivez avec l'appel à waveList.clear.

Voici le problème: une fois que vous avez dessiné les sprites de texte, vous ne voulez pas effacer l'espace sous les sprites d'onde, ou cela effacera la zone qui chevauche les blocs de texte déjà dessinés.

Si vous voulez faire cela correctement, essayez de le faire dans cet ordre:

  1. waves.update()
  2. all.clear (écran, arrière-plan)
  3. waveList.clear (écran, arrière-plan)
  4. all.draw (écran)
  5. waveList.draw (écran)

(mor e simplement, déplacez waveList.clear (écran, arrière-plan) sur la ligne juste en dessous de all.clear (écran, arrière-plan); Lorsque je travaille avec des groupes d'images-objets, j'essaie généralement de les regrouper afin que chaque groupe d'images-objets appelle la même méthode dans cet ordre: effacement, mises à jour, vérifications de collision (le cas échéant), dessins.

Ceci gère généralement les choses dans le bon ordre. Ensuite, vous devrez peut-être faire attention à ce qu'il y ait une superposition de lutins, mais c'est une autre histoire pour un autre jour.

Questions connexes