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.
import argparse, pathlib, operator, subprocess, sys
import argparse, pathlib, operator, subprocess, sys, os
from random import randint, choice, random
from math import pi
from copy import copy
@ -585,10 +585,10 @@ class LevelSelect(Animation):
platform.view.frames[ii] = scaled
platform.view.get_current_frameset().measure_rect()
platform.view.update_location_size()
for corner in platform.glow_masks:
for ii, frame in enumerate(corner):
scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale)))
corner[ii] = scaled
# for corner in platform.glow_masks:
# for ii, frame in enumerate(corner):
# scaled = pygame.transform.smoothscale(frame, (int(frame.get_width() * scale), int(frame.get_height() * scale)))
# corner[ii] = scaled
self.platforms[0].view.location.left = dsr.left + indent
self.platforms[1].view.location.centerx = dsr.centerx
self.platforms[2].view.location.right = dsr.right - indent
@ -929,14 +929,15 @@ class Tony(Sprite):
Sprite.update(self)
# Blend the effect frame with the sprite frame
if self.get_configuration("display", "alpha-effect-title"):
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)
else:
self.effect.update(flags=BLEND_RGBA_SUB)
if not self.get_configuration("system", "minimize-load-time"):
if self.get_configuration("display", "alpha-effect-title"):
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)
else:
self.effect.update(flags=BLEND_RGBA_SUB)
# Update title screen objects that are drawn over this sprite
if self.get_game().title.active:
@ -1165,9 +1166,9 @@ class Title(Animation):
arrow.set_colorkey((255, 0, 255))
arrow.fill((255, 0, 255))
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:
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.trigon(arrow, points[0], points[1], points[2], points[3], points[4], points[5], (0, 0, 0))
self.score_indicator.add_frame(arrow)
@ -1352,6 +1353,8 @@ class Dialogue(Animation):
self.name_box.add_frame(frame)
self.name_box.location.bottomleft = self.avatar_box.location.bottomright
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):
self.stop_speech()
@ -1410,13 +1413,13 @@ class Dialogue(Animation):
font = pygame.font.Font(self.get_resource(self.FONT_PATH), self.FONT_SIZE)
message = Sprite(self)
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):
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))
message.add_frame(frame)
message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8
message.update()
message.add_frame(frame)
message.location.topleft = self.text_box.location.left + 9, self.text_box.location.top + 8
message.update()
class SkipPrompt(GameChild):
@ -1647,44 +1650,49 @@ class Platform(GameChild):
def __init__(self, parent, center):
"""
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 center tuple that gives the (x, y) screen coordinates of this platform
"""
GameChild.__init__(self, parent)
# Create objects for tracking the individual pad lights
self.lights = [
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", "se_color"), NS.LSE),
Light(self, self.get_configuration("pads", "sw_color"), NS.LSW)
]
# Create a sprite which will display the pad
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([1], name=str(NS.N))
self.view.add_frameset([2], name=str(NS.E))
self.view.add_frameset([3], name=str(NS.NW))
self.view.add_frameset([4], name=str(NS.NE))
self.view.add_frameset([5], name=str(NS.W))
self.view.add_frameset([6], name=str(NS.S))
self.view.location.center = center
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:
# For each of the six combinations of lights, create a glowing frameset
light_masks = load_frames(self.get_resource("pad_mask"), True)
for orientation_index, orientation in enumerate((NS.N, NS.E, NS.NW, NS.NE, NS.W, NS.S)):
pad_base_frame = load_frames(os.path.join(self.get_resource("pad"), f"pad_{orientation_index + 1}.png"), True)[0]
self.view.add_frame(pad_base_frame)
frameset = [len(self.view.frames) - 1]
intensity_resolution = 12
for intensity in range(1, intensity_resolution):
copy = mask[0].copy()
pixels = pygame.PixelArray(copy)
color = pygame.Color(0, 0, 0)
h, s, l, a = color.hsla
l = int(intensity / intensity_resolution * 100)
color.hsla = h, s, l, a
pixels.replace(pygame.Color(0, 0, 0), color)
del pixels
mask.append(copy)
next_pad_frame = pad_base_frame.copy()
for light_orientation in self.get_buttons_from_edges([orientation]):
copy = light_masks[light_orientation].copy()
pixels = pygame.PixelArray(copy)
color = pygame.Color(0, 0, 0)
h, s, l, a = color.hsla
l = int(intensity / intensity_resolution * 100)
color.hsla = h, s, l, a
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):
"""
@ -1878,9 +1886,9 @@ class Platform(GameChild):
"""
for ii, light in enumerate(self.lights):
light.glow_index = 0
light.halt(light.glow)
light.unglow()
if ii in selected:
light.play(light.glow)
light.glow()
def update(self):
"""
@ -1897,11 +1905,6 @@ class Platform(GameChild):
else:
self.view.set_frameset(str(glowing))
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
if self.get_edge_pressed() is not None:
if self.get_edge_pressed() != self.previously_pressed_edge:
@ -1914,11 +1917,10 @@ class Platform(GameChild):
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
platform. Each light stores its color and position on the platform. This class contains methods for glowing the light and
getting its properties.
platform. Each light stores its color, position on the platform, and state of glowing.
"""
TITLE_OFFSET = 0
@ -1931,7 +1933,7 @@ class Light(Animation):
@param color pygame color object
@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.a = 225
self.position = position
@ -1956,39 +1958,46 @@ class Light(Animation):
self.points = mid, midright, backright, backmid
elif self.position == NS.LSW:
self.points = midleft, mid, backmid, backleft
self.register(self.glow)
def reset(self):
"""
Unhide, halt glow animation
"""
self.hidden = False
self.halt(self.glow)
self.reset_timer()
self.glow_index = 0
self.unglow()
def glow(self):
"""
Moves the glow animation forward a frame by incrementing an index
Set the glow state to True
"""
self.glow_index += 1
if self.glow_index >= len(self.parent.glow_masks[0]):
self.glow_index = 0
self.is_glowing = True
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):
"""
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:
boss = self.get_game().boss
chemtrails = self.get_game().chemtrails
# 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]):
self.play(self.glow)
if boss.queue and self.in_orientation(boss.queue[chemtrails.queue_index]):
self.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])):
self.reset()
elif not boss.queue or not self.in_orientation(boss.queue[chemtrails.queue_index]):
self.unglow()
def get_points(self):
if self.get_game().title.active:
@ -1999,21 +2008,6 @@ class Light(Animation):
else:
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):
"""
Returns True if this light is contained in the given edge
@ -2030,14 +2024,6 @@ class Light(Animation):
elif self.position == NS.LSW:
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):
"""

View File

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