2013-03-18 46 views
2

我正在製作一個函數,它將一個字符串分解成行,並返回一個表面,每行渲染爲前一行的下方。在pygame中的透明表面上渲染反鋸齒文本

例如:

Line1\nLine 2

呈現爲:

Line1 
Line2 

不管怎樣,我的問題是,我不能返回正確的透明表面到調用函數。我嘗試過使用顏色鍵,但它不適用於消除鋸齒的文本。有什麼辦法可以做到這一點?感謝您的回答。

我的代碼:(目前周圍留下文字醜陋的紫影)

def render_message(messages): 
    surfaces = [] 
    height = 0 
    max_width = 0 

    for message in messages.split('\n'): 
     surf = FONT.render(message, True, (0, 0, 0)) 
     surfaces.append(surf) 
     height += surf.get_height() + 5 
     if surf.get_width() > max_width: 
      max_width = surf.get_width() 

    result = pygame.Surface((max_width, height)) 
    result.fill((255, 0, 255)) 
    result.set_colorkey((255, 0, 255)) 

    top = 0 
    for surface in surfaces: 
     result.blit(surface, (max_width/2-surface.get_width()/2, top)) 
     top += surface.get_height() + 5 

    return result 

回答

0

發表了第二個答案,因爲這更復雜,人們可能想看到兩者。

multiline text screenshot

  • 12減少/增加字體大小
  • space切換BG

我離開文本換行了。編輯parse_text()以創建您想要的文本列表。

import pygame 
from pygame import Surface 
from pygame.locals import * 
# Todo: remove font object from TextLine() , to TextWall(). Then share a list of font's with any line. 

"""Example of multi-line text class, with alpha transparency.""" 
lorem = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed aliquet 
tellus eros, eu faucibus dui. Phasellus eleifend, massa id ornare sodales, est urna 
congue tellus, vitae varius metus nunc non enim. Mauris elementum, arcu vitae tempor euismod, justo turpis malesuada est, sed dictum nunc nulla nec mauris. Cras felis eros, elementum vitae sollicitudin in, elementum et augue. Proin eget nunc at dui congue pretium. Donec ut ipsum ut lacus mollis tristique. In pretium varius dui eu dictum. 

Proin pulvinar metus nec mi semper semper. Pellentesque habitant morbi tristique 
senectus et netus et malesuada fames ac turpis egestas. Proin in diam odio. Vestibulum 
at neque sed ante sodales eleifend quis id dui. Mauris sollicitudin, metus a semper consectetur, 
est lectus varius erat, sit amet ultrices tortor nisi id justo. Aliquam elementum vestibulum dui ut auctor. Mauris commodo sapien vitae augue tempus sagittis. Morbi a nibh lectus, sed porta nibh. Donec et est ac dui sodales aliquet tristique et arcu. Nullam enim felis, posuere vel rutrum eu, euismod a purus. Morbi porta cursus libero, id rutrum elit lacinia vitae. 

