new pad graphics and glow

This commit is contained in:
frank 2022-02-24 01:16:45 -05:00
parent 0526507649
commit 607f6a8059
7 changed files with 184 additions and 25 deletions

208
NS.py
View File

@ -37,7 +37,7 @@ from lib.pgfw.pgfw.Animation import Animation
from lib.pgfw.pgfw.extension import (
get_step, get_step_relative, get_delta, reflect_angle,
render_box, get_hsla_color, get_hue_shifted_surface,
get_color_swapped_surface
get_color_swapped_surface, load_frames
)
from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon
@ -56,10 +56,10 @@ class NS(Game, Animation):
# four sides of the square and the two diagonals.
N, NE, E, NW, S, W = range(6)
FRONT_WIDTH = 230
BACK_WIDTH = 500
LENGTH = 150
FRONT = 300
FRONT_WIDTH = 156
BACK_WIDTH = 271
LENGTH = 94
FRONT = 330
STEP = .4
IDLE_TIMEOUT = 60000 * 5
CHANNEL_COUNT = 8
@ -101,6 +101,10 @@ class NS(Game, Animation):
"system":
{
"bool": "minimize-load-time"
},
"pads":
{
"int-list": "center"
}
})
# If a serial port was passed on the command line, override the config file setting
@ -497,6 +501,7 @@ class Tony(Sprite):
self.effect.update(flags=BLEND_RGBA_SUB)
self.get_display_surface().blit(intermediate_surface, self.location.topleft)
if self.get_game().title.active:
self.get_game().title.video.update()
self.get_game().platform.update()
self.get_game().chemtrails.update()
frameset = self.get_current_frameset()
@ -718,7 +723,7 @@ class Title(Animation):
self.get_game().tony.set_frameset("static")
self.halt()
self.play(self.show_video, delay=self.get_configuration("time", "attract-reset-countdown"), play_once=True)
self.video.update()
# self.video.update()
self.draw_scores()
@ -1000,21 +1005,56 @@ class Wipe(Animation):
class Platform(GameChild):
"""
This class contains methods for manipulating and getting information about the platform the player is standing on,
both the real one and on-screen representation. It initializes four Light objects, one for each pad on the platform.
It can set lights to glowing, return the states of individual lights or pairs of lights, reset lights, and draw the
on-screen representation.
"""
def __init__(self, parent):
"""
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.
"""
GameChild.__init__(self, parent)
dsr = self.get_display_surface().get_rect()
self.border = Sprite(self)
self.border.load_from_path(self.get_resource("DancePadClear.png"), True)
self.border.location.midbottom = dsr.centerx, dsr.bottom
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)
]
self.view = Sprite(self)
self.view.load_from_path("pad", 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 = self.get_configuration("pads", "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:
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)
def reset(self):
"""
Deactivate this object and reset each light
"""
self.deactivate()
self.reset_lights()
@ -1023,19 +1063,37 @@ class Platform(GameChild):
light.reset()
def deactivate(self):
"""
This will stop the platform from being drawn and lights from updating
"""
self.active = False
def activate(self):
"""
This will cause the platform to get drawn and lights to update when this object's update method is called
"""
self.active = True
def unpress(self):
"""
Set the state of each light to unpressed
"""
for light in self.lights:
light.pressed = False
def get_pressed(self):
"""
Returns a list of light positions pressed (NS.LNW, NS.LNE, NS.LSE, NS.LSW)
"""
return [light.position for light in self.lights if light.pressed]
def get_edge_pressed(self):
"""
Gets the edge (2 light combination) currently pressed. This only returns one edge since there should only
be one able to be pressed at a time. If no edge is pressed, returns None.
@return NS.N | NS.NE | NS.E | NS.NW | NS.S | NS.W | None
"""
pressed = self.get_pressed()
if NS.LNW in pressed and NS.LNE in pressed:
return NS.N
@ -1050,7 +1108,32 @@ class Platform(GameChild):
elif NS.LSW in pressed and NS.LNW in pressed:
return NS.W
def get_glowing_edge(self):
"""
Return the edge currently glowing or None
@return NS.N | NS.NE | NS.E | NS.NW | NS.S | NS.W | None
"""
if self.lights[NS.LNW].glowing() and self.lights[NS.LNE].glowing():
return NS.N
elif self.lights[NS.LNE].glowing() and self.lights[NS.LSW].glowing():
return NS.NE
elif self.lights[NS.LNE].glowing() and self.lights[NS.LSE].glowing():
return NS.E
elif self.lights[NS.LNW].glowing() and self.lights[NS.LSE].glowing():
return NS.NW
elif self.lights[NS.LSE].glowing() and self.lights[NS.LSW].glowing():
return NS.S
elif self.lights[NS.LSW].glowing() and self.lights[NS.LNW].glowing():
return NS.W
def get_buttons_from_edges(self, edges):
"""
Get a list of light positions contained by a list of edges. For example, [NS.N, NS.E] would give [NS.LNW, NS.LNE, NS.LSE].
@param edges list of edges [NS.N | NS.NE | NS.E | NS.NW | NS.S | NS.W]
@return list of light positions [NS.LNW | NS.LNE | NS.LSE | NS.LSW]
"""
buttons = set()
for edge in edges:
if edge == NS.N:
@ -1068,6 +1151,13 @@ class Platform(GameChild):
return list(buttons)
def get_steps_from_edge(self, edge):
"""
Get the edges that are one step away from a given edge. For example, NS.N would give (NS.NE, NS.NW) because those
are the edges that only require a pivot move of one step from NS.N.
@param edge one of NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W
@return pair of edges that are one step away
"""
if edge == NS.N:
return NS.NE, NS.NW
elif edge == NS.NE:
@ -1082,6 +1172,13 @@ class Platform(GameChild):
return NS.NE, NS.NW
def get_right_angles_from_edge(self, edge):
"""
Get the pair of angles that are at a right angle to a given edge. For example, NS.N would return (NS.E, NW.W). For
diagonals, this returns None.
@param edge one of NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W
@return pair of edges that are at a right angle to given edge or None
"""
if edge == NS.N:
return NS.E, NS.W
elif edge == NS.NE:
@ -1096,6 +1193,13 @@ class Platform(GameChild):
return NS.N, NS.S
def get_opposite_of_edge(self, edge):
"""
Get the edge opposite to a given edge. For example, NS.N would return NS.S. For diagonals, the opposite is the
reverse diagonal.
@param edge one of NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W
@return edge opposite to given edge, one of NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W
"""
if edge == NS.N:
return NS.S
elif edge == NS.NE:
@ -1110,6 +1214,12 @@ class Platform(GameChild):
return NS.E
def get_color_pair_from_edge(self, edge):
"""
Return the pair of pygame color objects that make up a given edge
@param edge one of NS.N, NS.NE, NS.E, NS.NW, NS.S, NS.W
@return tuple of pygame color objects
"""
if edge == NS.N:
return self.lights[NS.LNW].color, self.lights[NS.LNE].color
elif edge == NS.NE:
@ -1124,6 +1234,11 @@ class Platform(GameChild):
return self.lights[NS.LNW].color, self.lights[NS.LSW].color
def set_glowing(self, selected):
"""
Set the given light IDs to glowing and other indices to not glowing.
@param selected list of light IDs (NS.LNW, NS.LNE, NS.LSE, NS.LSW)
"""
for ii, light in enumerate(self.lights):
light.glow_index = 0
light.halt(light.glow)
@ -1131,20 +1246,44 @@ class Platform(GameChild):
light.play(light.glow)
def update(self):
"""
Update each light and draw the platform and glow effect
"""
if self.active:
for light in self.lights:
light.update()
# self.border.update()
for light in self.lights:
light.draw_glow()
# draw the pad based on which pads are glowing
glowing = self.get_glowing_edge()
if glowing is None:
self.view.set_frameset("neutral")
self.view.update()
else:
self.view.set_frameset(str(glowing))
self.view.update()
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)
# for light in self.lights:
# light.draw_glow()
class Light(Animation):
"""
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.
"""
MAX_GLOW_INDEX = 25
TITLE_OFFSET = 0
def __init__(self, parent, color, position):
"""
Initialize a new Light object, providing color and position on the platform.
@param parent PGFW game object that instantiated this 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
"""
Animation.__init__(self, parent)
self.color = Color(color)
self.color.a = 225
@ -1170,38 +1309,43 @@ class Light(Animation):
self.points = mid, midright, backright, backmid
elif self.position == NS.LSW:
self.points = midleft, mid, backmid, backleft
self.register(self.blink, interval=300)
self.register(self.glow)
def reset(self):
"""
Unhide, halt glow animation
"""
self.hidden = False
self.halt(self.blink)
self.halt(self.glow)
self.reset_timer()
self.glow_index = 0
def blink(self):
self.hidden = not self.hidden
def glow(self):
"""
Moves the glow animation forward a frame by incrementing an index
"""
self.glow_index += 1
if self.glow_index > self.MAX_GLOW_INDEX:
if self.glow_index >= len(self.parent.glow_masks[0]):
self.glow_index = 0
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:
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 boss.brandish_complete and not self.is_playing(self.glow) \
and self.in_orientation(boss.queue[chemtrails.queue_index]):
self.play(self.glow)
elif self.is_playing(self.glow) and (not boss.queue or
not self.in_orientation(boss.queue[chemtrails.queue_index])):
# 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()
if not self.hidden:
ds = self.get_display_surface()
aa_filled_polygon(ds, self.get_points(), self.color)
# if not self.hidden:
# ds = self.get_display_surface()
# aa_filled_polygon(ds, self.get_points(), self.color)
def get_points(self):
if self.get_game().title.active:
@ -1234,6 +1378,12 @@ class Light(Animation):
)
def in_orientation(self, orientation):
"""
Returns True if this light is contained in the given edge
@param orientation edge to check, one of NS.N, NS.NW, NS.W, NS.NE, NS.E, NS.S
@return True | False
"""
if self.position == NS.LNW:
return orientation in (NS.N, NS.NW, NS.W)
elif self.position == NS.LNE:
@ -1243,6 +1393,14 @@ 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):

1
config
View File

@ -70,3 +70,4 @@ nw_color = #00FF88
ne_color = #FF88FF
se_color = #2222FF
sw_color = #FF2222
center = 319, 376

BIN
resource/pad/pad_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B