def __init__(self, definition_path, map_path, globals=Globals, in_game=False): self.globals = globals self.actions = list() self.browser = None self.message_time = 0 self.message_surf = None self.message_rect = None self.key_code = None self.mouse_down = False self.info_mode = False self.delete_mode = False self.in_game = in_game loader = AssetLoader(join("images", "tiles")) TileType.create_empty(loader) self.base_image = loader.load_image("transparent.png") self.base_rect = self.base_image.get_rect() self.definition_path = definition_path self.map_path = map_path self.tile_engine = TileEngine(self.definition_path, self.map_path) self.combo_tile_manager = TileManager(LevelEditor.COMBO_DEF_PATH, None) self.tile_rect = self.tile_engine.get_tile_rect() self.right_padding = self.tile_rect.width * \ LevelEditor.RIGHT_PADDING_FACTOR self.shift_factor = self.tile_rect.width self.init_camera() self.init_highlight() self.init_title() self.init_browser() self.init_second_title() self.init_combo_browser() self.in_combo = False
class SetJoystickKeyState(GameState): ALLOWED_TYPES = set( [pygame.JOYBUTTONDOWN, pygame.JOYAXISMOTION, pygame.JOYHATMOTION]) TITLE_IMAGE_PATH = 'set_key.png' TITLE_MARGIN_TOP = 60 def __init__(self, image_surf, list_index, return_state): self.list_index = list_index self.return_state = return_state self.image_surf = image_surf self.loader = AssetLoader('images') self.image_rect = self.image_surf.get_rect() self.image_rect.center = Globals.SCREEN.get_rect().center self.init_images() def init_images(self): self.background_img = self.loader.load_image('background.png') self.title_surf = self.loader.load_image_alpha( SetJoystickKeyState.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.centerx = Globals.WIDTH / 2 self.title_rect.top = SetJoystickKeyState.TITLE_MARGIN_TOP def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.image_surf, self.image_rect) def handle_escape(self): Globals.STATE = self.return_state def set_event(self, event): pair = self.convert_event(event) SettingsManager.EVENTS_UP = [ a for a in SettingsManager.EVENTS_UP if a != event] SettingsManager.EVENTS_DOWN = [ a for a in SettingsManager.EVENTS_DOWN if a != event] SettingsManager.EVENTS_LEFT = [ a for a in SettingsManager.EVENTS_LEFT if a != event] SettingsManager.EVENTS_RIGHT = [ a for a in SettingsManager.EVENTS_RIGHT if a != event] SettingsManager.EVENTS_ATTACK = [ a for a in SettingsManager.EVENTS_ATTACK if a != event] SettingsManager.EVENTS_ACTION = [ a for a in SettingsManager.EVENTS_ACTION if a != event] SettingsManager.EVENTS_ESCAPE = [ a for a in SettingsManager.EVENTS_ESCAPE if a != event] SettingsManager.EVENTS_RETURN = [ a for a in SettingsManager.EVENTS_RETURN if a != event] SettingsManager.EVENTS_BACKSPACE = [ a for a in SettingsManager.EVENTS_BACKSPACE if a != event] self.get_event_list().append(pair) SettingsManager.save() self.handle_escape() def get_event_list(self): from ControlSettings import ControlSettings if self.list_index == ControlSettings.INDEX_ESCAPE: return SettingsManager.EVENTS_ESCAPE elif self.list_index == ControlSettings.INDEX_ATTACK: return SettingsManager.EVENTS_ATTACK elif self.list_index == ControlSettings.INDEX_ACTION: return SettingsManager.EVENTS_ACTION elif self.list_index == ControlSettings.INDEX_RETURN: return SettingsManager.EVENTS_RETURN elif self.list_index == ControlSettings.INDEX_UP: return SettingsManager.EVENTS_UP elif self.list_index == ControlSettings.INDEX_DOWN: return SettingsManager.EVENTS_DOWN elif self.list_index == ControlSettings.INDEX_LEFT: return SettingsManager.EVENTS_LEFT elif self.list_index == ControlSettings.INDEX_RIGHT: return SettingsManager.EVENTS_RIGHT else: return list() def convert_event(self, event): pair = EventPair(type=event.type) if event.type == pygame.JOYBUTTONDOWN: pair.value = event.button elif event.type == pygame.JOYAXISMOTION: if event.value < 0: pair.value = -1 elif event.value > 0: pair.value = 1 else: pair.value = 0 pair.axis = event.axis elif event.type == pygame.JOYHATMOTION: pair.hat = event.hat pair.value = event.value return pair def handle_raw_event(self, event): if event.type in SetJoystickKeyState.ALLOWED_TYPES and \ EventManager.is_keydown(event): self.set_event(event)
class CustomLevelPicker(GameState): MAP_FILE_EXT = 'txt' CUSTOM_MAP_PATH = join('maps', 'custom') PLAY_PATH = 'custom' SELECTION_FONT = pygame.font.Font(None, 70) SELECTION_COLOR = pygame.color.Color('white') CREATE_NEW_TEXT = 'Create New Level' SELECTION_TOP_MARGIN = 30 SELECTION_PADDING = 20 HIGHLIGHT_PADDING_HEIGHT = 30 HIGHLIGHT_PADDING_WIDTH = 70 HIGHLIGHT_COLOR = pygame.color.Color("black") HIGHLIGHT_ALPHA = 150 ARROW_MARGIN = 20 SUBTITLE_BACKGROUND = pygame.color.Color("black") SUBTITLE_PADDING = 10 CENTER_SUBTITLE_TEXT = "Press enter to play" LEFT_SUBTITLE_TEXT = "Press 'd' to delete" RIGHT_SUBTITLE_TEXT = "Press 'e' to edit" SUBTITLE_OFFSET = 40 NEW_SUBTITLE_TEXT = "Press enter" SUBTITLE_COLOR = pygame.color.Color("white") SUBTITLE_FONT = pygame.font.Font(None, 32) SUBTITLE_MARGIN_BOTTOM = 50 TITLE_IMAGE_PATH = 'customlevel.png' TITLE_MARGIN_TOP = 70 def __init__(self): self.init_images() self.file_manager = FileManager( path=CustomLevelPicker.CUSTOM_MAP_PATH, file_ext=CustomLevelPicker.MAP_FILE_EXT) self.file_names = self.file_manager.get_files(strip_ext=True) self.current_selection = 0 self.text_surf = None self.text_rect = None self.highlight_surf = None self.highlight_rect = None self.build_text() self.build_subtitles() Globals.play_menu_sound() def init_images(self): self.loader = AssetLoader('images') self.background_img = self.loader.load_image('background.png') self.title_surf = self.loader.load_image_alpha( CustomLevelPicker.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.center = Globals.SCREEN.get_rect().center self.title_rect.top = CustomLevelPicker.TITLE_MARGIN_TOP self.arrow_down_surf = self.loader.load_image_alpha('arrow_down.png') self.arrow_down_rect = self.arrow_down_surf.get_rect() self.arrow_up_surf = self.loader.load_image_alpha('arrow_up.png') self.arrow_up_rect = self.arrow_up_surf.get_rect() self.arrow_up_rect.centerx = Globals.WIDTH / 2 self.arrow_down_rect.centerx = Globals.WIDTH / 2 def build_subtitles(self): self.left_subtitle_surf, self.left_subtitle_rect = self.init_subtitle( CustomLevelPicker.LEFT_SUBTITLE_TEXT, Globals.WIDTH / 4 - CustomLevelPicker.SUBTITLE_OFFSET) self.center_subtitle_surf, self.center_subtitle_rect = \ self.init_subtitle(CustomLevelPicker.CENTER_SUBTITLE_TEXT, Globals.WIDTH / 2) self.right_subtitle_surf, self.right_subtitle_rect = \ self.init_subtitle( CustomLevelPicker.RIGHT_SUBTITLE_TEXT, (3 * Globals.WIDTH) / 4 + CustomLevelPicker.SUBTITLE_OFFSET) self.new_subtitle_surf, self.new_subtitle_rect = \ self.init_subtitle(CustomLevelPicker.NEW_SUBTITLE_TEXT, Globals.WIDTH / 2) def init_subtitle(self, text, centerx): text_surf = CustomLevelPicker.SUBTITLE_FONT.render( text, True, CustomLevelPicker.SUBTITLE_COLOR) subtitle_rect = text_surf.get_rect() subtitle_rect.bottom = \ Globals.HEIGHT - CustomLevelPicker.SUBTITLE_MARGIN_BOTTOM subtitle_rect.centerx = centerx subtitle_rect.inflate_ip(CustomLevelPicker.SUBTITLE_PADDING * 2, CustomLevelPicker.SUBTITLE_PADDING * 2) subtitle_surf = pygame.Surface(subtitle_rect.size).convert() subtitle_surf.fill(CustomLevelPicker.SUBTITLE_BACKGROUND) subtitle_surf.blit(text_surf, (CustomLevelPicker.SUBTITLE_PADDING, CustomLevelPicker.SUBTITLE_PADDING)) return subtitle_surf, subtitle_rect def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.highlight_surf, self.highlight_rect) Globals.SCREEN.blit(self.text_surf, self.text_rect) if self.current_selection == 0: Globals.SCREEN.blit(self.new_subtitle_surf, self.new_subtitle_rect) else: Globals.SCREEN.blit(self.left_subtitle_surf, self.left_subtitle_rect) Globals.SCREEN.blit(self.center_subtitle_surf, self.center_subtitle_rect) Globals.SCREEN.blit(self.right_subtitle_surf, self.right_subtitle_rect) if len(self.file_names) > 0: Globals.SCREEN.blit(self.arrow_down_surf, self.arrow_down_rect) Globals.SCREEN.blit(self.arrow_up_surf, self.arrow_up_rect) def build_text(self): self.text_surf = CustomLevelPicker.SELECTION_FONT.render( self.get_selection_name(), True, CustomLevelPicker.SELECTION_COLOR) self.text_rect = self.text_surf.get_rect() self.text_rect.center = Globals.SCREEN.get_rect().center self.text_rect.top += CustomLevelPicker.SELECTION_TOP_MARGIN self.highlight_rect = self.text_rect.inflate( CustomLevelPicker.HIGHLIGHT_PADDING_WIDTH, CustomLevelPicker.HIGHLIGHT_PADDING_HEIGHT) self.highlight_surf = pygame.Surface(self.highlight_rect.size) self.highlight_surf.fill(CustomLevelPicker.HIGHLIGHT_COLOR) self.highlight_surf.set_alpha(CustomLevelPicker.HIGHLIGHT_ALPHA) self.arrow_up_rect.bottom = self.highlight_rect.top - \ CustomLevelPicker.ARROW_MARGIN self.arrow_down_rect.top = self.highlight_rect.bottom + \ CustomLevelPicker.ARROW_MARGIN def get_selection_name(self): if self.current_selection == 0: return CustomLevelPicker.CREATE_NEW_TEXT else: return self.file_names[self.current_selection - 1] def handle_change(self, delta): self.current_selection = (self.current_selection + delta) % \ (len(self.file_names) + 1) self.build_text() def handle_selection(self): if self.current_selection != 0: file_path = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) level = CustomLevel(join(CustomLevelPicker.PLAY_PATH, file_path)) level.got_current_state() Globals.STATE = level else: Globals.STATE = CustomLevelNameInput() def handle_edit_selection(self): if self.current_selection != 0: file_path = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) Globals.STATE = LevelEditor(join('maps', 'map_def.txt'), join(CustomLevelPicker.CUSTOM_MAP_PATH, file_path), globals=Globals, in_game=True) else: Globals.STATE = CustomLevelNameInput() def handle_delete(self): if self.current_selection != 0: full_name = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) full_path = join(CustomLevelPicker.CUSTOM_MAP_PATH, full_name) try: os.remove(full_path) self.file_names = self.file_manager.get_files(strip_ext=True) self.handle_change(-1) except Exception as e: print 'An error occured while deleting "' + full_path + '"' print e def handle_escape(self): Globals.STATE = Menu.Menu() def handle_return(self): self.handle_selection() def handle_raw_event(self, event): if event.type == pygame.KEYDOWN: if event.key == pygame.K_e: self.handle_edit_selection() elif event.key == pygame.K_d: self.handle_delete() def handle_key_up(self, keydown): if keydown: self.handle_change(-1) def handle_key_down(self, keydown): if keydown: self.handle_change(1)
class PauseScreen(GameState): UNPAUSE_KEYS = [pygame.K_p, pygame.K_RETURN] TITLE_FONT = pygame.font.Font(None, 100) TITLE_TEXT = 'Game Paused' TITLE_COLOR = pygame.color.Color('white') ALPHA_FACTOR = 550 MIN_ALPHA = 0 MAX_ALPHA = 255 def __init__(self, return_state, escape_state=None): self.return_state = return_state self.escape_state = escape_state if escape_state is not None else \ Menu.Menu() self.loader = AssetLoader('images') self.background_img = self.loader.load_image('background.png') self.pause_image = self.loader.load_image_alpha('game-paused.png') Globals.play_menu_sound() # self.title_surf = PauseScreen.TITLE_FONT.render( # PauseScreen.TITLE_TEXT, True, PauseScreen.TITLE_COLOR) # self.title_rect = self.title_surf.get_rect() # self.title_rect.center = Globals.SCREEN.get_rect().center self.black_surf = pygame.Surface( (Globals.WIDTH, Globals.HEIGHT)).convert() self.black_surf.fill((0, 0, 0)) self.fade_in = False self.fade_out = False self.alpha_factor = 300 self.start_fade_in() def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) # Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.pause_image, [175, Globals.HEIGHT / 3]) if self.fade_out or self.fade_in: Globals.SCREEN.blit(self.black_surf, (0, 0)) def update(self, time): if self.fade_out: old_alpha = self.black_surf.get_alpha() new_alpha = int(old_alpha + time * PauseScreen.ALPHA_FACTOR) if new_alpha >= PauseScreen.MAX_ALPHA: self.handle_finish_fade_out() self.fade_out = False self.black_surf.set_alpha(new_alpha) elif self.fade_in: old_alpha = self.black_surf.get_alpha() new_alpha = int(old_alpha - time * PauseScreen.ALPHA_FACTOR) if new_alpha <= PauseScreen.MIN_ALPHA: self.fade_in = False self.black_surf.set_alpha(new_alpha) def start_fade_out(self): if self.fade_out: return self.black_surf.set_alpha(PauseScreen.MIN_ALPHA) self.fade_out = True def start_fade_in(self): self.black_surf.set_alpha(PauseScreen.MAX_ALPHA) self.fade_in = True def handle_finish_fade_out(self): fn = getattr(self.return_state, "handle_unpause", None) if callable(fn): fn() Globals.STATE = self.return_state def handle_escape(self): Globals.STATE = self.escape_state def handle_return(self): Globals.stop_menu_sound() self.start_fade_out() def handle_action_key(self): Globals.stop_menu_sound() self.start_fade_out() def handle_raw_event(self, event): if EventManager.is_keyboard_event(event.type) and \ event not in SettingsManager.EVENTS_ESCAPE and \ event not in SettingsManager.EVENTS_RETURN and \ event not in SettingsManager.EVENTS_ACTION: self.handle_return()
class ControlSettings(GameState): TITLE_IMAGE_PATH = 'control_settings.png' TITLE_MARGIN_TOP = 60 TITLE_TEXT_MARGIN = 40 TITLE_ARROW_MARGIN = 100 SURF_INDEX_NORMAL = 0 SURF_INDEX_HIT = 1 SURF_INDEX_SELECTED = 2 ARROW_PADDING = 10 KEY_PADDING = 30 RESET_MARGIN_BOTTOM = 20 INDEX_UP = 0 INDEX_DOWN = 2 INDEX_LEFT = 1 INDEX_RIGHT = 3 INDEX_ATTACK = 4 INDEX_ACTION = 5 INDEX_ESCAPE = 6 INDEX_RETURN = 7 INDEX_RESET = 8 NUM_OPTIONS = 9 def __init__(self): self.loader = AssetLoader('images') self.control_loader = AssetLoader(join('images', 'controls')) self.background_img = self.loader.load_image('background.png') self.title_surf = self.loader.load_image_alpha( ControlSettings.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.centerx = Globals.WIDTH / 2 self.title_rect.top = ControlSettings.TITLE_MARGIN_TOP self.arrows_top = self.title_rect.bottom + \ ControlSettings.TITLE_ARROW_MARGIN self.arrows_x_center = int(Globals.WIDTH / 4) self.text_top = self.title_rect.bottom + \ ControlSettings.TITLE_TEXT_MARGIN self.surf_rect_pairs = [ SurfRectPair() for i in range(0, ControlSettings.NUM_OPTIONS) ] self.surf_index = [ ControlSettings.SURF_INDEX_NORMAL for i in range(0, ControlSettings.NUM_OPTIONS) ] self.last_surf_index = [ ControlSettings.SURF_INDEX_NORMAL for i in range(0, ControlSettings.NUM_OPTIONS) ] self.ignore_index = [0 for i in range(0, ControlSettings.NUM_OPTIONS)] self.load_control_images() self.selection = 0 self.set_selection(0) def set_selection(self, index): if self.selection != -1: if self.surf_index[self.selection] == \ ControlSettings.SURF_INDEX_HIT: self.last_surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL else: self.last_surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL self.surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL self.selection = index if self.surf_index[index] == ControlSettings.SURF_INDEX_HIT: self.last_surf_index[index] = ControlSettings.SURF_INDEX_SELECTED else: self.last_surf_index[index] = self.surf_index[index] self.surf_index[index] = ControlSettings.SURF_INDEX_SELECTED def change_selection(self, delta): index = self.selection + delta if index < 0 or index >= ControlSettings.NUM_OPTIONS: return self.set_selection(index) def select(self): if self.selection == -1: return if self.selection == ControlSettings.INDEX_RESET: SettingsManager.reset_controls() self.set_selection(0) return Globals.STATE = SetJoystickKeyState( self.surf_rect_pairs[self.selection].surf_arr[0], list_index=self.selection, return_state=self) def load_image_group(self, file_path): return self.control_loader.load_spritesheet_alpha(file_path, num_rows=3, num_cols=1) def set_surf_arr(self, index, file_path): self.surf_rect_pairs[index].surf_arr = self.load_image_group(file_path) self.surf_rect_pairs[index].rect = self.surf_rect_pairs[ index].surf_arr[0].get_rect() def get_surf(self, index): return self.surf_rect_pairs[index].surf_arr[self.surf_index[index]] def get_rect(self, index): return self.surf_rect_pairs[index].rect def load_control_images(self): self.load_arrows() self.set_surf_arr(ControlSettings.INDEX_ATTACK, 'attack_key.png') self.set_surf_arr(ControlSettings.INDEX_ACTION, 'action_key.png') self.set_surf_arr(ControlSettings.INDEX_ESCAPE, 'escape_key.png') self.set_surf_arr(ControlSettings.INDEX_RETURN, 'return_key.png') self.set_surf_arr(ControlSettings.INDEX_RESET, 'reset_controls.png') centerx = int((3 * Globals.WIDTH) / 4) attack_key_rect = self.get_rect(ControlSettings.INDEX_ATTACK) attack_key_rect.centerx = centerx attack_key_rect.top = self.text_top action_key_rect = self.get_rect(ControlSettings.INDEX_ACTION) action_key_rect.centerx = centerx action_key_rect.top = attack_key_rect.bottom + \ ControlSettings.KEY_PADDING escape_key_rect = self.get_rect(ControlSettings.INDEX_ESCAPE) escape_key_rect.centerx = centerx escape_key_rect.top = action_key_rect.bottom + \ ControlSettings.KEY_PADDING return_key_rect = self.get_rect(ControlSettings.INDEX_RETURN) return_key_rect.centerx = centerx return_key_rect.top = escape_key_rect.bottom + \ ControlSettings.KEY_PADDING reset_rect = self.get_rect(ControlSettings.INDEX_RESET) reset_rect.centerx = int(Globals.WIDTH / 2) reset_rect.bottom = Globals.HEIGHT - \ ControlSettings.RESET_MARGIN_BOTTOM def load_arrows(self): self.set_surf_arr(ControlSettings.INDEX_UP, 'arrow_up.png') self.set_surf_arr(ControlSettings.INDEX_DOWN, 'arrow_down.png') self.set_surf_arr(ControlSettings.INDEX_LEFT, 'arrow_left.png') self.set_surf_arr(ControlSettings.INDEX_RIGHT, 'arrow_right.png') arrow_up_rect = self.get_rect(ControlSettings.INDEX_UP) arrow_up_rect.centerx = self.arrows_x_center arrow_up_rect.top = self.arrows_top arrow_down_rect = self.get_rect(ControlSettings.INDEX_DOWN) arrow_down_rect.centerx = arrow_up_rect.centerx arrow_down_rect.top = arrow_up_rect.bottom + \ ControlSettings.ARROW_PADDING arrow_left_rect = self.get_rect(ControlSettings.INDEX_LEFT) arrow_left_rect.top = arrow_down_rect.top arrow_left_rect.right = arrow_down_rect.left - \ ControlSettings.ARROW_PADDING arrow_right_rect = self.get_rect(ControlSettings.INDEX_RIGHT) arrow_right_rect.top = arrow_down_rect.top arrow_right_rect.left = arrow_down_rect.right + \ ControlSettings.ARROW_PADDING def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) for i, pair in enumerate(self.surf_rect_pairs): Globals.SCREEN.blit(pair.surf_arr[self.surf_index[i]], pair.rect) def handle_raw_event(self, event): if event.type == pygame.KEYDOWN: index = -1 if event in SettingsManager.EVENTS_UP: index = ControlSettings.INDEX_UP elif event in SettingsManager.EVENTS_DOWN: index = ControlSettings.INDEX_DOWN elif event in SettingsManager.EVENTS_LEFT: index = ControlSettings.INDEX_LEFT elif event in SettingsManager.EVENTS_RIGHT: index = ControlSettings.INDEX_RIGHT elif event in SettingsManager.EVENTS_ESCAPE: index = ControlSettings.INDEX_ESCAPE elif event in SettingsManager.EVENTS_ACTION: index = ControlSettings.INDEX_ACTION elif event in SettingsManager.EVENTS_ATTACK: index = ControlSettings.INDEX_ATTACK elif event in SettingsManager.EVENTS_RETURN: index = ControlSettings.INDEX_RETURN if index != -1: self.ignore_index[index] = 2 def quit(self): import SettingsState Globals.STATE = SettingsState.SettingsState() def check_hit(self, index, keydown=True): if not keydown: self.ignore_index[index] = 0 if self.surf_index[index] != ControlSettings.SURF_INDEX_SELECTED: self.set_last_state(index) return False if self.ignore_index[index] > 0: self.ignore_index[index] -= 1 if self.surf_index[index] != ControlSettings.SURF_INDEX_SELECTED: self.set_last_state(index) return False self.last_surf_index[index] = self.surf_index[index] self.surf_index[index] = ControlSettings.SURF_INDEX_HIT return True def set_last_state(self, index): if self.last_surf_index[index] == ControlSettings.SURF_INDEX_HIT: self.last_surf_index[index] = ControlSettings.SURF_INDEX_NORMAL self.surf_index[index] = self.last_surf_index[index] def handle_action_key(self, keydown=True): self.check_hit(ControlSettings.INDEX_ACTION, keydown) def handle_action_keyup(self): self.handle_action_key(False) def handle_attack(self, keydown=True): self.check_hit(ControlSettings.INDEX_ATTACK, keydown) def handle_attack_keyup(self): self.handle_attack(False) def handle_key_down(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_DOWN] > 0: self.change_selection(1) self.check_hit(ControlSettings.INDEX_DOWN, keydown) def handle_key_up(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_UP] > 0: self.change_selection(-1) self.check_hit(ControlSettings.INDEX_UP, keydown) def handle_key_left(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_LEFT] > 0: self.change_selection(-1) self.check_hit(ControlSettings.INDEX_LEFT, keydown) def handle_key_right(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_RIGHT] > 0: self.change_selection(1) self.check_hit(ControlSettings.INDEX_RIGHT, keydown) def handle_backspace(self): pass def handle_return(self, keydown=True): if keydown and self.ignore_index[ControlSettings.INDEX_RETURN] > 0: self.select() self.ignore_index[ControlSettings.INDEX_RETURN] = 0 else: self.check_hit(ControlSettings.INDEX_RETURN, keydown) def handle_return_keyup(self): self.handle_return(False) def handle_escape(self, keydown=True): if self.ignore_index[ControlSettings.INDEX_ESCAPE] > 0: self.quit() self.check_hit(ControlSettings.INDEX_ESCAPE, keydown) def handle_escape_keyup(self): self.handle_escape(False)
class CustomLevelNameInput(GameState): ARROW_KEYS = [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT] MIN_LENGTH = 3 MAX_LENGTH = 25 PROMPT_FONT = None PROMPT_COLOR = (240, 250, 190) PROMPT_PADDING = 70 PROMPT_SIZE = 100 PROMPT = "Please type the level name" INPUT_FONT = None INPUT_SIZE = 70 HIGHLIGHT_PADDING_HEIGHT = 10 HIGHLIGHT_PADDING_WIDTH = 20 HIGHLIGHT_COLOR = pygame.color.Color("black") HIGHLIGHT_ALPHA = 150 INPUT_COLOR = pygame.color.Color("white") HINT = "Press Enter to continue" HINT_FONT = None HINT_SIZE = 30 HINT_PADDING = 400 HINT_COLOR = pygame.color.Color("white") ERROR_FONT = None ERROR_SIZE = 40 ERROR_PADDING = 110 # ERROR_COLOR = pygame.color.Color("red") ERROR_COLOR = (255, 71, 71) ERROR_BACKSPACE = "You can't delete nothing!" ERROR_TOO_LONG = "Name is too long!" ERROR_TOO_SHORT = "Name is too short!" ERROR_EXISTS = "A map with that name exists!" ERROR_ARROW_KEY = "The arrow keys are disabled!" EXTRA_BLINK_TIME = .75 EXTRA_POSTTEXT = '|' EXTRA_COLOR = pygame.color.Color("white") MAP_FILE_EXT = 'txt' CUSTOM_MAP_PATH = join('maps', 'custom') PLAY_PATH = 'custom' BASE_MAP_PATH = join('maps', 'base_custom.txt') def __init__(self): Globals.INTRO_SOUND_PLAYED = False self.file_name = "" self.error_message = None self.loader = AssetLoader('images') self.setup_text() self.show_extra = False self.extra_time = 0 Globals.play_menu_sound() self.background_img = self.loader.load_image('background.png') self.file_manager = FileManager( path=CustomLevelNameInput.CUSTOM_MAP_PATH, file_ext=CustomLevelNameInput.MAP_FILE_EXT) def setup_text(self): self.input_font = pygame.font.Font(CustomLevelNameInput.INPUT_FONT, CustomLevelNameInput.INPUT_SIZE) self.hint_font = pygame.font.Font(CustomLevelNameInput.HINT_FONT, CustomLevelNameInput.HINT_SIZE) self.error_font = pygame.font.Font(CustomLevelNameInput.ERROR_FONT, CustomLevelNameInput.ERROR_SIZE) self.prompt_font = pygame.font.Font(CustomLevelNameInput.PROMPT_FONT, CustomLevelNameInput.PROMPT_SIZE) self.prompt_surf = self.prompt_font.render( CustomLevelNameInput.PROMPT, True, CustomLevelNameInput.PROMPT_COLOR) self.prompt_rect = self.prompt_surf.get_rect() self.prompt_rect.centerx = Globals.WIDTH / 2 self.prompt_rect.top = CustomLevelNameInput.PROMPT_PADDING self.hint_surf = self.hint_font.render(CustomLevelNameInput.HINT, True, CustomLevelNameInput.HINT_COLOR) self.hint_rect = self.hint_surf.get_rect() self.hint_rect.centerx = Globals.WIDTH / 2 self.hint_rect.top = CustomLevelNameInput.HINT_PADDING def update(self, time): self.extra_time += time if self.extra_time >= CustomLevelNameInput.EXTRA_BLINK_TIME: self.extra_time = 0 self.show_extra = not self.show_extra def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.prompt_surf, self.prompt_rect) Globals.SCREEN.blit(self.hint_surf, self.hint_rect) if self.error_message is not None: error_surf = self.error_font.render( self.error_message, True, CustomLevelNameInput.ERROR_COLOR) error_rect = error_surf.get_rect() error_rect.centerx = Globals.WIDTH / 2 error_rect.bottom = Globals.HEIGHT - \ CustomLevelNameInput.ERROR_PADDING Globals.SCREEN.blit(error_surf, error_rect) input_rect = None if len(self.file_name) > 0: input_surf = self.input_font.render( self.file_name, True, CustomLevelNameInput.INPUT_COLOR) input_rect = input_surf.get_rect() input_rect.centerx = Globals.WIDTH / 2 input_rect.centery = Globals.HEIGHT / 2 highlight_rect = input_rect.inflate( CustomLevelNameInput.HIGHLIGHT_PADDING_WIDTH * 2, CustomLevelNameInput.HIGHLIGHT_PADDING_HEIGHT * 2) highlight_surf = pygame.Surface(highlight_rect.size).convert() highlight_surf.fill(CustomLevelNameInput.HIGHLIGHT_COLOR) highlight_surf.set_alpha(CustomLevelNameInput.HIGHLIGHT_ALPHA) Globals.SCREEN.blit(highlight_surf, highlight_rect) Globals.SCREEN.blit(input_surf, input_rect) if self.show_extra: extra_surf = self.input_font.render( CustomLevelNameInput.EXTRA_POSTTEXT, True, CustomLevelNameInput.EXTRA_COLOR) extra_rect = extra_surf.get_rect() extra_rect.centery = Globals.HEIGHT / 2 if input_rect is not None: extra_rect.left = input_rect.right else: extra_rect.centerx = Globals.WIDTH / 2 highlight_rect = extra_rect.inflate( CustomLevelNameInput.HIGHLIGHT_PADDING_WIDTH * 2, CustomLevelNameInput.HIGHLIGHT_PADDING_HEIGHT * 2) highlight_surf = pygame.Surface(highlight_rect.size).convert() highlight_surf.fill(CustomLevelNameInput.HIGHLIGHT_COLOR) highlight_surf.set_alpha(CustomLevelNameInput.HIGHLIGHT_ALPHA) Globals.SCREEN.blit(highlight_surf, highlight_rect) Globals.SCREEN.blit(extra_surf, extra_rect) def handle_entry(self, typed_char): if len(self.file_name) == CustomLevelNameInput.MAX_LENGTH: self.error_message = CustomLevelNameInput.ERROR_TOO_LONG else: self.file_name += typed_char def handle_backspace(self): if len(self.file_name) > 0: self.file_name = \ self.file_name[0:len(self.file_name) - 1] else: self.error_message = CustomLevelNameInput.ERROR_BACKSPACE def handle_return(self): if len(self.file_name) < CustomLevelNameInput.MIN_LENGTH: self.error_message = CustomLevelNameInput.ERROR_TOO_SHORT else: if self.file_name in self.file_manager.get_files(strip_ext=True): self.error_message = CustomLevelNameInput.ERROR_EXISTS else: full_name = self.file_manager.fix_ext(self.file_name) full_path = join(CustomLevelNameInput.CUSTOM_MAP_PATH, full_name) self.create_map_file(full_path) Globals.STATE = LevelEditor( join('maps', 'map_def.txt'), join(CustomLevelNameInput.CUSTOM_MAP_PATH, full_name), globals=Globals, in_game=True) def handle_escape(self): Globals.STATE = CustomLevelPicker.CustomLevelPicker() def handle_raw_event(self, event): if event.type == pygame.KEYDOWN: self.error_message = None if self.is_valid(event.key): self.handle_entry(self.parse_key(event.key)) elif event.key in CustomLevelNameInput.ARROW_KEYS: self.error_message = CustomLevelNameInput.ERROR_ARROW_KEY def parse_key(self, event_key): if self.is_num(event_key): return chr(event_key) mods = pygame.key.get_mods() shift_pressed = mods & pygame.KMOD_SHIFT if shift_pressed: if event_key == pygame.K_MINUS: return chr(pygame.K_UNDERSCORE) else: return chr(event_key).upper() else: return chr(event_key) def is_valid(self, event_key): return self.is_alpha(event_key) or self.is_num(event_key) or \ event_key == pygame.K_MINUS def is_num(self, event_key): return pygame.K_0 <= event_key and event_key <= pygame.K_9 def is_alpha(self, event_key): return pygame.K_a <= event_key and event_key <= pygame.K_z def create_map_file(self, file_path): shutil.copy(CustomLevelNameInput.BASE_MAP_PATH, file_path)
class CustomLevelPicker(GameState): MAP_FILE_EXT = 'txt' CUSTOM_MAP_PATH = join('maps', 'custom') PLAY_PATH = 'custom' SELECTION_FONT = pygame.font.Font(None, 70) SELECTION_COLOR = pygame.color.Color('white') CREATE_NEW_TEXT = 'Create New Level' SELECTION_TOP_MARGIN = 30 SELECTION_PADDING = 20 HIGHLIGHT_PADDING_HEIGHT = 30 HIGHLIGHT_PADDING_WIDTH = 70 HIGHLIGHT_COLOR = pygame.color.Color("black") HIGHLIGHT_ALPHA = 150 ARROW_MARGIN = 20 SUBTITLE_BACKGROUND = pygame.color.Color("black") SUBTITLE_PADDING = 10 CENTER_SUBTITLE_TEXT = "Press enter to play" LEFT_SUBTITLE_TEXT = "Press 'd' to delete" RIGHT_SUBTITLE_TEXT = "Press 'e' to edit" SUBTITLE_OFFSET = 40 NEW_SUBTITLE_TEXT = "Press enter" SUBTITLE_COLOR = pygame.color.Color("white") SUBTITLE_FONT = pygame.font.Font(None, 32) SUBTITLE_MARGIN_BOTTOM = 50 TITLE_IMAGE_PATH = 'customlevel.png' TITLE_MARGIN_TOP = 70 def __init__(self): self.init_images() self.file_manager = FileManager( path=CustomLevelPicker.CUSTOM_MAP_PATH, file_ext=CustomLevelPicker.MAP_FILE_EXT) self.file_names = self.file_manager.get_files(strip_ext=True) self.current_selection = 0 self.text_surf = None self.text_rect = None self.highlight_surf = None self.highlight_rect = None self.build_text() self.build_subtitles() Globals.play_menu_sound() def init_images(self): self.loader = AssetLoader('images') self.background_img = self.loader.load_image('background.png') self.title_surf = self.loader.load_image_alpha( CustomLevelPicker.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.center = Globals.SCREEN.get_rect().center self.title_rect.top = CustomLevelPicker.TITLE_MARGIN_TOP self.arrow_down_surf = self.loader.load_image_alpha('arrow_down.png') self.arrow_down_rect = self.arrow_down_surf.get_rect() self.arrow_up_surf = self.loader.load_image_alpha('arrow_up.png') self.arrow_up_rect = self.arrow_up_surf.get_rect() self.arrow_up_rect.centerx = Globals.WIDTH / 2 self.arrow_down_rect.centerx = Globals.WIDTH / 2 def build_subtitles(self): self.left_subtitle_surf, self.left_subtitle_rect = self.init_subtitle( CustomLevelPicker.LEFT_SUBTITLE_TEXT, Globals.WIDTH / 4 - CustomLevelPicker.SUBTITLE_OFFSET) self.center_subtitle_surf, self.center_subtitle_rect = \ self.init_subtitle(CustomLevelPicker.CENTER_SUBTITLE_TEXT, Globals.WIDTH / 2) self.right_subtitle_surf, self.right_subtitle_rect = \ self.init_subtitle( CustomLevelPicker.RIGHT_SUBTITLE_TEXT, (3 * Globals.WIDTH) / 4 + CustomLevelPicker.SUBTITLE_OFFSET) self.new_subtitle_surf, self.new_subtitle_rect = \ self.init_subtitle(CustomLevelPicker.NEW_SUBTITLE_TEXT, Globals.WIDTH / 2) def init_subtitle(self, text, centerx): text_surf = CustomLevelPicker.SUBTITLE_FONT.render( text, True, CustomLevelPicker.SUBTITLE_COLOR) subtitle_rect = text_surf.get_rect() subtitle_rect.bottom = \ Globals.HEIGHT - CustomLevelPicker.SUBTITLE_MARGIN_BOTTOM subtitle_rect.centerx = centerx subtitle_rect.inflate_ip( CustomLevelPicker.SUBTITLE_PADDING * 2, CustomLevelPicker.SUBTITLE_PADDING * 2 ) subtitle_surf = pygame.Surface(subtitle_rect.size).convert() subtitle_surf.fill(CustomLevelPicker.SUBTITLE_BACKGROUND) subtitle_surf.blit(text_surf, ( CustomLevelPicker.SUBTITLE_PADDING, CustomLevelPicker.SUBTITLE_PADDING )) return subtitle_surf, subtitle_rect def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.highlight_surf, self.highlight_rect) Globals.SCREEN.blit(self.text_surf, self.text_rect) if self.current_selection == 0: Globals.SCREEN.blit(self.new_subtitle_surf, self.new_subtitle_rect) else: Globals.SCREEN.blit( self.left_subtitle_surf, self.left_subtitle_rect) Globals.SCREEN.blit( self.center_subtitle_surf, self.center_subtitle_rect) Globals.SCREEN.blit( self.right_subtitle_surf, self.right_subtitle_rect) if len(self.file_names) > 0: Globals.SCREEN.blit(self.arrow_down_surf, self.arrow_down_rect) Globals.SCREEN.blit(self.arrow_up_surf, self.arrow_up_rect) def build_text(self): self.text_surf = CustomLevelPicker.SELECTION_FONT.render( self.get_selection_name(), True, CustomLevelPicker.SELECTION_COLOR) self.text_rect = self.text_surf.get_rect() self.text_rect.center = Globals.SCREEN.get_rect().center self.text_rect.top += CustomLevelPicker.SELECTION_TOP_MARGIN self.highlight_rect = self.text_rect.inflate( CustomLevelPicker.HIGHLIGHT_PADDING_WIDTH, CustomLevelPicker.HIGHLIGHT_PADDING_HEIGHT) self.highlight_surf = pygame.Surface(self.highlight_rect.size) self.highlight_surf.fill(CustomLevelPicker.HIGHLIGHT_COLOR) self.highlight_surf.set_alpha(CustomLevelPicker.HIGHLIGHT_ALPHA) self.arrow_up_rect.bottom = self.highlight_rect.top - \ CustomLevelPicker.ARROW_MARGIN self.arrow_down_rect.top = self.highlight_rect.bottom + \ CustomLevelPicker.ARROW_MARGIN def get_selection_name(self): if self.current_selection == 0: return CustomLevelPicker.CREATE_NEW_TEXT else: return self.file_names[self.current_selection - 1] def handle_change(self, delta): self.current_selection = (self.current_selection + delta) % \ (len(self.file_names) + 1) self.build_text() def handle_selection(self): if self.current_selection != 0: file_path = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) level = CustomLevel(join(CustomLevelPicker.PLAY_PATH, file_path)) level.got_current_state() Globals.STATE = level else: Globals.STATE = CustomLevelNameInput() def handle_edit_selection(self): if self.current_selection != 0: file_path = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) Globals.STATE = LevelEditor( join('maps', 'map_def.txt'), join(CustomLevelPicker.CUSTOM_MAP_PATH, file_path), globals=Globals, in_game=True) else: Globals.STATE = CustomLevelNameInput() def handle_delete(self): if self.current_selection != 0: full_name = self.file_manager.fix_ext( self.file_names[self.current_selection - 1]) full_path = join(CustomLevelPicker.CUSTOM_MAP_PATH, full_name) try: os.remove(full_path) self.file_names = self.file_manager.get_files(strip_ext=True) self.handle_change(-1) except Exception as e: print 'An error occured while deleting "' + full_path + '"' print e def handle_escape(self): Globals.STATE = Menu.Menu() def handle_return(self): self.handle_selection() def handle_raw_event(self, event): if event.type == pygame.KEYDOWN: if event.key == pygame.K_e: self.handle_edit_selection() elif event.key == pygame.K_d: self.handle_delete() def handle_key_up(self, keydown): if keydown: self.handle_change(-1) def handle_key_down(self, keydown): if keydown: self.handle_change(1)
class SettingsState(GameState): SLIDER_SIZE = (400, 50) SLIDER_DELTA = 10 MIN_BRIGHTNESS = 30 TITLE_IMAGE_PATH = 'settings.png' CONTROL_IMAGE_PATH = 'control_settings_small.png' VOLUME_IMAGE_PATH = 'volume.png' BRIGHTNESS_IMAGE_PATH = 'brightness.png' TITLE_MARGIN_TOP = 60 TITLE_MARGIN_BOTTOM = 50 LABEL_SLIDER_MARGIN = 5 SLIDER_MARGIN = 10 LABEL_FONT = pygame.font.Font(None, 60) LABEL_COLOR = pygame.color.Color('white') def __init__(self): self.loader = AssetLoader('images') self.background_img = self.loader.load_image('background.png') Globals.play_menu_sound() self.title_surf = self.loader.load_image_alpha( SettingsState.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.centerx = Globals.WIDTH / 2 self.title_rect.top = SettingsState.TITLE_MARGIN_TOP self.control_index = 0 self.init_labels() self.init_sliders() self.selected = 0 def init_labels(self): self.volume_label_surf = self.loader.load_image_alpha( SettingsState.VOLUME_IMAGE_PATH) self.volume_label_rect = self.volume_label_surf.get_rect() self.volume_label_rect.centerx = Globals.WIDTH / 2 self.volume_label_rect.top = self.title_rect.bottom + \ SettingsState.TITLE_MARGIN_BOTTOM self.brightness_label_surf = self.loader.load_image_alpha( SettingsState.BRIGHTNESS_IMAGE_PATH) self.brightness_label_rect = self.brightness_label_surf.get_rect() self.brightness_label_rect.centerx = Globals.WIDTH / 2 self.brightness_label_rect.top = self.volume_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN + \ SettingsState.SLIDER_SIZE[1] + SettingsState.SLIDER_MARGIN self.control_surfs = self.loader.load_spritesheet_alpha( SettingsState.CONTROL_IMAGE_PATH, num_rows=2, num_cols=1) self.control_rect = self.control_surfs[0].get_rect() self.control_rect.centerx = Globals.WIDTH / 2 self.control_rect.top = self.brightness_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN + \ SettingsState.SLIDER_SIZE[1] + SettingsState.SLIDER_MARGIN def init_sliders(self): volume_slider_rect = pygame.Rect((0, 0), SettingsState.SLIDER_SIZE) volume_slider_rect.centerx = Globals.WIDTH / 2 volume_slider_rect.top = self.volume_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN self.volume_slider = SettingsSlider(volume_slider_rect, max_value=100, value=SettingsManager.VOLUME) self.volume_slider.select() brightness_slider_rect = pygame.Rect((0, 0), SettingsState.SLIDER_SIZE) brightness_slider_rect.centerx = Globals.WIDTH / 2 brightness_slider_rect.top = self.brightness_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN self.brightness_slider = SettingsSlider( brightness_slider_rect, max_value=(100 - SettingsState.MIN_BRIGHTNESS), value=(SettingsManager.BRIGHTNESS - SettingsState.MIN_BRIGHTNESS)) def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.volume_label_surf, self.volume_label_rect) Globals.SCREEN.blit(self.brightness_label_surf, self.brightness_label_rect) Globals.SCREEN.blit(self.control_surfs[self.control_index], self.control_rect) self.volume_slider.render(Globals.SCREEN) self.brightness_slider.render(Globals.SCREEN) def update(self, time): self.volume_slider.update(time) self.brightness_slider.update(time) def change_selection(self, delta): self.selected = (self.selected + delta) % 3 if self.selected == 0: self.control_index = 0 self.volume_slider.select() self.brightness_slider.deselect() if self.selected == 1: self.control_index = 0 self.volume_slider.deselect() self.brightness_slider.select() elif self.selected == 2: self.control_index = 1 self.brightness_slider.deselect() self.volume_slider.deselect() def change_value(self, factor=1): if self.selected == 0: self.volume_slider.change_value(SettingsState.SLIDER_DELTA * factor) Globals.set_volume(self.volume_slider.value) elif self.selected == 1: self.brightness_slider.change_value(SettingsState.SLIDER_DELTA * factor) Globals.set_brightness(SettingsState.MIN_BRIGHTNESS + self.brightness_slider.value) def handle_escape(self): Globals.STATE = Menu.Menu() def handle_return(self): if self.selected == 2: Globals.STATE = ControlSettings() def handle_key_left(self, keydown): if keydown: self.change_value(-1) def handle_key_right(self, keydown): if keydown: self.change_value(1) def handle_key_up(self, keydown): if keydown: self.change_selection(-1) def handle_key_down(self, keydown): if keydown: self.change_selection(1)
class ControlSettings(GameState): TITLE_IMAGE_PATH = 'control_settings.png' TITLE_MARGIN_TOP = 60 TITLE_TEXT_MARGIN = 40 TITLE_ARROW_MARGIN = 100 SURF_INDEX_NORMAL = 0 SURF_INDEX_HIT = 1 SURF_INDEX_SELECTED = 2 ARROW_PADDING = 10 KEY_PADDING = 30 RESET_MARGIN_BOTTOM = 20 INDEX_UP = 0 INDEX_DOWN = 2 INDEX_LEFT = 1 INDEX_RIGHT = 3 INDEX_ATTACK = 4 INDEX_ACTION = 5 INDEX_ESCAPE = 6 INDEX_RETURN = 7 INDEX_RESET = 8 NUM_OPTIONS = 9 def __init__(self): self.loader = AssetLoader('images') self.control_loader = AssetLoader(join('images', 'controls')) self.background_img = self.loader.load_image('background.png') self.title_surf = self.loader.load_image_alpha( ControlSettings.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.centerx = Globals.WIDTH / 2 self.title_rect.top = ControlSettings.TITLE_MARGIN_TOP self.arrows_top = self.title_rect.bottom + \ ControlSettings.TITLE_ARROW_MARGIN self.arrows_x_center = int(Globals.WIDTH / 4) self.text_top = self.title_rect.bottom + \ ControlSettings.TITLE_TEXT_MARGIN self.surf_rect_pairs = [SurfRectPair() for i in range(0, ControlSettings.NUM_OPTIONS)] self.surf_index = [ControlSettings.SURF_INDEX_NORMAL for i in range( 0, ControlSettings.NUM_OPTIONS)] self.last_surf_index = [ ControlSettings.SURF_INDEX_NORMAL for i in range(0, ControlSettings.NUM_OPTIONS)] self.ignore_index = [0 for i in range(0, ControlSettings.NUM_OPTIONS)] self.load_control_images() self.selection = 0 self.set_selection(0) def set_selection(self, index): if self.selection != -1: if self.surf_index[self.selection] == \ ControlSettings.SURF_INDEX_HIT: self.last_surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL else: self.last_surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL self.surf_index[ self.selection] = ControlSettings.SURF_INDEX_NORMAL self.selection = index if self.surf_index[index] == ControlSettings.SURF_INDEX_HIT: self.last_surf_index[index] = ControlSettings.SURF_INDEX_SELECTED else: self.last_surf_index[index] = self.surf_index[index] self.surf_index[index] = ControlSettings.SURF_INDEX_SELECTED def change_selection(self, delta): index = self.selection + delta if index < 0 or index >= ControlSettings.NUM_OPTIONS: return self.set_selection(index) def select(self): if self.selection == -1: return if self.selection == ControlSettings.INDEX_RESET: SettingsManager.reset_controls() self.set_selection(0) return Globals.STATE = SetJoystickKeyState( self.surf_rect_pairs[self.selection].surf_arr[0], list_index=self.selection, return_state=self) def load_image_group(self, file_path): return self.control_loader.load_spritesheet_alpha( file_path, num_rows=3, num_cols=1) def set_surf_arr(self, index, file_path): self.surf_rect_pairs[index].surf_arr = self.load_image_group(file_path) self.surf_rect_pairs[index].rect = self.surf_rect_pairs[ index].surf_arr[0].get_rect() def get_surf(self, index): return self.surf_rect_pairs[index].surf_arr[self.surf_index[index]] def get_rect(self, index): return self.surf_rect_pairs[index].rect def load_control_images(self): self.load_arrows() self.set_surf_arr(ControlSettings.INDEX_ATTACK, 'attack_key.png') self.set_surf_arr(ControlSettings.INDEX_ACTION, 'action_key.png') self.set_surf_arr(ControlSettings.INDEX_ESCAPE, 'escape_key.png') self.set_surf_arr(ControlSettings.INDEX_RETURN, 'return_key.png') self.set_surf_arr(ControlSettings.INDEX_RESET, 'reset_controls.png') centerx = int((3 * Globals.WIDTH) / 4) attack_key_rect = self.get_rect(ControlSettings.INDEX_ATTACK) attack_key_rect.centerx = centerx attack_key_rect.top = self.text_top action_key_rect = self.get_rect(ControlSettings.INDEX_ACTION) action_key_rect.centerx = centerx action_key_rect.top = attack_key_rect.bottom + \ ControlSettings.KEY_PADDING escape_key_rect = self.get_rect(ControlSettings.INDEX_ESCAPE) escape_key_rect.centerx = centerx escape_key_rect.top = action_key_rect.bottom + \ ControlSettings.KEY_PADDING return_key_rect = self.get_rect(ControlSettings.INDEX_RETURN) return_key_rect.centerx = centerx return_key_rect.top = escape_key_rect.bottom + \ ControlSettings.KEY_PADDING reset_rect = self.get_rect(ControlSettings.INDEX_RESET) reset_rect.centerx = int(Globals.WIDTH / 2) reset_rect.bottom = Globals.HEIGHT - \ ControlSettings.RESET_MARGIN_BOTTOM def load_arrows(self): self.set_surf_arr(ControlSettings.INDEX_UP, 'arrow_up.png') self.set_surf_arr(ControlSettings.INDEX_DOWN, 'arrow_down.png') self.set_surf_arr(ControlSettings.INDEX_LEFT, 'arrow_left.png') self.set_surf_arr(ControlSettings.INDEX_RIGHT, 'arrow_right.png') arrow_up_rect = self.get_rect(ControlSettings.INDEX_UP) arrow_up_rect.centerx = self.arrows_x_center arrow_up_rect.top = self.arrows_top arrow_down_rect = self.get_rect(ControlSettings.INDEX_DOWN) arrow_down_rect.centerx = arrow_up_rect.centerx arrow_down_rect.top = arrow_up_rect.bottom + \ ControlSettings.ARROW_PADDING arrow_left_rect = self.get_rect(ControlSettings.INDEX_LEFT) arrow_left_rect.top = arrow_down_rect.top arrow_left_rect.right = arrow_down_rect.left - \ ControlSettings.ARROW_PADDING arrow_right_rect = self.get_rect(ControlSettings.INDEX_RIGHT) arrow_right_rect.top = arrow_down_rect.top arrow_right_rect.left = arrow_down_rect.right + \ ControlSettings.ARROW_PADDING def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) for i, pair in enumerate(self.surf_rect_pairs): Globals.SCREEN.blit(pair.surf_arr[self.surf_index[i]], pair.rect) def handle_raw_event(self, event): if event.type == pygame.KEYDOWN: index = -1 if event in SettingsManager.EVENTS_UP: index = ControlSettings.INDEX_UP elif event in SettingsManager.EVENTS_DOWN: index = ControlSettings.INDEX_DOWN elif event in SettingsManager.EVENTS_LEFT: index = ControlSettings.INDEX_LEFT elif event in SettingsManager.EVENTS_RIGHT: index = ControlSettings.INDEX_RIGHT elif event in SettingsManager.EVENTS_ESCAPE: index = ControlSettings.INDEX_ESCAPE elif event in SettingsManager.EVENTS_ACTION: index = ControlSettings.INDEX_ACTION elif event in SettingsManager.EVENTS_ATTACK: index = ControlSettings.INDEX_ATTACK elif event in SettingsManager.EVENTS_RETURN: index = ControlSettings.INDEX_RETURN if index != -1: self.ignore_index[index] = 2 def quit(self): import SettingsState Globals.STATE = SettingsState.SettingsState() def check_hit(self, index, keydown=True): if not keydown: self.ignore_index[index] = 0 if self.surf_index[index] != ControlSettings.SURF_INDEX_SELECTED: self.set_last_state(index) return False if self.ignore_index[index] > 0: self.ignore_index[index] -= 1 if self.surf_index[index] != ControlSettings.SURF_INDEX_SELECTED: self.set_last_state(index) return False self.last_surf_index[index] = self.surf_index[index] self.surf_index[index] = ControlSettings.SURF_INDEX_HIT return True def set_last_state(self, index): if self.last_surf_index[index] == ControlSettings.SURF_INDEX_HIT: self.last_surf_index[index] = ControlSettings.SURF_INDEX_NORMAL self.surf_index[index] = self.last_surf_index[index] def handle_action_key(self, keydown=True): self.check_hit(ControlSettings.INDEX_ACTION, keydown) def handle_action_keyup(self): self.handle_action_key(False) def handle_attack(self, keydown=True): self.check_hit(ControlSettings.INDEX_ATTACK, keydown) def handle_attack_keyup(self): self.handle_attack(False) def handle_key_down(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_DOWN] > 0: self.change_selection(1) self.check_hit(ControlSettings.INDEX_DOWN, keydown) def handle_key_up(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_UP] > 0: self.change_selection(-1) self.check_hit(ControlSettings.INDEX_UP, keydown) def handle_key_left(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_LEFT] > 0: self.change_selection(-1) self.check_hit(ControlSettings.INDEX_LEFT, keydown) def handle_key_right(self, keydown): if keydown and self.ignore_index[ControlSettings.INDEX_RIGHT] > 0: self.change_selection(1) self.check_hit(ControlSettings.INDEX_RIGHT, keydown) def handle_backspace(self): pass def handle_return(self, keydown=True): if keydown and self.ignore_index[ControlSettings.INDEX_RETURN] > 0: self.select() self.ignore_index[ControlSettings.INDEX_RETURN] = 0 else: self.check_hit(ControlSettings.INDEX_RETURN, keydown) def handle_return_keyup(self): self.handle_return(False) def handle_escape(self, keydown=True): if self.ignore_index[ControlSettings.INDEX_ESCAPE] > 0: self.quit() self.check_hit(ControlSettings.INDEX_ESCAPE, keydown) def handle_escape_keyup(self): self.handle_escape(False)
class SettingsState(GameState): SLIDER_SIZE = (400, 50) SLIDER_DELTA = 10 MIN_BRIGHTNESS = 30 TITLE_IMAGE_PATH = 'settings.png' CONTROL_IMAGE_PATH = 'control_settings_small.png' VOLUME_IMAGE_PATH = 'volume.png' BRIGHTNESS_IMAGE_PATH = 'brightness.png' TITLE_MARGIN_TOP = 60 TITLE_MARGIN_BOTTOM = 50 LABEL_SLIDER_MARGIN = 5 SLIDER_MARGIN = 10 LABEL_FONT = pygame.font.Font(None, 60) LABEL_COLOR = pygame.color.Color('white') def __init__(self): self.loader = AssetLoader('images') self.background_img = self.loader.load_image('background.png') Globals.play_menu_sound() self.title_surf = self.loader.load_image_alpha( SettingsState.TITLE_IMAGE_PATH) self.title_rect = self.title_surf.get_rect() self.title_rect.centerx = Globals.WIDTH / 2 self.title_rect.top = SettingsState.TITLE_MARGIN_TOP self.control_index = 0 self.init_labels() self.init_sliders() self.selected = 0 def init_labels(self): self.volume_label_surf = self.loader.load_image_alpha( SettingsState.VOLUME_IMAGE_PATH) self.volume_label_rect = self.volume_label_surf.get_rect() self.volume_label_rect.centerx = Globals.WIDTH / 2 self.volume_label_rect.top = self.title_rect.bottom + \ SettingsState.TITLE_MARGIN_BOTTOM self.brightness_label_surf = self.loader.load_image_alpha( SettingsState.BRIGHTNESS_IMAGE_PATH) self.brightness_label_rect = self.brightness_label_surf.get_rect() self.brightness_label_rect.centerx = Globals.WIDTH / 2 self.brightness_label_rect.top = self.volume_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN + \ SettingsState.SLIDER_SIZE[1] + SettingsState.SLIDER_MARGIN self.control_surfs = self.loader.load_spritesheet_alpha( SettingsState.CONTROL_IMAGE_PATH, num_rows=2, num_cols=1) self.control_rect = self.control_surfs[0].get_rect() self.control_rect.centerx = Globals.WIDTH / 2 self.control_rect.top = self.brightness_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN + \ SettingsState.SLIDER_SIZE[1] + SettingsState.SLIDER_MARGIN def init_sliders(self): volume_slider_rect = pygame.Rect((0, 0), SettingsState.SLIDER_SIZE) volume_slider_rect.centerx = Globals.WIDTH / 2 volume_slider_rect.top = self.volume_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN self.volume_slider = SettingsSlider( volume_slider_rect, max_value=100, value=SettingsManager.VOLUME) self.volume_slider.select() brightness_slider_rect = pygame.Rect((0, 0), SettingsState.SLIDER_SIZE) brightness_slider_rect.centerx = Globals.WIDTH / 2 brightness_slider_rect.top = self.brightness_label_rect.bottom + \ SettingsState.LABEL_SLIDER_MARGIN self.brightness_slider = SettingsSlider( brightness_slider_rect, max_value=(100 - SettingsState.MIN_BRIGHTNESS), value=(SettingsManager.BRIGHTNESS - SettingsState.MIN_BRIGHTNESS)) def render(self): Globals.SCREEN.blit(self.background_img, (0, 0)) Globals.SCREEN.blit(self.title_surf, self.title_rect) Globals.SCREEN.blit(self.volume_label_surf, self.volume_label_rect) Globals.SCREEN.blit(self.brightness_label_surf, self.brightness_label_rect) Globals.SCREEN.blit(self.control_surfs[self.control_index], self.control_rect) self.volume_slider.render(Globals.SCREEN) self.brightness_slider.render(Globals.SCREEN) def update(self, time): self.volume_slider.update(time) self.brightness_slider.update(time) def change_selection(self, delta): self.selected = (self.selected + delta) % 3 if self.selected == 0: self.control_index = 0 self.volume_slider.select() self.brightness_slider.deselect() if self.selected == 1: self.control_index = 0 self.volume_slider.deselect() self.brightness_slider.select() elif self.selected == 2: self.control_index = 1 self.brightness_slider.deselect() self.volume_slider.deselect() def change_value(self, factor=1): if self.selected == 0: self.volume_slider.change_value( SettingsState.SLIDER_DELTA * factor) Globals.set_volume(self.volume_slider.value) elif self.selected == 1: self.brightness_slider.change_value( SettingsState.SLIDER_DELTA * factor) Globals.set_brightness(SettingsState.MIN_BRIGHTNESS + self.brightness_slider.value) def handle_escape(self): Globals.STATE = Menu.Menu() def handle_return(self): if self.selected == 2: Globals.STATE = ControlSettings() def handle_key_left(self, keydown): if keydown: self.change_value(-1) def handle_key_right(self, keydown): if keydown: self.change_value(1) def handle_key_up(self, keydown): if keydown: self.change_selection(-1) def handle_key_down(self, keydown): if keydown: self.change_selection(1)