In condimentum ultrices ipsum, ut convallis odio egestas et. Cras at egestas elit. Morbi 
quis neque ligula. Sed tempor, sem at fringilla rhoncus, diam quam mollis nisi, vitae semper 
mi massa sit amet tellus. Vivamus congue commodo ornare. Morbi et mi non sem malesuada rutrum. Etiam est purus, interdum ut placerat sit amet, tempus eget eros. Duis eget augue quis diam facilisis blandit. Ut vulputate adipiscing eleifend. """ 

class TextLine(object): 
    # Manages drawing and caching a single line of text 
    # You can make font size, .color_fg etc be properties so they *automatically* toggle dirty bool. 
    def __init__(self, font=None, size=16, text="hi world"):   
     self.font_name = font 
     self.font_size = size 
     self.color_fg = Color("white") 
     self.color_bg = Color("gray20") 

     self._aa = True 
     self._text = text     
     self.font = pygame.font.Font(font, size) 
     self.screen = pygame.display.get_surface() 

     self.dirty = True 
     self.image = None 
     self._render() 

    def _render(self): 
     # render for cache 
     """no AA = automatic transparent. With AA you need to set the color key too""" 
     self.dirty = False   
     self.image = self.font.render(self._text, self.aa, self.color_fg)    
     self.rect = self.image.get_rect() 

    def draw(self): 
     # Call this do draw, always prefers to use cache 
     if self.dirty or (self.image is None): self._render() 
     self.screen.blit(self.image, self.rect)   

    @property 
    def text(self): 
     return self._text 

    @text.setter 
    def text(self, text): 
     self.dirty = True 
     self._text = text 

    @property 
    def aa(self): return self._aa 

    @aa.setter 
    def aa(self, aa): 
     self.dirty = True 
     self._aa = aa 

class TextWall(object): 
    # Manages multiple lines of text/paragraphs. 
    def __init__(self, font=None, size=16): 
     self.font = font 
     self.font_size = size   
     self.offset = Rect(20,20,1,1) # offset of whole wall 

     self.screen = pygame.display.get_surface() 
     self.dirty = True 
     self.text_lines = [] 
     self._text_paragraph = "Empty\nText" 
     self._render() 

    def _render(self): 
     # render list 
     self.dirty = False 
     self.text_lines = [ TextLine(self.font, self.font_size, line) for line in self._text_paragraph ]   

     # offset whole paragraph 
     self.text_lines[0].rect.top = self.offset.top 

     # offset the height of each line 
     prev = Rect(0,0,0,0)   
     for t in self.text_lines: 
      t.rect.top += prev.bottom 
      t.rect.left = self.offset.left 
      prev = t.rect 

    def parse_text(self, text): 
     # parse raw text to something usable 
     self._text_paragraph = text.split("\n") 
     self._render() 

    def draw(self): 
     # draw with cached surfaces  
     if self.dirty: self._render() 
     for text in self.text_lines: text.draw() 

    @property 
    def font_size(self): 
     return self._font_size 

    @font_size.setter 
    def font_size(self, size): 
     self.dirty = True 
     self._font_size = size 

    @property 
    def text(self): 
     return self._text_paragraph 

    @text.setter 
    def text(self, text_paragraph): 
     self.dirty = True 
     self.parse_text(text_paragraph) 

class Game(): 
    done = False 
    def __init__(self): 
     pygame.init() 
     self.screen = pygame.display.set_mode ((640,480)) 
     self.text = Surface([200,100]) 

     self.text_wall = TextWall() 
     self.toggle_bg = True 

     self.text_wall.parse_text(lorem) 

    def loop(self): 
     while not self.done: 
      self.handle_events() 
      self.draw() 

    def draw(self): 
     if self.toggle_bg: bg = Color("gray60") 
     else: bg = Color("gray20") 

     self.screen.fill(bg)   
     self.text_wall.draw()   
     pygame.display.update() 

    def handle_events(self): 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: self.done = True 

      elif event.type == KEYDOWN: 
       if event.key == K_ESCAPE: self.done = True     
       elif event.key == K_SPACE: self.toggle_bg = not self.toggle_bg 
       elif event.key == K_1: self.text_wall.font_size -= 3 
       elif event.key == K_2: self.text_wall.font_size += 3 

if __name__ == "__main__": 
    g = Game() 
    g.loop() 
+0

因此,讓我看看我是否理解你的答案。只需將每行文字直接繪製到屏幕上,您基本上就不再需要透明表面了? – thePurpleMonkey 2013-03-20 18:02:21

+0

否。它將文本渲染到具有alpha透明度的新表面。 (這是可變級別,顏色鍵只能使用單一級別)。當你想將它閃光到屏幕上,然後你將這個表面閃光。 – ninMonkey 2013-03-20 18:17:38

+0

原諒我這麼密集,但使用這種可變透明度的Surface在哪裏?我看到的只是字體直接傳送到屏幕上。 – thePurpleMonkey 2013-03-20 22:36:55

2

得到它的工作。主要不是我發現的是:沒有AA =自動透明。使用AA您也需要設置顏色鍵

這裏是一個工作示例,它切換BG以確保其透明。

import pygame 
from pygame import Surface 
#from pygame.locals import Rect, Color 
from pygame.locals import * 

class TextWall(): 
    def __init__(self, font=None, size=300): 
     # for simplicity uses one font, one size for now. 
     # You also can make font size, .text, etc be properties so they *automatically* toggle dirty bool. 
     self.font_name = font 
     self.font_size = size 
     self.color_fg = Color("white") 
     self.color_bg = Color("gray20") 
     self.aa = True 
     self.text = "hi world" 

     self.dirty = True 
     self.font = pygame.font.Font(font, size) 
     self.screen = pygame.display.get_surface() 


    def _render(self): 
     # re-render 
     """no AA = automatic transparent. With AA you need to set the color key too""" 
     self.dirty = False   
     self.text1 = self.font.render(self.text, self.aa, self.color_fg)    
     self.rect1 = self.text1.get_rect() 

    def draw(self): 
     # blits use cached surface, until text change makes it dirty 
     if self.dirty or self.text1 is None: self._render() 
     self.screen.blit(self.text1, self.rect1) 

    def text(self, text): 
     self.dirty = True 
     self.text_message = text # parse 

class Game(): 
    done = False 
    def __init__(self): 
     pygame.init() 
     self.screen = pygame.display.set_mode ((640,480)) 
     self.text = Surface([200,100]) 

     self.text_wall = TextWall() 
     self.toggle_bg = True 
    def loop(self): 
     while not self.done: 
      self.handle_events() 
      self.draw() 

    def draw(self): 
     if self.toggle_bg: bg = Color("darkred") 
     else: bg = Color("gray20") 

     self.screen.fill(bg)   
     self.text_wall.draw()   
     pygame.display.update() 

    def handle_events(self): 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: self.done = True 

      elif event.type == KEYDOWN: 
       if event.key == K_ESCAPE: self.done = True     
       elif event.key == K_SPACE: self.toggle_bg = not self.toggle_bg 
       elif event.key == K_a: 
        self.text_wall.aa = not self.text_wall.aa 
        self.text_wall.dirty = True 


if __name__ == "__main__": 
    g = Game() 
    g.loop() 

編輯:改進的代碼,使用alpha通道,而不是set_colorkey。

+0

對不起,但在我的機器上,即使使用您的代碼,問題仍然存在。我下載並運行了你的代碼,但是我仍然看到了字母周圍的灰色。我改變了字體顏色,背景顏色和幾乎所有我能想到的東西,但它拒絕透明。 – thePurpleMonkey 2013-03-19 04:55:07

+0

我的代碼沒有變化嗎?我只是再次測試我的,它的工作。 - 您的顯示器上是否有任何標誌或每像素設置了一定的位數? – ninMonkey 2013-03-19 15:43:09

+0

是的。我逐字地運行你的代碼,並且邊緣有灰色。不是很多,(可能是因爲系統字體非常線性),但仍然存在。將背景和顏色鍵設置爲綠色使其更易於看到。我不知道旗幟,據我所知,一切都設置爲默認值。 – thePurpleMonkey 2013-03-19 16:41:19