import pygame import json class SpriteSheet: """ Imports a sprite sheet as separate pygame images given an image file and a json file. """ def __init__(self, sprite_sheet, texture_json): # Load in whole sprite sheet as one image. self.sprite_sheet = pygame.image.load(sprite_sheet).convert_alpha() self.images = [] # Get the sprite sheet json file. with open(texture_json, 'r') as json_file: self.img_attrib = json.load(json_file) json_file.close() # Count for how many images have been added in the image list image_count = 0 # Get the sprite size as a tuple sprite_size = self.img_attrib['width'], self.img_attrib['height'] # Iterate through every image location on the sprite sheet given the sprite size for i in range(self.sprite_sheet.get_size()[1] // sprite_size[1]): i *= sprite_size[1] for j in range(self.sprite_sheet.get_size()[0] // sprite_size[0]): j *= sprite_size[0] # Create a new transparent surface sprite = pygame.Surface(sprite_size, pygame.SRCALPHA) # Blit the sprite onto the image sprite.blit(self.sprite_sheet, (0, 0), (j, i, sprite_size[0], sprite_size[1])) # Add the image to the list of images self.images.append(sprite) image_count += 1 # Break the loop if the specified number of frames has been reached. if image_count >= self.img_attrib['frames']: break if image_count >= self.img_attrib['frames']: break class SelectionEgg(pygame.sprite.Sprite): """ Class for the eggs on the egg selection screen. """ def __init__(self, egg_color, resources_dir): pygame.sprite.Sprite.__init__(self) self.egg_color = egg_color # Loads the JSON file of the egg to read in data. with open(resources_dir + '/data/bloop_info/{0}.json'.format(egg_color), 'r') as save_file: json_file = json.load(save_file) save_file.close() # Gets the description off the egg from the JSON file. self.description = json_file.get('description') self.contentedness = json_file.get('contentedness') self.metabolism = json_file.get('metabolism') # Load the egg from the given color and get the bounding rectangle for the image. sprite_sheet = SpriteSheet(resources_dir + '/images/bloops/{0}/egg.png'.format(self.egg_color), resources_dir + '/images/bloops/{0}/egg.json'.format(self.egg_color)) self.images = sprite_sheet.images # Get the rectangle from the first image in the list self.rect = self.images[0].get_rect() self.index = 0 self.image = self.images[self.index] def update(self): """ Updates the sprite object. """ # Animate the sprite self.index = (self.index + 1) % len(self.images) self.image = self.images[self.index] class InfoText: """ Class for drawing large amounts of text on the screen at a time """ def __init__(self, resources_dir, game_res, text='Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' 'Nam commodo tempor aliquet. Suspendisse placerat accumsan' ' neque, nec volutpat nunc porta ut.'): self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10) self.text = [] # Text broken up into a list according to how it will fit on screen. self.max_lines = 6 # Max number of lines to be shown on screen at a time. self.offset = 0 self.game_res = game_res # Arrow icons to indicate scrolling self.up_arrow = pygame.image.load(resources_dir + '/images/gui/up_arrow.png').convert_alpha() self.down_arrow = pygame.image.load(resources_dir + '/images/gui/down_arrow.png').convert_alpha() raw_text = text # Copy the text to a different variable to be cut up. margins = 4.5 max_line_width = self.game_res - (margins * 2) # The maximum pixel width that drawn text can be. cut_chars = '.,! ' # Characters that will be considered "cuts" aka when a line break can occur. # Prevents freezing if the end of the string does not end in a cut character # Will fix eventually more elegantly if raw_text[-1:] not in cut_chars: raw_text += ' ' # Calculating line breaks. while len(raw_text) > 0: index = 0 test_text = '' # Chunk of text to pseudo-render and test the width of. # Loops until the testing text has reached the size limit. while True: # Break if the current index is larger than the remaining text. if index + 1 > len(raw_text): index -= 1 break # Add one character to the testing text from the raw text. test_text += raw_text[index] # Get the width of the pseudo-rendered text. text_width = self.font.size(test_text)[0] # Break if the text is larger than the defined max width. if text_width > max_line_width: break index += 1 pass # Gets the chunk of text to be added to the list. text_chunk = raw_text[0:index + 1] # Determines if the chunk of text has any break characters. has_breaks = any(cut_chars in text_chunk for cut_chars in cut_chars) # If the text has break characters, start with the last character and go backwards until # one has been found, decreasing the index each time. if has_breaks: while raw_text[index] not in cut_chars: index -= 1 text_chunk = raw_text[0:index + 1] # If there are no break characters in the chunk, simply decrease the index by one and insert # a dash at the end of the line to indicate the word continues. else: index -= 1 text_chunk = raw_text[0:index + 1] text_chunk += '-' # Append the text chunk to the list of text to draw. self.text.append(text_chunk) # Cut the text to repeat the process with the new cut string. raw_text = raw_text[index + 1:] def draw(self, surface): """ Draws the text on a given surface. :param surface: The surface for the text to be drawn on. """ # Constants to help draw the text line_separation = 7 left_margin = 3 top_margin = 25 bottom_margin = 10 # Draw the lines on the screen for i in range(min(len(self.text), self.max_lines)): text = self.font.render(self.text[i + self.offset], False, (64, 64, 64)) surface.blit(text, (left_margin, top_margin + (i * line_separation))) # Draw the arrows if there is more text than is on screen. if self.offset != 0: surface.blit(self.up_arrow, ((self.game_res / 2) - (self.up_arrow.get_rect().width / 2), top_margin - 3)) if len(self.text) - (self.offset + 1) >= self.max_lines: surface.blit(self.down_arrow, ((self.game_res / 2) - (self.down_arrow.get_rect().width / 2), self.game_res - bottom_margin)) def scroll_down(self): """ Scrolls the text on the screen down. """ # Ensures that the offset cannot be too big as to try to render non-existent lines. if len(self.text) - (self.offset + 1) >= self.max_lines: self.offset += 1 def scroll_up(self): """ Scrolls the text on the screen up. """ if self.offset > 0: # Ensures a non-zero offset is not possible. self.offset -= 1 class EggInfo: """ Class to draw the contentedness and metabolism value off the egg on the info screen. """ def __init__(self, resources_dir, contentedness, metabolism, location): self.contentedness = contentedness self.metabolism = metabolism self.x = location[0] self.y = location[1] # Create a new surface to blit onto the other surface self.surface = pygame.Surface((44, 15), pygame.SRCALPHA) # Blit the two indicator icons on screen smiley = pygame.image.load(resources_dir + '/images/gui/smiley.png').convert_alpha() self.surface.blit(smiley, (0, 0)) apple = pygame.image.load(resources_dir + '/images/gui/apple.png').convert_alpha() self.surface.blit(apple, (1, 9)) # Draw 5 stars. If the value of the contentedness is less than the current star, make it a blank star. for i in range(5): if i < self.contentedness: star = pygame.image.load(resources_dir + '/images/gui/star.png').convert_alpha() else: star = pygame.image.load(resources_dir + '/images/gui/blank_star.png').convert_alpha() self.surface.blit(star, (11 + (i * 6), 1)) # Draw 5 stars. If the value of the metabolism is less than the current star, make it a blank star. for i in range(5): if i < self.metabolism: star = pygame.image.load(resources_dir + '/images/gui/star.png').convert_alpha() else: star = pygame.image.load(resources_dir + '/images/gui/blank_star.png').convert_alpha() self.surface.blit(star, (11 + (i * 6), 10)) def draw(self, surface): """ Draw the info icons on a given surface. :param surface: the surface to draw the icons on. """ # Blit the info onto the given surface. surface.blit(self.surface, (self.x, self.y))