From 57168817b98ef39c2001e31c174426db1d6f1ffa Mon Sep 17 00:00:00 2001 From: frank Date: Wed, 2 Nov 2022 19:21:24 -0400 Subject: [PATCH] add logo and tony glow effects to toggleable effects --- NS.py | 106 +++++++++++++++++++++++++++++++++++++++------------------ config | 2 +- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/NS.py b/NS.py index e3bc23b..4ecdb3f 100644 --- a/NS.py +++ b/NS.py @@ -536,13 +536,7 @@ class LevelSelect(Animation): text_rect.midleft = preview_rect.midleft frame = self.get_game().boss.backgrounds[level_index].frames[0] frame_rect = (preview_rect.w - text_rect.w - padding, preview_rect.h - padding * 2) - - # Smooth scaling is not available on some platforms, so fallback to regular scale - try: - environment = pygame.transform.smoothscale(frame, frame_rect) - except ValueError: - environment = pygame.transform.scale(frame, frame_rect) - + environment = pygame.transform.smoothscale(frame, frame_rect) environment_rect = environment.get_rect() environment_rect.midright = preview_rect.right - padding, preview_rect.centery boss = pygame.transform.smoothscale(self.get_game().boss.level_sprite(level_index).frames[0], @@ -777,14 +771,23 @@ class Meter(GameChild): class Tony(Sprite): + """ + A fullscreen-sized sprite of Tony Hawk the Birdman with animation and glow effects. + """ def __init__(self, parent): + """ + Load board animation, create a glow effect, and load taunt sound effects. + """ Sprite.__init__(self, parent, 100, False) + dsr = self.get_display_surface().get_rect() self.board = Sprite(self, 100) self.board.load_from_path(self.get_resource("newTony/TonyArms"), True) - self.effect = Sprite(self) - dsr = self.get_display_surface().get_rect() - if self.get_configuration("display", "effects"): + + # Create a glowing effect object by adding glow frames to a blank Sprite. It can then be applied to the main Tony Sprite frame + # using `pygame.BLEND_RGBA_SUB`. Skip this if fast load is requested. + if not self.get_configuration("system", "minimize-load-time"): + self.effect = Sprite(self) for offset in range(12): w, h = dsr.w + 40, int(dsr.h * .65) glow = Surface((w, h), SRCALPHA) @@ -797,7 +800,8 @@ class Tony(Sprite): ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color) filled_ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color) self.effect.add_frame(glow) - self.effect.location.topleft = -20, int(dsr.h * .35) + self.effect.location.topleft = -20, int(dsr.h * .35) + self.add_frame(load(self.get_resource("Big_Tony.png")).convert_alpha()) self.load_from_path(self.get_resource("newTony/TonyShirtHead"), True) self.add_frameset([0], name="static") @@ -828,21 +832,36 @@ class Tony(Sprite): self.get_audio().play_sfx(choice(self.taunts)) def update(self): - save = self.get_display_surface() - intermediate_surface = Surface(self.location.size, SRCALPHA) - self.display_surface = intermediate_surface - location_save = self.location.copy() - self.location.topleft = 0, 0 + """ + Apply the glow effect using an intermediate surface to blend the glow effect with the current main sprite frame. Skip the effect if + effects are off. Update title screen objects. Update the board sub-animation if it is active. + """ + # Create an intermediate surface for blending the glow with the sprite frame + if self.get_configuration("display", "effects"): + save = self.get_display_surface() + intermediate_surface = Surface(self.location.size, SRCALPHA) + self.display_surface = intermediate_surface + location_save = self.location.copy() + self.location.topleft = 0, 0 + + # Do a regular Sprite animation update Sprite.update(self) - self.display_surface = save - self.location = location_save - self.effect.display_surface = intermediate_surface - self.effect.update(flags=BLEND_RGBA_SUB) - self.get_display_surface().blit(intermediate_surface, self.location.topleft) + + # Blend the effect frame with the sprite frame + if self.get_configuration("display", "effects"): + self.display_surface = save + self.location = location_save + self.effect.display_surface = intermediate_surface + self.effect.update(flags=BLEND_RGBA_SUB) + self.get_display_surface().blit(intermediate_surface, self.location.topleft) + + # Update title screen objects that are drawn over this sprite if self.get_game().title.active: self.get_game().title.video.update() self.get_game().platform.update() self.get_game().chemtrails.update() + + # Update the board sub-animation frameset = self.get_current_frameset() if frameset.name == "board": self.board.get_current_frameset().current_index = frameset.current_index @@ -905,8 +924,15 @@ class Video(Sprite): class Logo(Sprite): + """ + A screen-sized layer that is itself two layers, displaying the logo, scrolling infinitely, with a glowing effect. + """ def __init__(self, parent): + """ + Load the logo and add locations at regular offsets until the screen is covered to create a tile fill effect. Create a second + Sprite that will display a glow effect that can be blended into the main layer. + """ Sprite.__init__(self, parent) dsr = self.get_display_surface().get_rect() self.load_from_path(self.get_resource("Title_tile.png"), True) @@ -914,24 +940,36 @@ class Logo(Sprite): for x in range(0, dsr.w + self.location.w, self.location.w): if x != 0 or y != 0: self.add_location((x, y)) - self.effect = Sprite(self, 100) - palette = (255, 255, 255), (255, 255, 128), (255, 255, 0) - thickness = 8 - for offset in range(len(palette)): - frame = Surface(dsr.size) - for x in range(0, dsr.w, thickness): - frame.fill(palette[(offset + x) % len(palette)], (x, 0, thickness, dsr.h)) - self.effect.add_frame(frame) + + # Create a screen sized Sprite to create a glowing animation drawn onto blank frames + if self.get_configuration("display", "effects"): + self.effect = Sprite(self, 100) + palette = (255, 255, 255), (255, 255, 128), (255, 255, 0) + thickness = 8 + for offset in range(len(palette)): + frame = Surface(dsr.size) + for x in range(0, dsr.w, thickness): + frame.fill(palette[(offset + x) % len(palette)], (x, 0, thickness, dsr.h)) + self.effect.add_frame(frame) def update(self): - self.effect.update() - # tiled background + """ + Scroll the tiles, wrapping at the edges of the screen. Draw the effect layer beneath the logo tile and blend with the logo + if effects are on. + """ + # Wrap around motion effect self.move(-2, 2) if self.location.right < 0: self.move(self.location.w) if self.location.top > 0: self.move(dy=-self.location.h) - Sprite.update(self, flags=BLEND_RGBA_MIN) + + # Blend with the effect layer if effects are on + if self.get_configuration("display", "effects"): + self.effect.update() + Sprite.update(self, flags=BLEND_RGBA_MIN) + else: + Sprite.update(self) class Title(Animation): @@ -2765,8 +2803,8 @@ class Sword(Animation): self.swords.append([[], [], [], [], [], []]) self.spinning_swords.append([[], [], [], [], [], []]) base_image_paths = sorted(iglob(join(self.get_resource(root), "*.png"))) - # If effects are turned off, use a single frame - if not self.get_configuration("display", "effects"): + # If fast load is requested, use a single frame + if not self.get_configuration("system", "minimize-load-time"): base_image_paths = [base_image_paths[0]] # Create a square surface that can be used to blit the rotated sword centered so each frame is the same size size = max(*load(self.get_resource(base_image_paths[0])).get_size()) diff --git a/config b/config index 91449e0..af123ce 100644 --- a/config +++ b/config @@ -26,7 +26,7 @@ show-framerate = no dimensions = 800, 450 fullscreen = no attract-gif-alpha = 0.95 -effects = yes +effects = True [system] # will force set display->effects to off