option to rotate display 90 degrees

This commit is contained in:
ohsqueezy 2022-12-16 10:55:00 -05:00
parent 2e84e3d916
commit ced7540262
4 changed files with 211 additions and 78 deletions

5
config
View File

@ -1,7 +1,7 @@
[setup] [setup]
title = Electric Sieve title = Electric Sieve
url = http://A-O.in/ url = https://shampoo.ooo
contact-email = frank.s.demarco@gmail.com contact-email = mailbox@shampoo.ooo
contact-name = Frank DeMarco contact-name = Frank DeMarco
summary = UFOs fracking your skull in 1920s America summary = UFOs fracking your skull in 1920s America
version = 0.1.1 version = 0.1.1
@ -18,6 +18,7 @@ title-font-path = font/Oxygen.ttf
scoreboard-font-path = font/terminus/Terminus.ttf scoreboard-font-path = font/terminus/Terminus.ttf
initials-font = font/terminus/Terminus-Bold.ttf initials-font = font/terminus/Terminus-Bold.ttf
show-framerate = yes show-framerate = yes
rotate = no
[mouse] [mouse]
visible = no visible = no

View File

@ -5,6 +5,7 @@ from random import randint, randrange, choice
from time import time from time import time
from operator import itemgetter from operator import itemgetter
import pygame
from pygame import Surface, PixelArray, Rect from pygame import Surface, PixelArray, Rect
from pygame.draw import aalines, polygon from pygame.draw import aalines, polygon
from pygame.font import Font from pygame.font import Font
@ -14,6 +15,7 @@ from pygame.locals import *
from lib.pgfw.pgfw.Game import Game from lib.pgfw.pgfw.Game import Game
from lib.pgfw.pgfw.GameChild import GameChild from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite from lib.pgfw.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.Vector import Vector
from lib.pgfw.pgfw.extension import render_box from lib.pgfw.pgfw.extension import render_box
# Import GPIO library if available # Import GPIO library if available
@ -36,11 +38,27 @@ class ElectricSieve(Game):
""" """
# Initialize super # Initialize super
Game.__init__(self) Game.__init__(self)
# Add type declarations for custom config entries
self.get_configuration().type_declarations.add("bool", "display", "rotate")
# Rotate the display if requested in the configuration
self.is_rotated = False
if self.get_configuration("display", "rotate"):
self.display.rotate()
self.is_rotated = True
# Initialize GPIO input and callbacks if GPIO library is loaded # Initialize GPIO input and callbacks if GPIO library is loaded
if "RPi.GPIO" in sys.modules: if "RPi.GPIO" in sys.modules:
self.initialize_gpio() self.initialize_gpio()
# Create game objects
self.title = Title(self)
self.sieve = Sieve(self)
self.triangles = Triangles(self)
self.acid = Acid(self)
self.static = Static(self)
# Create a purple background # Create a purple background
self.background = Surface(self.display.screen.get_size()) self.background = Surface(self.display.screen.get_size())
self.background.fill((255, 80, 190)) self.background.fill((255, 80, 190))
@ -81,13 +99,55 @@ class ElectricSieve(Game):
self.input.post_command("right", cancel=cancel) self.input.post_command("right", cancel=cancel)
self.input.post_any_command(id=pin, cancel=cancel) self.input.post_any_command(id=pin, cancel=cancel)
def set_children(self): def rotated(self):
Game.set_children(self) """
self.title = Title(self) @returns True if display has been rotated, False otherwise
self.sieve = Sieve(self) """
self.triangles = Triangles(self) return self.is_rotated
self.acid = Acid(self)
self.static = Static(self) def orient(self, geometry, reference=None):
"""
Orient the passed pgfw.Vector, pygame.Rect, or pygame.Surface so it is rotated if necessary.
@param geometry A pgfw.Vector or pygame.Rect to rotate
@return Either a new pgfw.Vector or pygame.Rect depending on which was passed
"""
if not self.rotated():
return geometry
else:
if isinstance(geometry, Vector):
return self.rotated_point(geometry, reference)
elif isinstance(geometry, pygame.Rect):
return self.rotated_rect(geometry, reference)
elif isinstance(geometry, pygame.Surface):
return pygame.transform.rotate(geometry, 90)
def rotated_point(self, point, reference=None):
"""
Return a new pgfw.Vector with the X and Y values of a pgfw.Vector rotated 90 degrees.
@param point pgfw.Vector to rotate in place
@return rotated pgfw.Vector
"""
if reference is None:
reference = self.get_display_surface()
return Vector(reference.get_height() - point.x, point.y)
def rotated_rect(self, rect, reference=None):
"""
Return a new pygame.Rect rotated 90 degrees.
@param rect pygame.Rect to rotate in place
@return rotated pygame.Rect
"""
if reference is None:
reference = self.get_display_surface()
rotated = pygame.Rect(0, 0, 0, 0)
rotated.x = rect.y
rotated.y = reference.get_height() - rect.x + rect.w
rotated.w = rect.h
rotated.h = rect.w
return rotated
def update(self): def update(self):
self.title.update() self.title.update()
@ -108,8 +168,8 @@ class Title(GameChild):
self.background = surface = Surface(self.display_surface.get_size()) self.background = surface = Surface(self.display_surface.get_size())
tile = Surface((2, 2)) tile = Surface((2, 2))
tile.fill(bg_color) tile.fill(bg_color)
tile.set_at((0, 1), (220, 119, 41)) tile.set_at(self.get_game().orient(Vector(0, 1)), (220, 119, 41))
tile.set_at((1, 0), (220, 119, 41)) tile.set_at(self.get_game().orient(Vector(1, 0)), (220, 119, 41))
for y in range(0, surface.get_height(), 2): for y in range(0, surface.get_height(), 2):
for x in range(0, surface.get_width(), 2): for x in range(0, surface.get_width(), 2):
surface.blit(tile, (x, y)) surface.blit(tile, (x, y))
@ -208,7 +268,10 @@ class Strip(Sprite):
for shift in self.hshifts: for shift in self.hshifts:
shift.update() shift.update()
if shift.time: if shift.time:
self.move(shift.get_change()) if not self.get_game().rotated():
self.move(shift.get_change())
else:
self.move(dy=shift.get_change())
Sprite.update(self) Sprite.update(self)
@ -228,11 +291,9 @@ class Shift(GameChild):
def update(self): def update(self):
least, greatest = self.nodeset[0].x, self.nodeset[-1].x least, greatest = self.nodeset[0].x, self.nodeset[-1].x
if self.active and self.time < greatest: if self.active and self.time < greatest:
self.time = min(self.time + self.timer.get_last_frame_duration(), self.time = min(self.time + self.timer.get_last_frame_duration(), greatest)
greatest)
elif not self.active and self.time > least: elif not self.active and self.time > least:
self.time = max(self.time - self.timer.get_last_frame_duration(), self.time = max(self.time - self.timer.get_last_frame_duration(), least)
least)
def get_change(self): def get_change(self):
return self.nodeset.get_y(self.time) * self.direction return self.nodeset.get_y(self.time) * self.direction
@ -275,21 +336,28 @@ class Scoreboard(GameChild):
surface.fill(self.FOREGROUND) surface.fill(self.FOREGROUND)
rect.center = surface.get_rect().center rect.center = surface.get_rect().center
surface.blit(score_plate, rect) surface.blit(score_plate, rect)
sprites[ii][1].add_frame(render_box(font, score_text, False, color, sprites[ii][1].add_frame(self.get_game().orient(
self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)) render_box(font, score_text, False, color, self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)))
sprites[ii][0].add_frame(render_box(font, score[2], False, color, sprites[ii][0].add_frame(self.get_game().orient(
self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)) render_box(font, score[2], False, color, self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)))
if self.most_recent_score and not blink and score[1:] == self.most_recent_score: if self.most_recent_score and not blink and score[1:] == self.most_recent_score:
sprites[ii][1].add_frame(render_box(font, score_text, False, self.NEW, sprites[ii][1].add_frame(self.get_game().orient(
self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)) render_box(font, score_text, False, self.NEW, self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)))
sprites[ii][0].add_frame(render_box(font, score[2], False, self.NEW, sprites[ii][0].add_frame(self.get_game().orient(
self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)) render_box(font, score[2], False, self.NEW, self.BACKGROUND, self.FOREGROUND, self.BORDER, self.PADDING)))
blink = True blink = True
sprites[ii][0].location.left = self.MARGIN if not self.get_game().rotated():
sprites[ii][1].location.right = self.get_display_surface().get_rect().right - self.MARGIN sprites[ii][0].location.left = self.MARGIN
y = self.get_display_surface().get_rect().centery + self.SPACING * (ii - len(sizes) / 2) sprites[ii][1].location.right = self.get_display_surface().get_rect().right - self.MARGIN
for sprite in sprites[ii]: y = self.get_display_surface().get_rect().centery + self.SPACING * (ii - len(sizes) / 2)
sprite.location.centery = y for sprite in sprites[ii]:
sprite.location.centery = y
else:
sprites[ii][0].location.bottom = self.get_display_surface().get_height() - self.MARGIN
sprites[ii][1].location.top = self.MARGIN
x = self.get_display_surface().get_rect().centerx + self.SPACING * (ii - len(sizes) / 2)
for sprite in sprites[ii]:
sprite.location.centerx = x
def get_scores(self): def get_scores(self):
scores = [] scores = []
@ -320,7 +388,12 @@ class Sieve(Strip):
Strip.__init__(self, parent) Strip.__init__(self, parent)
self.delegate = self.get_game().delegate self.delegate = self.get_game().delegate
self.electric = Electric(self) self.electric = Electric(self)
self.add_location(offset=(self.location.w, 0)) if not self.get_game().rotated():
self.location.left = 0
self.add_location(offset=(self.location.w, 0))
else:
self.location.bottom = self.get_display_surface().get_height()
self.add_location(offset=(0, -self.location.h))
def add_frames(self): def add_frames(self):
bar_locations = [] bar_locations = []
@ -346,26 +419,46 @@ class Sieve(Strip):
for ii, frame in enumerate(frames): for ii, frame in enumerate(frames):
frame.fill(colors[ii], (x, 0, bar_w, sh)) frame.fill(colors[ii], (x, 0, bar_w, sh))
frame.fill(colors[ii - 1], (x + 1, 1, 1, sh - 2)) frame.fill(colors[ii - 1], (x + 1, 1, 1, sh - 2))
if self.get_game().rotated():
for ii, rect in enumerate(bar_rects):
bar_rects[ii] = self.get_game().orient(rect)
bar_rects[ii].move_ip(0, -6)
for frame in frames: for frame in frames:
self.add_frame(frame) self.add_frame(self.get_game().orient(frame))
def reset(self): def reset(self):
Strip.reset(self) Strip.reset(self)
self.location.centerx = self.display_surface.get_rect().centerx if not self.get_game().rotated():
self.locations[1].centerx = self.location.centerx + self.location.w self.location.centerx = self.display_surface.get_rect().centerx
self.locations[1].centerx = self.location.centerx + self.location.w
else:
self.location.centery = self.display_surface.get_rect().centery
self.locations[1].centery = self.location.centery + self.location.h
def update(self): def update(self):
if self.active: if self.active:
if self.location.right < 0: if not self.get_game().rotated():
self.move(self.location.w) if self.location.right < 0:
if self.locations[1].left > self.display_surface.get_width(): self.move(self.location.w)
self.move(-self.location.w) if self.locations[1].left > self.display_surface.get_width():
for location in self.locations: self.move(-self.location.w)
location.bottom = self.parent.acid.get_top() for location in self.locations:
self.electric.location.centery = self.location.centery + 13 location.bottom = self.parent.acid.get_top()
self.electric.location.centery = self.location.centery + 13
else:
if self.location.top > self.display_surface.get_height():
self.move(dy=-self.location.h)
if self.locations[1].bottom < 0:
self.move(dy=self.location.h)
for location in self.locations:
location.right = self.parent.acid.get_top()
self.electric.location.centerx = self.location.centerx + 13
self.electric.update() self.electric.update()
for rect in self.bar_rects: for rect in self.bar_rects:
rect.centery = self.location.centery if not self.get_game().rotated():
rect.centery = self.location.centery
else:
rect.centerx = self.location.centerx
Strip.update(self) Strip.update(self)
@ -377,8 +470,10 @@ class Electric(Sprite):
self.add_frames() self.add_frames()
def add_frames(self): def add_frames(self):
surface = Surface((self.display_surface.get_width(), if not self.get_game().rotated():
self.parent.location.h - 10)) surface = Surface((self.display_surface.get_width(), self.parent.location.h - 10))
else:
surface = Surface((self.display_surface.get_height(), self.parent.location.w - 10))
frames = surface, surface.copy() frames = surface, surface.copy()
colors = (255, 255, 0), (100, 89, 213) colors = (255, 255, 0), (100, 89, 213)
pixel_arrays = PixelArray(frames[0]), PixelArray(frames[1]) pixel_arrays = PixelArray(frames[0]), PixelArray(frames[1])
@ -389,7 +484,7 @@ class Electric(Sprite):
for pixels in pixel_arrays: for pixels in pixel_arrays:
del pixels del pixels
for frame in frames: for frame in frames:
self.add_frame(frame) self.add_frame(self.get_game().orient(frame))
class Triangles(GameChild, list): class Triangles(GameChild, list):
@ -419,12 +514,21 @@ class Triangles(GameChild, list):
def populate(self): def populate(self):
if not self: if not self:
self.append(Triangle(self)) self.append(Triangle(self))
self[-1].location.bottom = 0 if not self.get_game().rotated():
self.set_next_gap() self[-1].location.bottom = 0
while self[-1].location.top > -self.display_surface.get_height(): else:
self.append(Triangle(self)) self[-1].location.right = 0
self[-1].location.bottom = self[-2].location.top - self.next_gap
self.set_next_gap() self.set_next_gap()
if not self.get_game().rotated():
while self[-1].location.top > -self.display_surface.get_height():
self.append(Triangle(self))
self[-1].location.bottom = self[-2].location.top - self.next_gap
self.set_next_gap()
else:
while self[-1].location.left > -self.display_surface.get_width():
self.append(Triangle(self))
self[-1].location.right = self[-2].location.left - self.next_gap
self.set_next_gap()
def set_next_gap(self): def set_next_gap(self):
self.next_gap = randint(500, 800) self.next_gap = randint(500, 800)
@ -451,17 +555,17 @@ class Triangles(GameChild, list):
if self[0].location.colliderect(sieve.electric.location): if self[0].location.colliderect(sieve.electric.location):
self.parent.acid.increase() self.parent.acid.increase()
self.streak += 1 self.streak += 1
self.score += self.streak ** .8 + \ self.score += self.streak ** .8 + self.parent.acid.get_volume() * 5 + self[0].count
self.parent.acid.get_volume() * 5 + \
self[0].count
self.remove(self[0]) self.remove(self[0])
self.hit.play() self.hit.play()
else: else:
for br in sieve.bar_rects: for br in sieve.bar_rects:
for tr in self[0].collision_rects: for tr in self[0].collision_rects:
if tr.move((self[0].location.left, tr_offset = (self[0].location.left, 0) if not self.get_game().rotated() else \
0)).colliderect(br.move((sieve.location.left, (0, self[0].location.bottom - self.get_display_surface().get_height())
0))): br_offset = (sieve.location.left, 0) if not self.get_game().rotated() else \
(0, sieve.location.bottom - self.get_display_surface().get_height())
if tr.move(tr_offset).colliderect(br.move(br_offset)):
self.remove(self[0]) self.remove(self[0])
self.parent.static.increase() self.parent.static.increase()
self.streak = 0 self.streak = 0
@ -490,21 +594,33 @@ class Triangle(Sprite):
self.collision_rects = collision_rects = [] self.collision_rects = collision_rects = []
for width in widths: for width in widths:
x += sieve.bar_w x += sieve.bar_w
points = (x + margin / 2, height - 2), \ points = (x + margin // 2, height - 2), \
(x + width - margin / 2 - 1, height - 2), \ (x + width - margin // 2 - 1, height - 2), \
(x + width / 2.0, 1) (x + width / 2.0, 1)
polygon(surface, (60, 255, 220), points) polygon(surface, (60, 255, 220), points)
collision_rects.append(Rect(points[0], (width - margin - 1, 1))) if not self.get_game().rotated():
collision_rects.append(Rect(points[0], (width - margin - 1, 1)))
else:
collision_rects.append(Rect(height - 2 - 1, self.get_display_surface().get_height() - x - width + margin // 2 + 1, 1, width - margin - 1))
x += width - sieve.bar_w x += width - sieve.bar_w
self.add_frame(surface) self.add_frame(self.get_game().orient(surface))
self.location.centerx = self.get_display_surface().get_rect().centerx if not self.get_game().rotated():
self.location.centerx = self.get_display_surface().get_rect().centerx
else:
self.location.centery = self.get_display_surface().get_rect().centery
self.count = len(widths) self.count = len(widths)
def update(self): def update(self):
self.move(dy=9.5 * self.get_game().acid.get_volume() + 3.8 + \ step = 9.5 * self.get_game().acid.get_volume() + 3.8 + self.parent.get_boost()
self.parent.get_boost()) if not self.get_game().rotated():
self.move(dy=step)
else:
self.move(dx=step)
for rect in self.collision_rects: for rect in self.collision_rects:
rect.bottom = self.location.bottom if not self.get_game().rotated():
rect.bottom = self.location.bottom
else:
rect.right = self.location.right
Sprite.update(self) Sprite.update(self)
@ -521,11 +637,13 @@ class Acid(GameChild):
self.substance = 0 self.substance = 0
def get_top(self): def get_top(self):
return self.display_surface.get_height() - self.get_level() if not self.get_game().rotated():
return self.display_surface.get_height() - self.get_level()
else:
return self.display_surface.get_width() - self.get_level()
def get_level(self): def get_level(self):
return self.get_volume() * (self.level_r[1] - self.level_r[0]) + \ return self.get_volume() * (self.level_r[1] - self.level_r[0]) + self.level_r[0]
self.level_r[0]
def get_volume(self): def get_volume(self):
return self.nodeset.get_y(self.substance) return self.nodeset.get_y(self.substance)
@ -646,7 +764,6 @@ class Initials(GameChild):
PADDING = 10 PADDING = 10
ARROW_MARGIN = 40 ARROW_MARGIN = 40
ARROW_HEIGHT = 10 ARROW_HEIGHT = 10
def __init__(self, parent): def __init__(self, parent):
GameChild.__init__(self, parent) GameChild.__init__(self, parent)
@ -703,22 +820,27 @@ class Initials(GameChild):
if self.active: if self.active:
ds = self.get_display_surface() ds = self.get_display_surface()
for ii, letter in enumerate(self.text): for ii, letter in enumerate(self.text):
box = render_box(self.font, letter, False, self.FOREGROUND, self.BACKGROUND, box = self.get_game().orient(render_box(
self.FOREGROUND, padding=self.PADDING) self.font, letter, False, self.FOREGROUND, self.BACKGROUND, self.FOREGROUND, padding=self.PADDING))
rect = box.get_rect() rect = box.get_rect()
rect.centery = ds.get_rect().centery if not self.get_game().rotated():
rect.centerx = ii * ds.get_width() / 3 + ds.get_width() / 6 rect.centery = ds.get_rect().centery
rect.centerx = ii * ds.get_width() / 3 + ds.get_width() / 6
else:
rect.centerx = ds.get_rect().centerx
rect.centery = (len(self.text) - 1 - ii) * ds.get_height() / 3 + ds.get_height() / 6
ds.blit(box, rect) ds.blit(box, rect)
if ii == self.index: if ii == self.index:
margin = self.ARROW_MARGIN if not self.get_game().rotated():
margin = self.ARROW_MARGIN
else:
margin = self.ARROW_MARGIN // 2
polygon(ds, (0, 255, 0), ((rect.left, rect.top - margin), polygon(ds, (0, 255, 0), ((rect.left, rect.top - margin),
(rect.right, rect.top - margin), (rect.right, rect.top - margin),
(rect.centerx, (rect.centerx, rect.top - margin - self.ARROW_HEIGHT)))
rect.top - margin - self.ARROW_HEIGHT)))
polygon(ds, (0, 255, 0), ((rect.left, rect.bottom + margin), polygon(ds, (0, 255, 0), ((rect.left, rect.bottom + margin),
(rect.right, rect.bottom + margin), (rect.right, rect.bottom + margin),
(rect.centerx, (rect.centerx, rect.bottom + margin + self.ARROW_HEIGHT)))
rect.bottom + margin + self.ARROW_HEIGHT)))
class Total(Sprite): class Total(Sprite):
@ -763,7 +885,7 @@ class Total(Sprite):
# polygon(surface, choice(colors), ((tr.centerx - 7, 80), # polygon(surface, choice(colors), ((tr.centerx - 7, 80),
# (tr.centerx, tr.h - 1), # (tr.centerx, tr.h - 1),
# (tr.centerx + 7, 80))) # (tr.centerx + 7, 80)))
self.add_frame(surface) self.add_frame(self.get_game().orient(surface))
self.location.center = self.display_surface.get_rect().center self.location.center = self.display_surface.get_rect().center
self.active = True self.active = True

@ -1 +1 @@
Subproject commit 24b5d7c6e7c7f17ec09ddb3de2127c092aa6f874 Subproject commit 7a1652717931d49c112e8fe75919129b4906d9f4

View File

@ -134,3 +134,13 @@
1670819531.720299 203 FLA 1670819531.720299 203 FLA
1670819619.775536 96 --- 1670819619.775536 96 ---
1670989457.377776 0 --- 1670989457.377776 0 ---
1671076263.7870994 4 ---
1671076281.177432 0 ---
1671076361.7916923 20 ---
1671076398.698485 4 ---
1671076453.8790646 43 ---
1671076466.5137062 0 ---
1671076561.3319085 52 ---
1671086208.2518148 135 ---
1671161829.4724848 14 ---
1671168164.8205705 0 ---