pre-render platform glow, slightly optimize dialogue

This commit is contained in:
ohsqueezy 2022-12-02 16:34:44 -05:00
parent 0b3e09f807
commit 63a7ddf51f
2 changed files with 78 additions and 91 deletions

168
NS.py
View File

@ -10,7 +10,7 @@
# #
# This is the main file containing all the pygame code. # This is the main file containing all the pygame code.
import argparse, pathlib, operator, subprocess, sys import argparse, pathlib, operator, subprocess, sys, os
from random import randint, choice, random from random import randint, choice, random
from math import pi from math import pi
from copy import copy from copy import copy
@ -585,10 +585,10 @@ class LevelSelect(Animation):
platform.view.frames[ii] = scaled platform.view.frames[ii] = scaled
platform.view.get_current_frameset().measure_rect() platform.view.get_current_frameset().measure_rect()
platform.view.update_location_size() platform.view.update_location_size()
for corner in platform.glow_masks: # for corner in platform.glow_masks:
for ii, frame in enumerate(corner): # for ii, frame in enumerate(corner):
scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale))) # scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale)))
corner[ii] = scaled # corner[ii] = scaled
self.platforms[0].view.location.left = dsr.left + indent self.platforms[0].view.location.left = dsr.left + indent
self.platforms[1].view.location.centerx = dsr.centerx self.platforms[1].view.location.centerx = dsr.centerx
self.platforms[2].view.location.right = dsr.right - indent self.platforms[2].view.location.right = dsr.right - indent
@ -929,14 +929,15 @@ class Tony(Sprite):
Sprite.update(self) Sprite.update(self)
# Blend the effect frame with the sprite frame # Blend the effect frame with the sprite frame
if self.get_configuration("display", "alpha-effect-title"): if not self.get_configuration("system", "minimize-load-time"):
self.display_surface = save if self.get_configuration("display", "alpha-effect-title"):
self.location = location_save self.display_surface = save
self.effect.display_surface = intermediate_surface self.location = location_save
self.effect.update(flags=BLEND_RGBA_SUB) self.effect.display_surface = intermediate_surface
self.get_display_surface().blit(intermediate_surface, self.location.topleft) self.effect.update(flags=BLEND_RGBA_SUB)
else: self.get_display_surface().blit(intermediate_surface, self.location.topleft)
self.effect.update(flags=BLEND_RGBA_SUB) else:
self.effect.update(flags=BLEND_RGBA_SUB)
# Update title screen objects that are drawn over this sprite # Update title screen objects that are drawn over this sprite
if self.get_game().title.active: if self.get_game().title.active:
@ -1165,9 +1166,9 @@ class Title(Animation):
arrow.set_colorkey((255, 0, 255)) arrow.set_colorkey((255, 0, 255))
arrow.fill((255, 0, 255)) arrow.fill((255, 0, 255))
if screen_pos[0] == 0: if screen_pos[0] == 0:
points = 0, arrow.get_height() // 2, arrow.get_width(), 0, arrow.get_width(), arrow.get_height() points = 0, arrow.get_height() // 2, arrow.get_width() - 1, 0, arrow.get_width() - 1, arrow.get_height() - 1
else: else:
points = 0, 0, 0, arrow.get_height(), arrow.get_width(), arrow.get_height() // 2 points = 0, 0, 0, arrow.get_height() - 1, arrow.get_width() - 1, arrow.get_height() // 2
pygame.gfxdraw.filled_trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], bg) pygame.gfxdraw.filled_trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], bg)
pygame.gfxdraw.trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], (0, 0, 0)) pygame.gfxdraw.trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], (0, 0, 0))
self.score_indicator.add_frame(arrow) self.score_indicator.add_frame(arrow)
@ -1352,6 +1353,8 @@ class Dialogue(Animation):
self.name_box.add_frame(frame) self.name_box.add_frame(frame)
self.name_box.location.bottomleft = self.avatar_box.location.bottomright self.name_box.location.bottomleft = self.avatar_box.location.bottomright
self.speech_channel = None self.speech_channel = None
self.base_message_frame = Surface((self.text_box.location.w - 10, 30 * 2))
self.base_message_frame.fill(self.BACKGROUND)
def reset(self): def reset(self):
self.stop_speech() self.stop_speech()
@ -1410,13 +1413,13 @@ class Dialogue(Animation):
font = pygame.font.Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE) font = pygame.font.Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE)
message = Sprite(self) message = Sprite(self)
lines = self.full_text[:self.text_index].split("\n") lines = self.full_text[:self.text_index].split("\n")
frame = Surface((self.text_box.location.w - 10, 30 * len(lines)), SRCALPHA) frame = self.base_message_frame.copy()
for ii, line in enumerate(lines): for ii, line in enumerate(lines):
surface = font.render(line, True, self.TEXT_COLOR).convert_alpha() surface = font.render(line, True, self.TEXT_COLOR, self.BACKGROUND).convert()
frame.blit(surface, (0, 30 * ii)) frame.blit(surface, (0, 30 * ii))
message.add_frame(frame) message.add_frame(frame)
message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8 message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8
message.update() message.update()
class SkipPrompt(GameChild): class SkipPrompt(GameChild):
@ -1647,44 +1650,49 @@ class Platform(GameChild):
def __init__(self, parent, center): def __init__(self, parent, center):
""" """
Initialize four lights, one for each pad on the platform. Initialize a Sprite for the pad graphics with one Initialize four lights, one for each pad on the platform. Initialize a Sprite for the pad graphics with one
frameset per six possible combinations of lights. Initialize masks for creating a glow effect on the pads. frameset per six possible combinations of lights.
@param parent PGFW game object that initialized this object @param parent PGFW game object that initialized this object
@param center tuple that gives the (x, y) screen coordinates of this platform @param center tuple that gives the (x, y) screen coordinates of this platform
""" """
GameChild.__init__(self, parent) GameChild.__init__(self, parent)
# Create objects for tracking the individual pad lights
self.lights = [ self.lights = [
Light(self, self.get_configuration("pads", "nw_color"), NS.LNW), Light(self, self.get_configuration("pads", "nw_color"), NS.LNW),
Light(self, self.get_configuration("pads", "ne_color"), NS.LNE), Light(self, self.get_configuration("pads", "ne_color"), NS.LNE),
Light(self, self.get_configuration("pads", "se_color"), NS.LSE), Light(self, self.get_configuration("pads", "se_color"), NS.LSE),
Light(self, self.get_configuration("pads", "sw_color"), NS.LSW) Light(self, self.get_configuration("pads", "sw_color"), NS.LSW)
] ]
# Create a sprite which will display the pad
self.view = Sprite(self) self.view = Sprite(self)
self.view.load_from_path("pad", True) self.view.load_from_path(os.path.join(self.get_resource("pad"), "pad_0.png"), True)
self.view.add_frameset([0], name="neutral") self.view.add_frameset([0], name="neutral")
self.view.add_frameset([1], name=str(NS.N))
self.view.add_frameset([2], name=str(NS.E)) # For each of the six combinations of lights, create a glowing frameset
self.view.add_frameset([3], name=str(NS.NW)) light_masks = load_frames(self.get_resource("pad_mask"), True)
self.view.add_frameset([4], name=str(NS.NE)) for orientation_index, orientation in enumerate((NS.N, NS.E, NS.NW, NS.NE, NS.W, NS.S)):
self.view.add_frameset([5], name=str(NS.W)) pad_base_frame = load_frames(os.path.join(self.get_resource("pad"), f"pad_{orientation_index + 1}.png"), True)[0]
self.view.add_frameset([6], name=str(NS.S)) self.view.add_frame(pad_base_frame)
self.view.location.center = center frameset = [len(self.view.frames) - 1]
self.glow_masks = []
base_images = load_frames(self.get_resource("pad_mask"), True)
for image in base_images:
self.glow_masks.append([image])
for mask in self.glow_masks:
intensity_resolution = 12 intensity_resolution = 12
for intensity in range(1, intensity_resolution): for intensity in range(1, intensity_resolution):
copy = mask[0].copy() next_pad_frame = pad_base_frame.copy()
pixels = pygame.PixelArray(copy) for light_orientation in self.get_buttons_from_edges([orientation]):
color = pygame.Color(0, 0, 0) copy = light_masks[light_orientation].copy()
h, s, l, a = color.hsla pixels = pygame.PixelArray(copy)
l = int(intensity / intensity_resolution * 100) color = pygame.Color(0, 0, 0)
color.hsla = h, s, l, a h, s, l, a = color.hsla
pixels.replace(pygame.Color(0, 0, 0), color) l = int(intensity / intensity_resolution * 100)
del pixels color.hsla = h, s, l, a
mask.append(copy) pixels.replace(pygame.Color(0, 0, 0), color)
del pixels
next_pad_frame.blit(copy, (0, 0), None, BLEND_RGBA_ADD)
self.view.add_frame(next_pad_frame)
frameset.append(len(self.view.frames) - 1)
self.view.add_frameset(frameset, name=str(orientation))
self.view.location.center = center
def reset(self): def reset(self):
""" """
@ -1878,9 +1886,9 @@ class Platform(GameChild):
""" """
for ii, light in enumerate(self.lights): for ii, light in enumerate(self.lights):
light.glow_index = 0 light.glow_index = 0
light.halt(light.glow) light.unglow()
if ii in selected: if ii in selected:
light.play(light.glow) light.glow()
def update(self): def update(self):
""" """
@ -1897,11 +1905,6 @@ class Platform(GameChild):
else: else:
self.view.set_frameset(str(glowing)) self.view.set_frameset(str(glowing))
self.view.update() self.view.update()
if not self.view.is_hidden() and not self.view.is_playing(self.view.wipe_out):
for light in self.lights:
if light.glowing():
self.get_display_surface().blit(
self.glow_masks[light.position][light.glow_index], self.view.location, None, BLEND_RGBA_ADD)
# track how long an edge has been pressed # track how long an edge has been pressed
if self.get_edge_pressed() is not None: if self.get_edge_pressed() is not None:
if self.get_edge_pressed() != self.previously_pressed_edge: if self.get_edge_pressed() != self.previously_pressed_edge:
@ -1914,11 +1917,10 @@ class Platform(GameChild):
self.press_elapsed = 0 self.press_elapsed = 0
class Light(Animation): class Light(GameChild):
""" """
This class represents a pad on the platform. Typically there are four instances for a platform, one for each corner of the This class represents a pad on the platform. Typically there are four instances for a platform, one for each corner of the
platform. Each light stores its color and position on the platform. This class contains methods for glowing the light and platform. Each light stores its color, position on the platform, and state of glowing.
getting its properties.
""" """
TITLE_OFFSET = 0 TITLE_OFFSET = 0
@ -1931,7 +1933,7 @@ class Light(Animation):
@param color pygame color object @param color pygame color object
@param position the light's position on the platform, one of NS.LNW, NS.LNE, NS.LSE, NS.LSW @param position the light's position on the platform, one of NS.LNW, NS.LNE, NS.LSE, NS.LSW
""" """
Animation.__init__(self, parent) GameChild.__init__(self, parent)
self.color = Color(color) self.color = Color(color)
self.color.a = 225 self.color.a = 225
self.position = position self.position = position
@ -1956,39 +1958,46 @@ class Light(Animation):
self.points = mid, midright, backright, backmid self.points = mid, midright, backright, backmid
elif self.position == NS.LSW: elif self.position == NS.LSW:
self.points = midleft, mid, backmid, backleft self.points = midleft, mid, backmid, backleft
self.register(self.glow)
def reset(self): def reset(self):
""" """
Unhide, halt glow animation Unhide, halt glow animation
""" """
self.hidden = False self.unglow()
self.halt(self.glow)
self.reset_timer()
self.glow_index = 0
def glow(self): def glow(self):
""" """
Moves the glow animation forward a frame by incrementing an index Set the glow state to True
""" """
self.glow_index += 1 self.is_glowing = True
if self.glow_index >= len(self.parent.glow_masks[0]):
self.glow_index = 0 def unglow(self):
"""
Set the glow state to False
"""
self.is_glowing = False
def glowing(self):
"""
Returns True if this light is glowing, False otherwise
@return True | False
"""
return self.is_glowing
def update(self): def update(self):
""" """
Checks the attack state to determine whether to start or stop glowing Checks the attack state to determine whether to start or stop glowing
""" """
Animation.update(self)
if not self.get_game().title.active and not self.get_game().level_select.active: if not self.get_game().title.active and not self.get_game().level_select.active:
boss = self.get_game().boss boss = self.get_game().boss
chemtrails = self.get_game().chemtrails chemtrails = self.get_game().chemtrails
# checks the boss attack queue and chameleon queue index to see if the glow should be started now # checks the boss attack queue and chameleon queue index to see if the glow should be started now
if boss.queue and not self.is_playing(self.glow) and self.in_orientation(boss.queue[chemtrails.queue_index]): if boss.queue and self.in_orientation(boss.queue[chemtrails.queue_index]):
self.play(self.glow) self.glow()
# turns off the glow # turns off the glow
elif self.is_playing(self.glow) and (not boss.queue or not self.in_orientation(boss.queue[chemtrails.queue_index])): elif not boss.queue or not self.in_orientation(boss.queue[chemtrails.queue_index]):
self.reset() self.unglow()
def get_points(self): def get_points(self):
if self.get_game().title.active: if self.get_game().title.active:
@ -1999,21 +2008,6 @@ class Light(Animation):
else: else:
return self.points return self.points
def draw_glow(self):
for ii, y in enumerate(range(0, self.glow_index, 3)):
shifted = []
for point in self.get_points():
shifted.append((point[0], point[1] - y))
if self.position == NS.LSW:
saturation = 0
else:
saturation = int((self.color.hsla[1] + 80) % 100)
if not ii % 2:
lightness = 0
else:
lightness = 40
lines(self.get_display_surface(), get_hsla_color(int(self.color.hsla[0]), saturation, lightness), True, shifted, 3)
def in_orientation(self, orientation): def in_orientation(self, orientation):
""" """
Returns True if this light is contained in the given edge Returns True if this light is contained in the given edge
@ -2030,14 +2024,6 @@ class Light(Animation):
elif self.position == NS.LSW: elif self.position == NS.LSW:
return orientation in (NS.S, NS.NE, NS.W) return orientation in (NS.S, NS.NE, NS.W)
def glowing(self):
"""
Returns True if this light is glowing, False otherwise
@return True | False
"""
return self.is_playing(self.glow)
class Chemtrails(Sprite): class Chemtrails(Sprite):
""" """

View File

@ -1,6 +1,7 @@
41802 0 41802 0
41903 0 41903 0
42153 0 42153 0
47259 0
48935 0 48935 0
50940 0 50940 0
51245 0 51245 0