def get_surface(room): surface = Surface((800, 600)) room["scrap"] = [] for wall in room["walls"]: pygame.draw.polygon(surface, dark_green, wall) if "ellipses" in room: for ellipse in room["ellipses"]: transparent_beige = (beige[0], beige[1], beige[2], 0) pygame.draw.ellipse(surface, transparent_beige, ellipse) for scrap_center in room["scrap_pile_coords"]: if scrap_center[2] is not None and scrap_center[2] == 1: scrap = pygame.image.load(f"resources/mutter/mutter_{scrap_i}.png") else: scrap = pygame.image.load(f"resources/screw/screw_{scrap_i}.png") scrap.set_colorkey(beige) scrap_rect = scrap.get_rect() scrap_rect.center = (scrap_center[0], scrap_center[1]) room["scrap"].append(scrap_rect) surface.blit(scrap, scrap_rect) return surface
class Ground(Platform): def __init__(self, surf, area, coords, width): super().__init__(surf, coords, width, 50) self.sprite = Surface((width, 50)) for i in range(0, width // 50): img = 'imgs/' + area + '-ground-' + str(randint(1, 3)) + '.png' self.sprite.blit(pg.image.load(img), (i * 50, 0))
def convert_to_colorkey_alpha(surf, colorkey=Color('magenta')): """Give the surface a colorkeyed background that will be transparent when drawing. Colorkey alpha, unlike per-pixel alpha, will keep the image's transparent background while using methods such as Surface.set_alpha(). Keyword arguments: surf (Surface): Will be converted to alpha using colorkey. colorkey (Color): The color value for the colorkey. The default is magenta or RGB(255, 0, 255). This should be set to a color that isn't present in the image, otherwise those areas with a matching colour will be drawn transparent as well. """ colorkeyed_surf = Surface(surf.get_size()) colorkeyed_surf.fill(colorkey) colorkeyed_surf.blit(surf, (0, 0)) colorkeyed_surf.set_colorkey(colorkey) colorkeyed_surf.convert() colorkeyed_surf.set_alpha(255) return colorkeyed_surf
class Runner(Sprite): def __init__(self): Sprite.__init__(self) self.sprite_image = './runnersprite.png' self.sprite_width = 70 self.sprite_height = 100 self.sprite_sheet = pygame.image.load(self.sprite_image).convert() self.sprite_columns = 14 self.current_frame = 0 self.image = Surface((self.sprite_width, self.sprite_height)) rect = (self.sprite_width * self.current_frame, 0, self.sprite_width, self.sprite_height) self.image.blit(self.sprite_sheet, (0, 0), rect) self.image.set_colorkey(Color(255, 0, 255)) self.rect = self.image.get_rect() def update(self): if self.current_frame == self.sprite_columns - 1: self.current_frame = 0 else: self.current_frame += 1 rect = (self.sprite_width * self.current_frame, 0, self.sprite_width, self.sprite_height) self.image.blit(self.sprite_sheet, (0, 0), rect)
def draw_snake(self, head_img, color, screen: Surface, blocksize: int): for part in self.body[:-1]: pygame.draw.rect(screen, color, \ [part.x * blocksize, part.y * blocksize,\ blocksize - 1, blocksize - 1]) screen.blit(head_img, (self.head.x * blocksize, self.head.y * blocksize))
def prepare_map(self): map_surface = Surface(self.map_rect.size) # print(self.resource_manager.maps) tile_map = self.resource_manager.maps[self.level_name] tile_size = self.textures["tile0"].get_rect().w tile_list = [] for row_idx, row in enumerate(tile_map): for column_idx, tile in enumerate(row): tile_rect = self.textures["tile" + str(tile)].get_rect().copy() tile_rect.topleft = (column_idx * tile_size, row_idx * tile_size) map_surface.blit(self.textures["tile" + str(tile)], tile_rect) if tile in [2]: tile_list.append([tile_rect, True]) elif tile == 1: spawn_point = tile_rect.topleft spawn_tile = (column_idx, row_idx) elif tile == 4: end_tile = (column_idx, row_idx) paths = self.prepare_paths(tile_map, spawn_tile, end_tile) return map_surface, tile_list, paths, spawn_point
def tile(image_name, surface): # PYGAME CHOKE POINT if image_name not in Graphics.PRE_RENDERS: bg_image = load_resource(image_name) sx, sy = Settings.SCREEN_SIZE # pre render the tiled background sx *= 2 # to the size of a full screen sy *= 2 pr_surface = Surface((sx, sy), SRCALPHA, 32) w, h = pr_surface.get_size() img_w, img_h = bg_image.get_size() for x in range(0, w + img_w, img_w): for y in range(0, h + img_h, img_h): pr_surface.blit(bg_image, (x, y)) Graphics.PRE_RENDERS[image_name] = pr_surface full_bg = Graphics.PRE_RENDERS[ image_name] # return a subsection of the full # # pre rendered background r = surface.get_rect().clip(full_bg.get_rect()) blit_region = full_bg.subsurface(r) surface.blit(blit_region, (0, 0)) return surface
class GameUI: def __init__(self, mainchar): self.bg = Surface((600, 1600)) self.statusbar = Surface((200, 600)) self.mainchar = mainchar self.widget = [] self.create_bg() def create_bg(self): rbg = self.bg.get_rect() bgimg = media.load_image('bg.png').convert() rbgimg = bgimg.get_rect() columns = int(rbg.width / rbgimg.width) + 1 rows = int(rbg.height / rbgimg.height) + 1 for y in xrange(rows): for x in xrange(columns): if x == 0 and y > 0: rbgimg = rbgimg.move([-(columns -1 ) * rbgimg.width, rbgimg.height]) if x > 0: rbgimg = rbgimg.move([rbgimg.width, 0]) self.bg.blit(bgimg, rbgimg) def update(self): r = pygame.rect.Rect(0, 0, 200, 100) for w in self.widget: w.update() self.statusbar.blit(w.image, r) r = r.move((0, 100))
def draw_status(self, surface: Surface): text = Fonts.shields.render( str(self.current_hull) + '/' + str(self.max_hull), True, (255, 255, 255)) text2 = Fonts.shields.render(str(self.command), True, (0, 255, 0)) surface.blit(text, (0, 30)) surface.blit(text2, (0, 10))
def display_dialog(surface: Surface, name: str, dialog: str): WIDTH = 455 HEIGHT = 205 BORDER = 5 IN_WIDTH = WIDTH - BORDER IN_HEIGHT = HEIGHT - BORDER canevas = Surface((WIDTH, HEIGHT)) canevas.fill(color.TEXT_BACKGROUND_COLOR) pos = Vector(dimensions.WINDOW_WIDTH - (30 + IN_WIDTH), dimensions.WINDOW_HEIGHT - (30 + IN_HEIGHT)) sizes = Vector(IN_WIDTH, IN_HEIGHT) rect = pygame.Rect(Vector().to_pos(), sizes.to_pos()) draw.rect(canevas, color.WHITE, rect, 5) font_name = ImagesCache().fonts["dialog"].render("{}: ".format(name), True, color.TEXT_NAME_COLOR) canevas.blit(font_name, (5, 4)) height = 30 for line in break_dialog_lines(dialog): font_text = ImagesCache().fonts["dialog"].render( line, True, color.TEXT_FOREGROUND_COLOR) canevas.blit(font_text, (10, height)) height += 20 return functools.partial(surface.blit, canevas, pos.to_pos())
def order_reversed_spritesheet(self, flipped_sheet): """Reorganize the frames in a flipped sprite sheet so that they are in the same order as the original sheet. Args: flipped_sheet: A PyGame Surface containing a flipped sprite sheet. Returns: A PyGame Surface containing the sprite sheet with each frame flipped and in the correct order. """ ordered_sheet = Surface((self.spritesheet.get_width(), self.spritesheet.get_height()), SRCALPHA) ordered_sheet.convert_alpha() for frame_index in xrange(0, self.get_num_of_frames()): frame_x = self.get_width() * frame_index old_frame_index = self.get_num_of_frames() - 1 - frame_index old_region = self.get_frame_region(old_frame_index) ordered_sheet.blit(flipped_sheet, (frame_x, 0), old_region) return ordered_sheet
def draw(self): """Draw battle field time. Returns: Surface: Drawn surface """ surface = Surface((self._width, self._height)) _minute, _second = divmod(math.ceil(self._jhclient.bf.time), 60) text = f"{_minute:02d}:{_second:02d}" # change text color by remaining time if _minute >= 1 and _second > 0: text = self.font.render(text, True, config.COLORS["white"]) elif _second > 30: text = self.font.render(text, True, config.COLORS["blue"]) elif _second > 10: text = self.font.render(text, True, config.COLORS["orange"]) else: text = self.font.render(text, True, config.COLORS["red"]) self.text_width, self.text_height = text.get_rect()[2:] _left = (self._width - self.text_width) // 2 _top = (self._height - self.text_height) // 2 surface.blit(text, (_left, _top)) return surface
class menu(object): def __init__(self, rect, width): self.surface = Surface((width, rect.height)) self.surface.fill((100,100,250)) self.buttonDict = dict() self.addButton(10, 10, 40, 40, "House") self.updateAll() def addButton(self, x, y, width, height, text): self.buttonDict[(x, y, width, height)] = (button.button(width, height, text)) def getButton(self, x, y): for myRect in self.buttonDict.keys(): if Rect(myRect[0], myRect[1], myRect[2], myRect[3]).collidepoint(x, y): return self.buttonDict[(myRect[0], myRect[1], myRect[2], myRect[3])].text return None def updateAll(self): for myRect, button in self.buttonDict.items(): self.surface.blit(button.surface, (myRect[0], myRect[1])) def getSurface(self): return self.surface
def update(self, duration): if self.dirty == 0: return # TODO: is bliting on existing surf faster than creating a new surface? size = self.rect.size txtcolor = self.txtcolor bgcolor = self.bgcolor if bgcolor: # opaque bg txtimg = self.font.render(self.text, True, txtcolor, bgcolor) txtimg = txtimg.convert() img = Surface(size) img.fill(bgcolor) else: # transparent bg txtimg = self.font.render(self.text, True, txtcolor) txtimg = txtimg.convert_alpha() img = Surface(size, SRCALPHA) # handle transparency img.fill((0, 0, 0, 0)) # 0 = transparent, 255 = opaque # center the txt inside its box ctr_y = size[1] / 2 textpos = txtimg.get_rect(left=2, centery=ctr_y) img.blit(txtimg, textpos) self.image = img
def prepare_table(rows, alignment="lr", size="normal", colour=(0,0,0), padding=0): f = FONTS[size] numcolumns = len(rows[0]) numrows = len(rows) def u(n): return n if isinstance(n, unicode) else unicode(n) shapes = [[f.size(u(col)) for col in row] for row in rows] maxheight = max(max(shape[1] for shape in shaperow) for shaperow in shapes) widths = [max(shaperow[i][0] for shaperow in shapes) for i in range(numcolumns)] table = Surface((sum(widths) + padding * (numcolumns - 1), maxheight * numrows + padding * (numrows - 1)), pygame.SRCALPHA) table.fill((255,255,255,0)) y = 0 for r, row in enumerate(rows): x = 0 for c, col in enumerate(row): w, h = shapes[r][c] text = prepare(u(col), size=size, colour=colour) align = alignment[c] if align == "r": adjustx = widths[c] - w elif align == "c": adjustx = (widths[c] - w) // 2 else: adjustx = 0 table.blit(text, (x + adjustx, y)) x += widths[c] + padding y += maxheight + padding return table
class Wall(Platform): def __init__(self, surf, area, coords, height): super().__init__(surf, coords, 50, height) self.sprite = Surface((50, height)) for i in range(0, height // 50): img = 'imgs/' + area + '-wall-right-' + str(randint(1, 3)) + '.png' self.sprite.blit(pg.image.load(img), (0, i * 50))
def update(self, duration): """ update all the contained linewidgets TODO: check that it works with transparent bg """ if self.dirty == 0: return # make the box size = self.rect.size bgcol = self.bgcolor if bgcol: # only display a bg img if bgcolor specified img = Surface(size) img.fill(bgcol) img = img.convert() else: # more or less transparent img = Surface(size, SRCALPHA) # handles transparency transparency = 50 # 0 = transparent, 255 = opaque img.fill((0, 0, 0, transparency)) img = img.convert_alpha() # blit each line numelemts = min(len(self.texts), self.maxnumlines) for i in range(numelemts): wid = self.linewidgets[i] wid.set_text(self.texts[-i - 1]) wid.update(duration) img.blit(wid.image, wid.rect) self.image = img
class Label(): def __init__(self, width, height, color): self.surface = Surface((width, height)) self.color = color self.surface.fill(color) def caption(self, text, fontStyle): myfont = font.SysFont(fontStyle.font, fontStyle.size) self.size = myfont.size(text) offsetX = (self.surface.get_width() - self.size[0]) / 2 offsetY = (self.surface.get_height() - self.size[1]) / 2 self.surface.fill(self.color) label = myfont.render(text, True, fontStyle.color) self.surface.blit(label, (offsetX, offsetY)) return self.surface def width(self): return self.size[0] def height(self): return self.size[1]
def __init__(self, fruit, interp_step): """ Prepare the fruit's spr: a square diamond with a number in the center. interp_step determines where to position the sprite, based on the view's current sprite step. """ DirtySprite.__init__(self) self.fruit = fruit # make the square sq_surf = Surface((cell_size / 1.414, cell_size / 1.414)) sq_surf.set_colorkey((255, 0, 255)) # magenta = color key sq_surf.fill(FRUIT_COLORS[fruit.fruit_type]) # rotate for a diamond dm_surf = rotate(sq_surf, 45) blit_rect = Rect(0, 0, cell_size * 1.414, cell_size * 1.414) # blit the diamond as the fruit's image img = Surface((cell_size, cell_size)) img.set_colorkey((255, 0, 255)) # magenta = color key img.fill((255, 0, 255)) img.blit(dm_surf, blit_rect) # add text at the center self.font = Font(None, font_size) txtsurf = self.font.render(str(fruit.fruit_num), True, (0, 0, 0)) textpos = txtsurf.get_rect(center=(cell_size / 2, cell_size / 2)) img.blit(txtsurf, textpos) # prepare rect to blit on screen self.resync(interp_step) self.image = img
def update(self, duration): """ update all the contained linewidgets. Return right away if no text has changed. """ if self.dirty == 0: # no new text has been added return # make the box size = self.rect.size bgcolor = self.bgcolor if bgcolor: # completely opaque bg img = Surface(size) img.fill(self.bgcolor) img = img.convert() else: # more or less transparent img = Surface(size, SRCALPHA) # handles transparency transparency = 50 # 0 = transparent, 255 = opaque img.fill((0, 0, 0, transparency)) # black img = img.convert_alpha() # blit each line for wid in self.linewidgets: wid.update(duration) img.blit(wid.image, wid.rect) self.image = img self.dirty = 0
def prepare_paragraph(text, width, size="normal", colour=(0,0,0)): font = FONTS[size] lines = [] words = text.split() if words: lastline = None line = words[0] for i in range(1,len(words)): lastline = line line = line+" "+words[i] w,h = font.size(line) if w > width: lines.append(lastline) line = words[i] else: line = "" lines.append(line) parawidth = max(font.size(each)[0] for each in lines) lineheight = font.get_height() paraheight = lineheight*len(lines) paragraph = Surface((parawidth,paraheight),pygame.SRCALPHA) paragraph.fill((255,255,255,0)) for y,line in enumerate(lines): text = prepare(line,size,colour) paragraph.blit(text,(0,y*lineheight)) return paragraph
class Runner(Sprite): #Sprite의 파생 클래스 정의. def __init__(self): Sprite.__init__(self) #1)Sprite.__init__()메소드를 호출. self.sprite_image = 'runnersprite.png' self.sprite_width = 70 self.sprite_height = 100 self.sprite_sheet = pygame.image.load( self.sprite_image).convert() self.sprite_columns = 14 self.current_frame = 0 #image데이터속성할당. self.image = Surface((self.sprite_width, self.sprite_height)) rect = (self.sprite_width*self.current_frame, 0, self.sprite_width, self.sprite_height) self.image.blit( self.sprite_sheet, (0, 0), rect) self.image.set_colorkey(Color(255, 0, 255)) #투명하게 표시할 생을 지정. self.rect = self.image.get_rect() #3)rect 데이터 속성 할당. def update(self): #4)update()정의 if self.current_frame == self.sprite_columns - 1: #마지막 이미지이면 self.current_frame = 0 #다시 처음 이미지로. else: self.current_frame += 1 rect = (self.sprite_width*self.current_frame, 0, self.sprite_width, self.sprite_height) self.image.blit( self.sprite_sheet, (0, 0), rect)
def makeMap(tiles, tileSz): R, C = tiles.shape surf = Surface((int(R * tileSz), int(C * tileSz))) for r in range(R): for c in range(C): surf.blit(tiles[r, c], (int(r * tileSz), int(c * tileSz))) return surf
def draw(self, surface: Surface, dest_rect: Rect, critter_location: Union[Rect, None]): """ Render a window into the maze into the main surface while making sure the critter at critter_location is visible :param surface: Main window's surface :param dest_rect: The rectangle of where in the window's that the viewable maze section is rendered into :param critter_location: Rectangle of critter to scroll maze around """ rect = self.rect.copy() if critter_location is not None: if RIGHT_SCROLL_LIM > critter_location.left > LEFT_SCROLL_LIM: rect.left = critter_location.left - LEFT_SCROLL_LIM elif critter_location.left < MID_PLAY_WIDTH: rect.left = 0 else: rect.left = RIGHT_SCROLL_LIM - MID_PLAY_WIDTH if BOT_SCROLL_LIM > critter_location.top > TOP_SCROLL_LIM: rect.top = critter_location.top - TOP_SCROLL_LIM elif critter_location.top < MID_PLAY_HEIGHT: rect.top = 0 else: rect.top = BOT_SCROLL_LIM - MID_PLAY_HEIGHT surface.blit(self.surface, dest_rect, rect)
class LeaderBoardText(Text): """ LeaderBoardText class extended from Text class. It creates the the leaderboard table sprite """ def __init__(self, game_env): Text.__init__(self, game_env, size=20) self.__game_env = game_env name_length = self.__game_env.static.name_length * 2 leaders = LeaderBoardHandler().load() seperator = self.font.render( '===================================================================================================', 1, self.color) header = self.font.render('=== HALL OF FAME ===', 1, self.color) all_surfaces = [] all_surfaces.append(seperator) all_surfaces.append( self.font.render( '{} {} {} {} {} {}'.format('RANK'.ljust(5), 'NAME'.ljust(name_length), 'SCORE'.ljust(10), 'LEVEL'.ljust(5), 'ACCURACY'.ljust(8), 'TIME'.rjust(21)), 1, self.color)) all_surfaces.append(seperator) try: if len(leaders) == 0: all_surfaces.append( self.font.render( 'No records, make sure you have working internet connectivity', 1, self.color)) for index, score in enumerate(leaders['scores']): all_surfaces.append( self.font.render( '{} {} {} {} {} {}'.format( str(index + 1).ljust(5), score['name'][:name_length].ljust(name_length), str(score['score']).ljust(10), str(score['level']).ljust(5), str(score['accuracy'] + '%').ljust(8), str(time.ctime(int(score['epoch']))).rjust(25)), 1, self.color)) except: pass all_surfaces.append(seperator) self.surf = Surface( (all_surfaces[2].get_width(), all_surfaces[0].get_height() * (len(all_surfaces) + 1)), self.__game_env.SRCALPHA) self.surf.blit(header, (self.surf.get_width() / 2 - header.get_width() / 2, 0)) for index, temp_surf in enumerate(all_surfaces): self.surf.blit( temp_surf, (0, header.get_height() + index * temp_surf.get_height())) self.rect = self.surf.get_rect( center=(self.__game_env.static.screen_width / 2, self.__game_env.static.screen_height / 2))
class ExitMenuText(Text): """ ExitText class extended from Text class. It creates the game exit menu with confirmation sprite """ def __init__(self, game_env): Text.__init__(self, game_env, size=38) self.__game_env = game_env self.__title = Text(self.__game_env, "Do you want to quit?", 48) self.__y_selected_surf = self.font.render( "Yes", 1, self.__game_env.static.text_selection_color ) # creating surface with Yes text when highlighted self.__n_surf = self.font.render( "/No", 1, self.color) # creating surface with No text self.__y_surf = self.font.render( "Yes/", 1, self.color) # creating surface with Yes text self.__n_selected_surf = self.font.render( "No", 1, self.__game_env.static.text_selection_color ) # creating surface with No text when highlighted self.__choices = self.__title.surf.get_width() / 2 - ( self.__y_selected_surf.get_width() + self.__n_surf.get_width()) / 2 self.__highlight_no() def __recreate_surf(self): self.surf = Surface( (self.__title.surf.get_width(), self.__title.surf.get_height() + self.__y_surf.get_height()), self.__game_env.SRCALPHA) self.surf.blit( self.__title.surf, (self.surf.get_width() / 2 - self.__title.surf.get_width() / 2, 0)) def update(self, pressed_keys): if pressed_keys[self.__game_env.K_LEFT]: self.__highlight_yes() elif pressed_keys[self.__game_env.K_RIGHT]: self.__highlight_no() self.rect = self.surf.get_rect( center=(self.__game_env.static.screen_width / 2, self.__game_env.static.screen_height / 2 + 10)) def __highlight_yes(self): self.__recreate_surf() self.surf.blit(self.__y_selected_surf, (self.__choices, self.__title.surf.get_height())) self.surf.blit(self.__n_surf, (self.__choices + self.__y_selected_surf.get_width(), self.__title.surf.get_height())) self.__game_env.dynamic.exit = True def __highlight_no(self): self.__recreate_surf() self.surf.blit(self.__y_surf, (self.__choices, self.__title.surf.get_height())) self.surf.blit(self.__n_selected_surf, (self.__choices + self.__y_surf.get_width(), self.__title.surf.get_height())) self.__game_env.dynamic.exit = False
def draw_status(self, surface: Surface): text = Fonts.shields.render( str(self.shields) + '/' + str(self.max_shields), True, (0, 0, 255)) text2 = Fonts.shields.render( str(self.aux_shields) + '/' + str(self.max_aux_shields), True, (0, 0, 255)) surface.blit(text, (0, 30)) surface.blit(text2, (0, 10))
def render_sprites(screen: Surface, background: Surface, sprites: List[AbstractSprite]) -> None: screen.blit(background, (0, 0)) for s in sprites: if not s.active: continue # print(f'Sprite: {s.name} is at {s.position}') screen.blit(s.image, s.rect.position)
class Projectile(Sprite, Attack): MAX_FRAMES = 2 FRAME_HEIGHT = 137 FRAME_WIDHT = 128 ANIMATION_STEPING = 2# value f.e. 10 means that each 10-th frame animation frame will be changed def __init__(self, projectileType, direction, position, damage): Sprite.__init__(self) Attack.__init__(self, damage) self.speed = 15 self.direction = direction self.frame = 0 self.size = 48 self.spriteSheet = pygame.image.load(projectileType.value) self.prapareSprite(self.frame) self.rect = self.image.get_rect() self.rect.x = position[0] self.rect.y = position[1] self.timelapsed = 0 self.animationDirection = 1 def calculateState(self): if self.frame < Projectile.MAX_FRAMES and self.frame >= 0: self.timelapsed += 1 if self.timelapsed % Projectile.ANIMATION_STEPING == 0: self.prapareSprite(self.frame) self.frame += self.animationDirection else: self.animationDirection *= -1 self.frame += self.animationDirection if self.direction == Direction.DOWN: self.rect.y += self.speed elif self.direction == Direction.UP: self.rect.y -= self.speed elif self.direction == Direction.LEFT: self.rect.x -= self.speed elif self.direction == Direction.RIGHT: self.rect.x += self.speed def prapareSprite(self, frame): self.image = Surface((Projectile.FRAME_HEIGHT,Projectile.FRAME_HEIGHT)) spX = Projectile.FRAME_WIDHT * frame spY = 0 self.image.blit(self.spriteSheet, (0, 0), (spX, spY, Projectile.FRAME_HEIGHT, Projectile.FRAME_HEIGHT)) self.image.set_colorkey((0, 0, 0)) self.image = pygame.transform.scale(self.image, (self.size, self.size)) if self.direction == Direction.DOWN: self.image = pygame.transform.rotate(self.image, -90) elif self.direction == Direction.UP: self.image = pygame.transform.rotate(self.image, 90) elif self.direction == Direction.LEFT: self.image = pygame.transform.flip(self.image, True, False) def delete(self): s = Settings() if self.rect.x + 2 * self.size < 0 or self.rect.x - self.size > s.screen_width or self.rect.y + 2 * self.size < 0 or self.rect.y - self.size > s.screen_height: return True return False
def draw(self, surface: Surface): for ind, scaledImg in enumerate(self.scaledImages): x = self.blockWidth * ind + self.blockWidth * self.XMARGIN surface.blit(scaledImg, (x, self.properties.HEIGHT * self.VMARGIN)) if self.waitingForInputFrom == ind: TextSurf, TextRect = Utils.textGenerator( self.labels[ind], self.labelFont, color.BLACK) TextRect.midtop = (self.properties.WIDTH / 2, self.labelY) surface.blit(TextSurf, TextRect)
def draw_status(self, surface: Surface): i = 0 j = 0 for weapon in self.weapons: surface.blit(WeaponRenderer.get_weapon_surface(weapon), (5 + i*10, 5 + j*10)) i += 1 if i > 3: i = 0 j += 1
def draw_status(self, surface: Surface): text = Fonts.shields.render( str(self.reactor_used) + '/' + str(self.reactor_value), True, (0, 255, 255)) surface.blit(text, (0, 30)) if self.overload_value > 0: text2 = Fonts.shields.render(str(self.overload_value), True, (0, 255, 255)) surface.blit(text2, (0, 10))
def draw_information(self, screen: Surface, index: int) -> Surface: """draws the recent action, energy and reward of the agent on the top right corner of the window""" text = self.font.render( 'Last Action: {} Energy: {:.2f} Reward: {:.2f}'.format(self.last_action, self.energy, self.reward), True, self.color, WHITE) text_rect = text.get_rect() text_rect.move_ip(GAME_WIDTH - text_rect.width, index * text_rect.height) screen.blit(text, text_rect)
def draw(self, surface: Surface, start_x: float, start_y: float, grid_width: float, score: int, font_color: Tuple[int, int, int]): self.score = self.font.render("Score: {:04d}".format(score), False, font_color) self.score_rect = self.score.get_rect() center_x = (grid_width * 0.5) + start_x center_y = start_y - 10 - (self.score_rect.height * 0.5) self.score_rect.center = (center_x, center_y) surface.blit(self.score, self.score_rect)
def draw(self, surface: Surface, dest_rect: Rect): self.display.fill(BACKGROUND_COLOR) for idx, digit in enumerate(self.value_list): digit_location = 16 * idx self.display.blit(self.digits, Rect(digit_location, 0, 16, 32), self.digit_rects[digit]) surface.blit(self.display, dest_rect)
def draw_status(self, surface: Surface): text = Fonts.shields.render( str(int(self.current_speed)) + '/' + str(self.max_speed), True, (255, 255, 255)) text2 = Fonts.shields.render( str(int(self.current_turn * 100)) + '/' + str(int(self.max_turn_speed * 100)), True, (255, 255, 255)) surface.blit(text, (0, 30)) surface.blit(text2, (0, 10))
class LoadingScene(AbstractScene): """ @type image: SurfaceType @type rect: pygame.rect.RectType """ image = None rect = None def __init__(self, manager): """ @type manager: slg.application.manager.Manager """ super().__init__(manager) self.group = GameSceneGroup(self) image = pygame.image.load(os.path.join(GUI_DIR, 'loading_screen.jpg')) self.image = Surface(self._manager.get_display().get_size()) self.rect = pygame.rect.Rect(self.image.get_rect()) image_size = image.get_size() surface_size = self.image.get_size() x = int((image_size[0] - surface_size[0]) / 2) y = int((image_size[1] - surface_size[1]) / 2) if x < 0 and y < 0: image = pygame.transform.scale(image, surface_size) x, y = 0, 0 elif x <= 0 <= y: image = pygame.transform.scale(image, (surface_size[0], image_size[1])) x = 0 elif y <= 0 <= x: image = pygame.transform.scale(image, (image_size[0], surface_size[1])) y = 0 styles = {'font': 'alger', 'font_size': 40, 'align': [TextWidget.CENTER, TextWidget.CENTER]} text = TextWidget(**styles) text.set_text("""Loading... Please wait""") self.image.blit(image, (-x, -y)) text.draw(self.image) def handle_events(self, events): self.group.handle_events(events) for e in events: if e.type == KEYDOWN: self.handle_keypress(e.key, pygame.key.get_mods()) def handle_keypress(self, key, modificated): if key == K_SPACE and self._manager.state < GAME_STATE_LOADING: ChangeState(int(not bool(self._manager.state))).post() if key == K_m and modificated and pygame.KMOD_CTRL: Selector(self._manager.get_display(), self.group) ChangeState(GAME_STATE_PAUSED).post() def draw(self): display_surface = self._manager.get_display() display_surface.blit(self.image, (0, 0)) self.group.update(display_surface) self.group.draw(display_surface)
def render_description(self, screen: Surface, position: Tuple) -> None: font = Fonts.MEDIUM_FONT font_size = font.size(self.description) position_rectangle = (position[0], position[1] - font_size[1], font_size[0] + 4, font_size[1] + 4) pygame.draw.rect(screen, Colors.White, position_rectangle, 0) pygame.draw.rect(screen, Colors.Black, position_rectangle, 1) label = font.render(self.description, 1, Colors.Blue) screen.blit(label, (position[0] + 2, position[1] - font_size[1] + 2))
def randomSprite(self, area, Type, reps, height, width, h=True, v=False): start = 'imgs/' + area + '-' + Type + '-' sprite = Surface((width, height)) if v: h = False for i in range(0, reps): img = start + str(randint(1, 3)) + '.png' if h: sprite.blit(pg.image.load(img), (i * 50, 0)) else: sprite.blit(pg.image.load(img), (0, i * 50)) return sprite
def update_hearts(self, surface: Surface): y = self.rect.centery-self.rect.size[1]/2-10 health_img = self.health_img.copy() for heart in range(int(self.health/20)): x = self.rect.centerx + heart * health_img.get_size()[0] surface.blit(health_img, (x, y)) if self.health >= 0: hp = pygame.font.SysFont(None, 15).render(str(self.health), True, (0, 0, 0)) surface.blit(hp, (self.rect.centerx, y-10))
def create_layer(self): bgimg = media.load_image('bg.png').convert() rbgimg = bgimg.get_rect() rows = int(600 / rbgimg.height) + 2 layer = Surface((rbgimg.width, 600)) for y in xrange(rows): layer.blit(bgimg, rbgimg) rbgimg = rbgimg.move([0, rbgimg.height]) return layer
def create_top(self): bgimg = media.load_image('tile_wall.png').convert() rbgimg = bgimg.get_rect() self.top_size = rbgimg.width cols = int(1000 / rbgimg.width) top = Surface((1000, rbgimg.height)) for x in xrange(cols): top.blit(bgimg, rbgimg) rbgimg = rbgimg.move([rbgimg.width, 0]) return top
def create_bottom(self): bgimg = media.load_image('tile_wall.png').convert() bgimg = pygame.transform.flip(bgimg, False, True) rbgimg = bgimg.get_rect() cols = int(1000 / rbgimg.width) top = Surface((1000, rbgimg.height)) for x in xrange(cols): top.blit(bgimg, rbgimg) rbgimg = rbgimg.move([rbgimg.width, 0]) return top
def add_border(self): """Draw a border around the thumbnail image Surface.""" new_surf = Surface((THUMB_SIZE + (BORDER_WIDTH * 2), THUMB_SIZE + (BORDER_WIDTH * 2))) new_surf.blit(self.image, (BORDER_WIDTH, BORDER_WIDTH)) border_rect = Rect(get_line_center(BORDER_WIDTH), get_line_center(BORDER_WIDTH), THUMB_SIZE + BORDER_WIDTH + 1, THUMB_SIZE + BORDER_WIDTH + 1) pygame.draw.rect(new_surf, THUMB_BORDER_COLOR, border_rect, BORDER_WIDTH) self.image = new_surf
def prepare_passage(text, width, size="normal", colour=(0,0,0)): sections = text.split("\n") paras = [prepare_paragraph(t,width,size=size,colour=colour) for t in sections] fullwidth = max(p.get_width() for p in paras) fullheight = sum(p.get_height() for p in paras) passage = Surface((fullwidth,fullheight),pygame.SRCALPHA) passage.fill((255,255,255,0)) y = 0 for p in paras: passage.blit(p,(0,y)) y += p.get_height() return passage
def padimage(self, image): """ Do a little processing of the input image to make it purdyer. Pad the image with transparent pixels so the edges get antialised when rotated and scaled. Looks real nice. """ new = Surface(image.get_rect().inflate(2, 2).size, pygame.SRCALPHA) color = image.get_at((0,0)) color[3] = 0 new.fill(color) new.blit(image, (1,1)) return new
def draw(self, pressed): from pygame.surface import Surface from pygame.draw import rect from pygame.display import flip self.surface.fill(self.surface_color) if pressed: self.current_position += pressed self.current_position %= self.number_buttons menu_surface = Surface((self.menu_width, self.menu_height)) menu_surface.fill(self.surface_color) rect(menu_surface, self.selection_color, self.info_list[self.current_position].point_rect) for i in range(self.number_buttons): menu_surface.blit(self.info_list[i].text_surface, self.info_list[i].text_rect) self.surface.blit(menu_surface, self.shift) flip()
def getEndGameSplash(winnerName=None, winnerColor=None): """If winningName and winnerColor are both None, display a tie game screen. """ screen = Display.get_surface() splashGroup = SpriteGroup() if winnerName != None and winnerColor != None: # Create winning bomberman image fatalityRect = Rect((0, 0, 500, 500)) fatalityRect.centerx = screen.get_rect().centerx fatalityRect.centery = screen.get_rect().centery fatalityAnimation = WorldlessWidget(Surface((500, 500)), fatalityRect) fatalImage = pygame.image.load("images/fatality.png").convert() fatalImage.set_colorkey(LAVENDER) bmanColor = Surface((fatalImage.get_width(), fatalImage.get_height())) bmanColor.fill(winnerColor) bmanColor.blit(fatalImage, bmanColor.get_rect()) winnerFrames = createFrames(bmanColor) fatalityAnimation.startAnimation(winnerFrames, 0, 12) splashGroup.add(fatalityAnimation) # Create text for winning player winnerText = TextBar(winnerName + " Wins!", (0, 0, 200, 50), 50) imgWidth = winnerText.image.get_width() winnerText.rect.left = (screen.get_size()[X] - imgWidth) / 2 splashGroup.add(winnerText) else: tieText = TextBar("TIE GAME!", (0, 20, 250, 50), 35) imgWidth = tieText.image.get_width() tieText.rect.left = (screen.get_size()[X] - imgWidth) / 2 splashGroup.add(tieText) escMessage = TextBar("Press Escape to exit.", (0, 60, 250, 50), 25) imgWidth = escMessage.image.get_width() escMessage.rect.left = (screen.get_size()[X] - imgWidth) / 2 splashGroup.add(escMessage) pressKeyText = TextBar( "Press a key or button when ready. Next round will start when everyone is ready.", (0, 90, 250, 50), 25 ) imgWidth = pressKeyText.image.get_width() pressKeyText.rect.left = (screen.get_size()[X] - imgWidth) / 2 splashGroup.add(pressKeyText) return splashGroup
def update(self, duration): """ reblit the entries on my rect """ if self.dirty == 0: return # make the transparent box size = self.rect.size img = Surface(size, SRCALPHA) transparency = 50 # 0 = transparent, 255 = opaque img.fill((0, 0, 0, transparency)) img = img.convert_alpha() # TODO: alpha or color key? # blit each entry for entry in self.entries: entry.update(duration) img.blit(entry.image, entry.rect) self.image = img
def on_board_built(self, ev): """ Build the board background. """ width, height = ev.width, ev.height board = ev.board # to obtain cells from coords win_height = self.window.get_height() bg = Surface((win_height, win_height)) bg = bg.convert() bg.fill(bg_color) for left in range(width): for top in range(height): cell = board.get_cell(left, top) bg.blit(cell.image, cell.rect) # blit the board bg onto the window's bg self.window_bg.blit(bg, (0, 0)) self._em.subscribe(BoardUpdatedEvent, self.on_board_update)
def add_underline(self): """Draws an underline on the text Surface, on top the text.""" # The underline will be drawn from the bottom of the text Surface # and will extend its entire horizontal length. text_width = self.rect.width text_height = self.rect.height start_point = (0, text_height - 4) end_point = (text_width, text_height - 4) # The underline is drawn onto a new Surface with the same dimensions # as the text Surface, but slightly taller to account for the # underline. The text is drawn on top. new_image = Surface((text_width, text_height + 4), pygame.SRCALPHA, 32) new_image = new_image.convert_alpha() draw.line(new_image, UNDERLINE_COLOUR, start_point, end_point, UNDERLINE_SIZE) new_image.blit(self.image, (0, 0)) self.image = new_image
def add_borders(self): """Draw an outer and inner border around the snapshot image.""" new_surf = Surface((PREVIEW_WIDTH + (BORDER_WIDTH * 4), PREVIEW_HEIGHT + (BORDER_WIDTH * 4))) new_surf.blit(self.image, (BORDER_WIDTH * 2, BORDER_WIDTH * 2)) inner_rect = Rect(BORDER_WIDTH + get_line_center(BORDER_WIDTH), BORDER_WIDTH + get_line_center(BORDER_WIDTH), PREVIEW_WIDTH + BORDER_WIDTH + 1, PREVIEW_HEIGHT + BORDER_WIDTH + 1) outer_rect = Rect(get_line_center(BORDER_WIDTH), get_line_center(BORDER_WIDTH), PREVIEW_WIDTH + (BORDER_WIDTH * 3) + 1, PREVIEW_HEIGHT + (BORDER_WIDTH * 3) + 1) pygame.draw.rect(new_surf, PREVIEW_INNER_BORDER_COLOR, inner_rect, BORDER_WIDTH) pygame.draw.rect(new_surf, PREVIEW_OUTER_BORDER_COLOR, outer_rect, BORDER_WIDTH) self.image = new_surf
def convert_to_colorkey_alpha(surf, colorkey=color.Color('magenta')): """Give the surface a colorkeyed background that will be transparent when drawing. Colorkey alpha, unlike per-pixel alpha, will allow the surface's transparent background to remain while using methods such as Surface.set_alpha(). Keyword arguments: surf The Surface to convert. colorkey The color value for the colorkey. The default is magenta or RGB(255, 0, 255). This should be set to a color that isn't present in the image, otherwise those areas with a matching colour will be drawn transparent as well. """ colorkeyed_surf = Surface(surf.get_size()) colorkeyed_surf.fill(colorkey) colorkeyed_surf.blit(surf, (0, 0)) colorkeyed_surf.set_colorkey(colorkey) colorkeyed_surf.convert() return colorkeyed_surf
class InfoWidget(pygame.sprite.Sprite): def __init__(self, bg, font): pygame.sprite.Sprite.__init__(self) self.title = '' self.data = '' self.bg = bg self.font = font self.image = Surface((200, 100)) def update(self): self.image.blit(self.bg, (0,0)) titleimg = self.font.render(self.title, True, (255,255,255)) dataimg = self.font.render(self.data, True, (255,255,255)) self.image.blit(titleimg, titleimg.get_rect().move(20, 20)) self.image.blit(dataimg, dataimg.get_rect().move(60, 60))
def render_text(font, text, text_color, outline_color=None, position=None): """Render a text Surface or Graphic, with an optional outline 1-pixel thick. Args: font: A PyGame Font object used for rendering the text. text: A String for the text that will be rendered. text_color: A tuple of integers which specify the RGB color of the text. outline_color: Optional. A tuple of integers which specify the RGB color of a 1-pixel thick outline. position: Optional. A tuple containing integer coordinates for the text's position relative to its parent Surface. The default value of None will cause this function to return a Surface, while passing a proper position tuple will cause it to return a Graphic. Returns: A Surface with the desired text, outlined if specified. Passing a position returns a Graphic instead. """ text_surf = font.render(text, True, text_color) if outline_color is not None: outline = font.render(text, True, outline_color) outlined_text_surf = Surface((text_surf.get_width() + 2, text_surf.get_height() + 2), SRCALPHA) outlined_text_surf.blit(outline, (0, 0)) outlined_text_surf.blit(outline, (0, 2)) outlined_text_surf.blit(outline, (2, 0)) outlined_text_surf.blit(outline, (2, 2)) outlined_text_surf.blit(text_surf, (1, 1)) text_surf = outlined_text_surf if position is None: return text_surf else: text_graphic = Graphic(outlined_text_surf, position) return text_graphic
class Animation: """Animation class""" colorkey = (0xff, 0xff, 0) def __init__(self, surface: Surface, rows, cols, frame_time=.1): self.surface = surface self.rows = rows self.cols = cols self.frame_width = surface.get_width() / rows self.frame_height = surface.get_height() / cols self.row = 0 self._col = 0 self.frame_time = frame_time self.time = 0 self.image = Surface((self.frame_width, self.frame_height)) self.image.set_colorkey(Animation.colorkey) self.valid = False def update_image(self): """Updates image""" area = Rect(self.row * self.frame_width, self._col * self.frame_height, 0, 0) area.x = self.row * self.frame_width area.y = self._col * self.frame_height area.width = area.x + self.frame_width area.height = area.y + self.frame_height self.image.fill(Animation.colorkey) self.image.blit(self.surface, (0, 0), area) self.valid = True def update(self, delta_time): """Updates""" self.time += delta_time old_row = self.row self.row = int(self.time / self.frame_time) % self.rows if old_row != self.row or not self.valid: self.update_image() def reset(self): """Resets""" self.row = 0 self._col = 0 self.time = 0 self.valid = False @property def col(self): """Returns col""" return self._col @col.setter def col(self, value): """Sets column""" self._col = value self.valid = False
class GameUI: def __init__(self, mainchar): self.bg = Surface((800, 600)) self.mainchar = mainchar self.layer = self.create_layer() self.top = self.create_top() self.bottom = self.create_bottom() self.scroll = 0 self.scroll_top = 0 def create_layer(self): bgimg = media.load_image('bg.png').convert() rbgimg = bgimg.get_rect() rows = int(600 / rbgimg.height) + 2 layer = Surface((rbgimg.width, 600)) for y in xrange(rows): layer.blit(bgimg, rbgimg) rbgimg = rbgimg.move([0, rbgimg.height]) return layer def create_top(self): bgimg = media.load_image('tile_wall.png').convert() rbgimg = bgimg.get_rect() self.top_size = rbgimg.width cols = int(1000 / rbgimg.width) top = Surface((1000, rbgimg.height)) for x in xrange(cols): top.blit(bgimg, rbgimg) rbgimg = rbgimg.move([rbgimg.width, 0]) return top def create_bottom(self): bgimg = media.load_image('tile_wall.png').convert() bgimg = pygame.transform.flip(bgimg, False, True) rbgimg = bgimg.get_rect() cols = int(1000 / rbgimg.width) top = Surface((1000, rbgimg.height)) for x in xrange(cols): top.blit(bgimg, rbgimg) rbgimg = rbgimg.move([rbgimg.width, 0]) return top def update(self, tick): self.scroll += tick / 6 self.scroll_top += tick / 6 rlayer = self.layer.get_rect() rlayer = rlayer.move((-self.scroll, -18)) columns = int(800 / rlayer.width) + 2 for x in xrange(columns): self.bg.blit(self.layer, rlayer) rlayer = rlayer.move((rlayer.width, 0)) if self.scroll > rlayer.width: self.scroll -= rlayer.width rtop = self.top.get_rect() rbottom = self.bottom.get_rect() rtop = rtop.move((-self.scroll_top, 6)) rbottom = rbottom.move((-self.scroll_top, self.bg.get_rect().height - rbottom.height - 6)) self.bg.blit(self.top, rtop) self.bg.blit(self.bottom, rbottom) if self.scroll_top > self.top_size: self.scroll_top -= self.top_size
class ButtonWidget(Widget): """ clickable widget with text in it """ def __init__( self, evManager, text, rect=None, onDownClickEvent=None, onUpClickEvent=None, onMouseMoveOutEvent=None ): Widget.__init__(self, evManager) # Widget init sets dirty to true, hence the actual text rendering # will be done in ButtonWidget.update(), called by the view renderer. self._em.reg_cb(DownClickEvent, self.on_downclick) self._em.reg_cb(UpClickEvent, self.on_upclick) self._em.reg_cb(MoveMouseEvent, self.on_mousemove) # the events to be triggered when the button is clicked or mouse moved self.onDownClickEvent = onDownClickEvent self.onUpClickEvent = onUpClickEvent self.onMouseMoveOutEvent = onMouseMoveOutEvent self.text = text self.font = Font(None, config_get_fontsize()) # default font, 40 pixels high if rect: self.rect = rect self.image = Surface(self.rect.size) # container size from specified rect # if txtimg does not fit in rect, it'll get cut (good thing) else: txtimg = self.font.render(self.text, True, (0, 0, 0)) self.rect = txtimg.get_rect() self.image = Surface(self.rect.size) # container size from rendered text # if txt changes, the size of the button will stay the same def update(self, duration): if self.dirty == 0: return if self.focused: color = config_get_focusedbtn_txtcolor() bgcolor = config_get_focusedbtn_bgcolor() else: color = config_get_unfocusedbtn_txtcolor() bgcolor = config_get_unfocusedbtn_bgcolor() # TODO: is bliting on existing faster than creating a new surface? self.image = Surface(self.rect.size) # rectangle container for the text self.image.fill(bgcolor) txtimg = self.font.render(self.text, True, color) txtimg = txtimg.convert() textpos = txtimg.get_rect(centerx=self.image.get_width() / 2, centery=self.image.get_height() / 2) self.image.blit(txtimg, textpos) # self.dirty is set to 0 by LayeredDirty.update def on_downclick(self, event): """ button down focuses and triggers eventual behavior """ if self.rect.collidepoint(event.pos): self.dirty = 1 self.set_focus(True) if self.onDownClickEvent: self._em.post(self.onDownClickEvent) def on_upclick(self, event): """ button up loses focus and triggers eventual behavior """ if self.rect.collidepoint(event.pos): if self.focused: self.dirty = 1 self.set_focus(False) if self.onUpClickEvent: self.log.debug("Clicked on button widget " + self.text) self._em.post(self.onUpClickEvent) def on_mousemove(self, event): """ if focused, lose focus when the mouse moves out """ if self.rect.collidepoint(event.pos): # mouse moved in pass else: # mouse moved out if self.focused: if not self.onMouseMoveOutEvent: # default behavior self.set_focus(False)
class BaseScreen(): """ Base Class Screen. Use to manage screen of games Use for exec main_loop, update screen. Enable to switch screen easier. Example : +------+ +------+ | Game | <----> | Menu | +------+ +------+ ^^ || vv +-------+ | Pause | +-------+ Raise a ChangeScreenException to change screen. """ def __init__(self, width, height, background=None): """ Init of baseScreen. Save the background : - BEFORE init_entities_before ( sprite ) - AFTER init_entities_after (Attach entities or text to background) so init_entities save elements with background init_entities """ self.surface = Surface((width, height)) if background is not None: self.surface.blit(background, background.get_rect()) self.init_entities_before(self.surface) self.background = self.surface.copy() self.init_entities_after(self.surface) def init_entities_after(self, surface): """ Create entities after saving background. Need to be redefined""" pass def init_entities_before(self, surface): """ Create entities before saving background. Need to be redefined""" pass def main_loop(self): """ Function to use in main loop. Return update list of coordinates to refresh. """ self.execute(self.surface) self.erase_all_map() return self.draw(self.surface) def execute(self, surface): """ Exec and Update entities of the screen. Need to be redefined. """ pass def erase_all_map(self): """ Erase all background Can redefine this function """ self.surface = self.background.copy() def draw(self, surface): """ Draw entities in the surface. Need to be redefined. """ pass
def render(self): """ generate an image suitable to represnt this monster. return Rect(pos[0] - radius, pos[1] - radius, radius * 2, radius * 2) the image will be used in battle screens """ d = self.mDNA.d color = (200,200,200) scratch = Surface((150, 150)) s = Surface((150,150)) s.lock() body_rect = body(s, d, (40,40)) #draw.rect(s, color, body_rect, 2) if d["limbNum"] > 0: # draw one limb to see how big it is limb_rect = limb(scratch, d, (0, 0)) t = d["limbLocation"] if t == 0: x, y = body_rect.bottomleft y -= body_rect.height / 4 else: x, y = body_rect.midleft dx = body_rect.width / d["limbNum"] for i in range(0, d["limbNum"]): limb_rect = limb(s, d, (x, y)) x += dx t = d["headLocation"] if t == 0: x, y = body_rect.midleft elif t == 1: x, y = body_rect.topleft y -= body_rect.height / 4 else: x, y = body_rect.topleft head_rect = head(s, d, (x, y)) x, y = head_rect.center y = y + head_rect.height / 6 mouth_rect = mouth(s, d, (x, y)) t = d["eyeLocation"] if t == 0: x, y = head_rect.center y -= head_rect.height / 4 else: x, y = head_rect.topleft for i in range(0, d["eyeNum"]): eye = MonsterEye(d) eye.rect.center = (x, y) eye.render() self.parts.append(eye) x += (d["eyeSkill"] + 1) * 5 s.unlock() # draw the parts onto the monster [ s.blit(part.image, part.rect) for part in self.parts ] self.image = s self.rect = s.get_rect()